我正在使用监督控制器模式(模型视图演示器)构建一个应用程序,但我遇到了困难。在我的页面中,我有一个转发器控件,它将显示我传递给它的集合的每个项目。中继器项目包含 2 个下拉列表,允许用户选择特定值。当我单击下一个按钮时,我希望控制器检索这些值。
我怎么能以干净的方式做到这一点?
我正在使用监督控制器模式(模型视图演示器)构建一个应用程序,但我遇到了困难。在我的页面中,我有一个转发器控件,它将显示我传递给它的集合的每个项目。中继器项目包含 2 个下拉列表,允许用户选择特定值。当我单击下一个按钮时,我希望控制器检索这些值。
我怎么能以干净的方式做到这一点?
您还可以为下拉菜单制作一个“小部件”界面。我将为您提供一个 TextBox 小部件的一些工作代码的简单示例,以便您了解。
public interface ITextWidget
{
event EventHandler TextChanged;
string Text { get; set; }
}
public abstract class TextWidget<T> : ITextWidget
{
protected T _wrappedWidget { get; set; }
public event EventHandler TextChanged;
protected void InvokeTextChanged(object sender, EventArgs e)
{
var textChanged = TextChanged;
if (textChanged != null) textChanged(this, e);
}
public abstract string Text { get; set; }
}
请注意,到目前为止,一切都与技术无关。现在这是一个 Win Forms TextBox 的实现:
public class TextBoxWidget : TextWidget<TextBox>
{
public TextBoxWidget(TextBox textBox)
{
textBox.TextChanged += InvokeTextChanged;
_wrappedWidget = textBox;
}
public override string Text
{
get { return _wrappedWidget.Text; }
set { _wrappedWidget.Text = value; }
}
}
这在 Form 本身中被实例化,返回到 MVP 也是 IViewWhatever:
public partial class ProjectPickerForm : Form, IProjectPickerView
{
private IProjectPickerPresenter _presenter;
public void InitializePresenter(IProjectPickerPresenter presenter) {
_presenter = presenter;
_presenter.InitializeWidgets(
...
new TextBoxWidget(txtDescription));
}
...
}
在演示者中:
public class ProjectPickerPresenter : IProjectPickerPresenter
{
...
public void InitializeWidgets(ITextWidget descriptionFilter) {
Check.RequireNotNull<ITextWidget>(descriptionFilter, "descriptionFilter");
DescriptionFilter = descriptionFilter;
DescriptionFilter.Text = string.Empty;
DescriptionFilter.TextChanged += OnDescriptionTextChanged;
}
...
public void OnDescriptionTextChanged(object sender, EventArgs e) {
FilterService.DescriptionFilterValue = DescriptionFilter.Text;
}
它看起来比设置时更糟糕,因为一旦你有了这个想法,大部分工作都是相当机械的。干净的部分是演示者可以获取(和设置)它在小部件上需要的任何信息,而无需知道或关心实际实现的小部件是什么。它还可以根据需要与其他相同类型的小部件(您最终构建它们的库)和其他 UI 技术(一旦您拥有接口/基类,另一种技术中的实现)重用琐碎的)。由于您拥有接口,因此使用模拟对象进行测试也很容易。而且您的 UI 现在几乎对所有与 UI 相关的任务一无所知。缺点是每个小部件都有一堆类,并且需要一点学习曲线才能适应它。
对于您的下拉菜单,您可能只需要 SelectedIndexChanged 类型的事件,您可以用它来替换这个示例 TextChanged 事件。
当控制器视图交互变得过于复杂时,我通常将它们分成子控制器和子视图。
您可以让转发器中的项目成为具有自己的视图和控制器的用户控件。然后,您的主视图可以有一个子视图(用户控件)列表,这些子视图(用户控件)具有由主控制器维护的自己的控制器。
当用户单击下一步时,您的主控制器可以向所有子控制器发出信号,以从他们的视图中刷新他们的项目。