我正在使用 MVP 模式在 WinForms 上创建一个应用程序。我为每个表单都有一个单独的项目,视图的界面位于单独的项目中。演讲者也有自己独立的项目。我有两个问题:
如何使用 MVP 正确构建 Winforms 应用程序
如果需要,如何通过演示者向表单添加控件(我有一个主表单,上面有一个注册按钮,单击此按钮将打开注册表单作为我使用 UserControl 的注册表单)。
我在winforms类库中创建了一个presenter,使用Action delegate作为事件参数,但我认为这不是正确的做法,有更好的解决方案
您的 Form 类是 Presenter:它位于视图(= 与操作员交互)和模型之间。
我假设您知道如何使用 Visual Studio Designer 来创建和设计表单。
您的 Form 类有(引用)您的模型的实例。
IMyModel Model {get => ...}
每当操作员按下按钮、选择项目等时,就会生成一个事件。使用 Visual Studio 设计器为此生成事件处理程序。该事件处理程序是在您的 Form 类(Presenter)中创建的。
例如,操作员在文本框中键入产品 ID,然后按“获取产品信息”按钮。在您的表格课程中:
void OnButtonGetProductInformation_Clicked(object sender, ...)
{
}
void DisplayRequestedProduct()
{
string textProductId = this.textBoxProductId.Text;
int productId = Int32.Parse(textProductId)
this.DisplayProduct(productId);
}
void DisplayProduct(int productId)
{
IProduct product = this.Model.GetProduct(productId)
// fetches the product with productId from the Database
this.DisplayProduct(product);
}
Product DisplayedProduct {get; set;}
void DisplayProduct(Product product)
{
// show some product data in labels
this.labelProductId.Text = product.Id;
this.labelProductName.Text = product.Name;
this.labelProductDescription.Text = product.Description;
this.labelProductPrice.Text = product.Price.ToString(...);
this.labelProductStock.Text = product.Stock.ToString(...);
this.DisplayedProduct = product;
}
我将操作分成小方法,因此这些方法更容易进行单元测试,可以重用,并且更改不会影响其他方法。例如,如果您想在编辑框或表格中显示获取的产品,其他过程不会改变。
顺便说一下,为了简单起见,我没有检查输入的productId。当然你应该检查输入是否是正确的整数,以及输入是否是现有产品的productId。
某些模型的数据会发生变化。更改应在视图中自动更新。例如,如果产品已售出,则应更新库存,如果产品已售完,则显示的产品应显示为红色。
只要其中一个产品发生变化,IMyModel 就应该引发一个事件。您应该在您的表单中订阅此活动:
void SubScribeEventProductChanges()
{
this.Model.ProductChanged += this.OnProductChanged;
}
void OnProductChanged(object sender, ProductChangedEventData e)
{
// is my displayed Product changed?
if (e.ChangedProduct.Id == this.DisplayedProduct.Id
{
// The name, price, etc of the Product can be changed
this.DisplayProduct(e.ChangedProduct); // slightly changed version
}
// else: not my product, nothing to do
}
void DisplayProduct(Product product)
{
Color productTextColor = this.GetProductTextColor(product);
this.SetProductDisplayColor(productTextColor);
// as in earlier method:
this.labelProductId.Text = product.Id;
this.labelProductName.Text = product.Name;
...
}
Color GetProductTextColor(Product product)
{
return (product.Stock == 0) ? Color.Red : Color.Black;
}
void SetProductDisplayColor(Color productDisplayColor)
{
this.labelProductId.ForeColor = productDisplayColor;
this.labelProductName.ForeColor = productDisplayColor;
... etc.
}
因为我制作的小程序只有一项小任务,所以我必须对现有程序进行的更改很小。
实现 MVP 或 MVVM:
只要其他人需要知道的值发生变化,模型就应该引发事件。
表单类必须有一个返回模型对象接口的属性。来自操作员的输入由表单类使用事件处理。如果这意味着必须通知模型,则从模型接口形成类方法。
表单类订阅它需要的模型事件。如果引发事件,模型类将检查视图是否必须更新,并采取相应的行动。