我们已经有了WPF应用程序的现有用户界面,其中单独的按钮按下将显示基于可见性(MVVM)绑定的元素,其中ICommand将打开或关闭这些可见性属性。这些效果很好,但是最近我们要求按下按钮来显示/隐藏像以前一样的元素,但是按下另一种类型的按钮以显示其他元素但是在TabControl中。
我想这样做的方式是:
a)创建包含这些元素的单独UserControl
b)这些UserControl在运行时通过ViewModel实例化,具体取决于按下按钮,并通过ObservableCollection绑定到View as ItemsSource:
视图模型:
private ObservableCollection<Object> centerView;
public ObservableCollection<Object> CenterView
{
get { return centerView; }
}
...
UserControlOfReportRelatedElements reportsView = new UserControlOfReportRelatedElements();
CenterView.Clear();
Grid.SetRow(reportsView, 0);
CenterView.Add(reportsView);
XAML:
<ItemsControl ItemsSource="{Binding CenterView}" Grid.Row="2">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
因此,根据UserControl是否包含在TabControl中,我们只需将它放在ObservableCollection中(在运行时)。
这很有效,而且很方便。但这会破坏MVVM吗?我们还能做些什么吗?
答案 0 :(得分:3)
我会说,是的,打破了MVVM模式。关于MVVM的一个想法是保持View(UI)和ViewModel(业务逻辑)彼此分离。
您可以创建一个Base-ViewModel-Class,其中继承了不同视图(您的标签页)的ViewModel。在你的ObserableCollection中,你有Base-ViewModel-Instanced。
要向您的视图模型显示正确的视图,您可以在App.xaml中执行以下操作
<DataTemplate DataType="{x:Type viewModel:CustomViewModel1}">
<view:CustomView1/>
</DataTemplate>
使用此定义,您告诉您的应用程序,只要应显示CustomViewModel1
,就应显示CustomView1
。有了这个,DataContext也被设置了。
一个非常好的例子是this
答案 1 :(得分:3)
是的,在视图模型中引用UI元素会破坏MVVM。视图模型应该是完全隔离的,并且不知道视图。
解决此问题的方法是将实际数据内容公开为视图模型上的属性。然后,您可以使用各种机制来显示基于该内容的控件。例如,如果您公开对象列表,则可以使用数据模板根据对象的类型显示不同的控件。
因此,您只需在视图模型上公开数据,并期望视图提供正确显示数据的必要方法。
例如,您不会公开UserControlOfReportRelatedElements
控件,而是公开包含数据的ReportData
个对象。然后,您将在ReportData
类型上注册一个数据模板,然后显示UserControlOfReportRelatedElements
元素,并显示ReportData
对象中的数据。