我有一个很大的winform,上面有6个选项卡,里面充满了控件。第一个选项卡是主选项卡,另外5个选项卡是主要选项卡的一部分。在数据库术语中,其他5个选项卡引用了主要选项卡。
你可以想象,我的体型越来越大,很难保持。所以我的问题是,如何处理大型UI?你是怎么处理的?
在开始之前考虑一下你的目标。在我看来,你要以坚定的原则为目标。这意味着,除其他事项外,类/方法应该具有单个责任。在您的情况下,表单代码可能正在协调UI内容和业务规则/域方法。
分解为用户控件是一个很好的开始方式。例如,在您的情况下,每个选项卡可能只有一个用户控件。然后,您可以保持实际的表单代码非常简单,加载和填充用户控件。您应该有一个命令处理器实现,这些用户控件可以发布/订阅该实现,以启用视图间对话。
此外,研究UI设计模式。M-V-C是非常流行和完善的,尽管很难在有状态的基于桌面的应用程序中实现。这就产生了M-V-P/被动视图和M-V-VM模式。就我个人而言,我喜欢MVVM,但如果你不小心的话,在WinForms中实现时,你可能会构建很多"框架代码"——保持简单。
此外,从"任务"或"操作"的角度开始思考,从而构建一个基于任务的UI,而不是创建/读取/更新/删除(CRUD)UI。将绑定到第一个选项卡的对象视为聚合根,并具有用户可以单击以执行某些任务的按钮/工具栏/链接标签。当他们这样做时,他们可能会被导航到一个完全不同的页面,该页面只聚合完成该工作所需的特定字段,从而消除了复杂性。
命令处理器
命令处理器模式基本上是用户启动事件的同步发布者/使用者模式。下面包括一个基本的(相当天真的)例子。
从本质上讲,您试图使用此模式实现的是将事件的实际处理从表单本身中移出。表单可能仍然会处理UI问题,如隐藏/[dis/en]启用控件、动画等,但真正的业务逻辑的关注点完全分离是您的目标。如果您有一个丰富的域模型,"命令处理程序"将协调对域模型上方法的调用。命令处理器本身为您提供了一个有用的位置,可以在事务中包装处理程序方法,或者提供AOP风格的东西,如审计和日志记录。
public class UserForm : Form
{
private ICommandProcessor _commandProcessor;
public UserForm()
{
// Poor-man's IoC, try to avoid this by using an IoC container
_commandProcessor = new CommandProcessor();
}
private void saveUserButton_Click(object sender, EventArgs e)
{
_commandProcessor.Process(new SaveUserCommand(GetUserFromFormFields()));
}
}
public class CommandProcessor : ICommandProcessor
{
public void Process(object command)
{
ICommandHandler[] handlers = FindHandlers(command);
foreach (ICommandHandler handler in handlers)
{
handler.Handle(command);
}
}
}
处理大型UI的关键是关注点和封装的干净分离。根据我的经验,最好尽可能保持UI没有数据和功能:模型视图控制器是实现这一点的著名模式(但很难应用)。
由于UI往往会因UI代码而变得混乱,因此最好将所有其他代码从UI中分离出来,并将所有与UI无关的事情直接委托给其他类(例如,将用户输入的处理委托给控制器类)。你可以通过为每个选项卡创建一个控制器类来应用这一点,但这取决于每个选项卡的复杂程度。也许最好将一个选项卡本身分解为几个控制器类,并将它们组合在一个选项卡的控制器类中,以便于处理。
我发现MVC模式的一个变体很有用:被动视图。在这种模式中,视图只包含UI组件的层次结构和状态。其他一切都委托给控制器类并由控制器类控制,控制器类决定对用户输入执行什么操作。
当然,它也有助于将UI本身分解为组织良好、封装良好的组件本身。
我建议您阅读Microsoft实践和模式中的CAB(复合UI应用程序块),它具有以下模式:命令模式、策略模式、MVP模式。。。等
微软实践和模式
复合UI应用程序块