这是我第一次尝试实现MVVM模型,所以提前道歉。我有一个主窗口,它有自己的ViewModel。然后主窗口有三个用户控件,根据导航菜单中选择的内容加载。但是,数据上下文未更改为正确的视图模型。
MainWindow.xaml
<Window.DataContext>
<VM:MainVM></VM:MainVM>
</Window.DataContext>
<Window.Resources>
<DataTemplate x:Key="View1Template" DataType="{x:Type VM:CustomerVM}">
<View:Customers DataContext="{Binding VM:CustomerVM}" />
</DataTemplate>
<DataTemplate x:Key="View2Template" DataType="{x:Type VM:SuppliersVM}">
<View:Suppliers DataContext="{Binding VM:Suppliers}"/>
</DataTemplate>
</Window.Resources>
<ContentControl Margin="0,135,0,10" Grid.Column="1">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource View1Template}" />
<Style.Triggers>
<DataTrigger Binding="{Binding SwitchView}" Value="0">
<Setter Property="ContentTemplate" Value="{StaticResource View1Template}" />
</DataTrigger>
<DataTrigger Binding="{Binding SwitchView}" Value="1">
<Setter Property="ContentTemplate" Value="{StaticResource View2Template}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
这有自己的ViewModel并且导航正确加载视图,但是我有一个在加载时运行且不执行的命令。这只是填充列表视图。我知道它有效,因为如果我删除窗口的datacontext并将其设置为CustomerVM
,则会填充列表视图,但导航不再有效,因为MainVM
已被删除。
Customer.xaml
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding LoadCustomersCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
<TextBox Tag="Search Customers" x:Name="searchTextBox" Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" HorizontalAlignment="Left" Height="40" Margin="10,9,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="340" Padding="5,6,0,0" FontSize="16"/>
<Label Content="{Binding Path=SearchText}" Margin="430,0,436,263" />
<ListView ItemsSource="{Binding Customers}" x:Name="customerListBox" Margin="10,57,10,10" AlternationCount="2" >
<ListView.View>
<GridView>
<GridViewColumn Header="ID" Width="Auto" DisplayMemberBinding="{Binding id}" />
<GridViewColumn Header="NAME" Width="Auto" DisplayMemberBinding="{Binding name}" />
<GridViewColumn Header="ADDRESS" Width="Auto" DisplayMemberBinding="{Binding address1}" />
<GridViewColumn Header="ADDRESS 2" Width="150" DisplayMemberBinding="{Binding address2}" />
<GridViewColumn Header="TOWN" Width="150" DisplayMemberBinding="{Binding town}" />
<GridViewColumn Header="COUNTY" Width="150" DisplayMemberBinding="{Binding county}" />
<GridViewColumn Header="POSTCODE" Width="150" DisplayMemberBinding="{Binding postcode}" />
<GridViewColumn Header="PHONE" Width="150" DisplayMemberBinding="{Binding phone}" />
<GridViewColumn Header="EMAIL" Width="150" DisplayMemberBinding="{Binding email}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
CustomerVM.cs
private string _searchText;
private readonly ObservableCollection<Customer> _customers = new ObservableCollection<Customer>();
public string Title = "Customers";
public string SearchText
{
get { return _searchText; }
set
{
_searchText = value;
RaisePropertyChangedEvent("SearchText");
}
}
public IEnumerable<Customer> Customers
{
get { return _customers; }
}
public ICommand LoadCustomersCommand
{
get { return new DelegateCommand(LoadCustomers); }
}
public void LoadCustomers()
{
Customer cus = new Customer { id = 1, name = "sam" };
_customers.Add(cus);
}
MainVM.cs
public ICommand NavigationClick
{
get { return new DelegateCommand(Navigate); }
}
public void Navigate()
{
SwitchView = 1;
}
答案 0 :(得分:4)
我认为这里有几件事情。我们从一开始就对我最清楚的那个开始。
DataContext
是一个对象 - 通常是viewmodel类的一个实例。 DataTemplate
用于显示viewmodel类的实例。它的DataContext
由它包含的控件继承。这可能是你想要的:
<Window.Resources>
<DataTemplate DataType="{x:Type VM:CustomerVM}">
<View:Customers />
</DataTemplate>
<DataTemplate DataType="{x:Type VM:SuppliersVM}">
<View:Suppliers />
</DataTemplate>
</Window.Resources>
其次,您必须使用一个子视图模型或另一个子视图模型的实际实例填充ContentControl。
您找到的一种方法是在XAML中为每个视图提供一个<DataContext>
元素,以创建一个viewmodel实例:
<DataContext>
<VM:CustomerVM />
</DataContext>
但是主视图模型如何与其子代进行交互?一种解决方案是使用MVVM框架添加拜占庭定位器&#34;中途解决了一堆乱七八糟的问题和解决方法。 Much effort is spent satisfying the framework's demands。
该设计将视图置于一切之中,但视图没有逻辑。他们没有业务负责人。 &#34;大脑&#34;您的应用程序被分成十几个彼此隐藏的小块。
另一种方式是以#34; viewmodel为中心的设计&#34;:将您的应用程序设计为一组视图模型。子视图模型是父视图模型的属性。 MainVM
可以轻松找到其子SupplierVM
,因为MainVM
已创建并拥有它。这些视图是视图模型的孤立附属物,而不是视图模型是视图模型悬挂的孤立附属物 - 这绝对是好的,因为视图几乎就是坐在那里。
使用WPF的所有内容都更容易。
您在这里有三个视图模型:父母MainVM
和两个孩子,CustomerVM
和SupplierVM
。在主视图中,您希望一次显示一个孩子或另一个孩子。
所以我们给MainVM
每个孩子的一个实例:
public MainVM()
{
Customer = new CustomerVM();
Supplier = new SupplierVM();
}
public CustomerVM Customer {
get { return _customerVM; }
private set { _customerVM = value; }
}
public SupplierVM Supplier {
get { return _supplierVM; }
private set { _supplierVM = value; }
}
public INotifyPropertyChanged _selectedChild;
public INotifyPropertyChanged SelectedChild {
get { return _selectedChild; }
set {
if (value != _selectedChild) {
_selectedChild = value;
// I don't know how you raise PropertyChanged; if it doesn't look
// like this, let me know.
OnPropertyChanged();
}
}
}
public void Navigate()
{
SelectedChild = Customer;
}
在XAML中,内容控制非常简单。您放入SelectedChild
的内容将显示在内容控件中。它如何知道使用什么模板?
简单:我们从上面的数据模板中删除了x:Key
属性,但我们保留了DataType
属性。这使得它们成为所谓的隐含数据模板&#34;:无论它们在何处,它们都将由需要显示的任何ContentControl
自动 使用这些类型之一的对象。如果您告诉XAML&#34;这里是Window
,请CustomerVM
中的任何位置;将它显示给用户&#34;,XAML将使用上述两个数据模板中的第一个来显示它。
<ContentControl
Content="{Binding SelectedChild}"
Margin="0,135,0,10"
Grid.Column="1"
/>
你可以摆脱SwitchView
财产。你所做的确实有效(而且你已经发现,做一些在XAML中工作的东西并不容易),但这种方式更简单,更传统。