我们说我有一个客户窗口,显示有关客户的信息,如姓名,地址和电话号码。在底部有一个他们订单的DataGrid。当然,Customer有一个Orders属性,所以如果你使用MVVM,你只需要设置:
ItemsSource = "{Binding Customer.Orders}"
但是,现在让我们说数据网格现在是用户控件的一部分,用户控件还包括用于编辑/添加/删除订单的控件。我想在多个地方使用同一组控件,我希望编辑/添加/删除Order对象的所有逻辑都封装在用户控件中。因为我想使用命令而不是事件处理程序,我希望用户控件拥有自己的视图模型。
现在问题是:如何将订单从客户视图模型传递到订单用户控件的视图模型?因为Orders用户控件将绑定到视图模型,所以我不能说:
<local:OrdersUserControl DataContext="{Binding Customer.Orders}" />
因为用户控件拥有自己的视图模型。它会期望在那里看到Customer.Orders,当然它不是。
我想这是一种鸡肉或鸡蛋的情况。
我们非常感谢您的帮助。
亚伦
答案 0 :(得分:7)
现在我的每周“不要那样做”答案......
我不能说...因为用户控件拥有自己的视图模型。
我说的是
由于这种气味,你遇到了这个问题,这应该表明你做错了。
解决方案是抛弃为UserControl构建的VM。如果它包含业务逻辑,则应将其移动到另一个ViewModel中的适当位置。
您应该将UserControl视为一个更复杂的控件。 TextBox是否有自己的ViewModel?您可以将您的 VM的属性绑定到控件的Text
属性,控件会在其UI中显示您的文本。
MVVM并不意味着没有代码隐藏。将用户控件的UI逻辑放在代码隐藏中。如果它太复杂以至于您需要在用户控件中使用业务逻辑,那么这表明它太过笼统。将其分解为两个或更多。
将MVCon中的UserControl想象成这样 - 对于每个模型,您都有一个UserControl,它旨在将该模型中的数据呈现给用户。您可以在任何想要向用户显示该模型的地方使用它。它需要一个按钮吗?在UserControl上公开ICommand属性,并让您的业务逻辑绑定到它。您的业务逻辑是否需要知道内部发生的事情?添加路由事件。
通常情况下,在WPF中,如果你发现自己在问某些为什么会有什么伤害,那是因为你不应该这样做。
答案 1 :(得分:0)
有许多方法可以给猫皮肤。我这样做的方法是让我的CustomerViewModel具有OrdersViewModel类型的属性。然后在构造函数中(或者在您设置客户的任何地方)让它设置&#34; OrdersContext&#34;使用新的OrdersViewModel传入customer.orders。
<强> XAML:强>
<local:OrdersUserControl DataContext="{Binding OrdersContext}" />
ViewModel:
public CustomerViewModel(Customer customer)
{
Customer = customer;
OrdersContext = new OrdersViewModel(customer.Orders);
}