我目前正在创建一个测试WPF灵活性的应用程序。我有一些用户控件,当涉及到它的ViewModel时,它们是非常透明的。透明的意思是usercontrol可以使用任何类型的ViewModel,前提是ViewModel具有绑定到该usercontrol中控件的所有必需属性。我这样做是通过将ViewModel指定为特定用户控件的datacontext。
当只有两个用户控件(一个可以访问ViewModelLocator,一个需要前者的datacontext声明)时,这种方法有效。当它达到3层或更多用户控制时,我不知道该怎么做。有没有办法在usercontrol中设置usercontrol的datacontext,该usercontrol驻留在可以访问ViewModelLocator的用户控件中?
以下是一些可以澄清我的问题的代码。
此代码是父usercontrol。它旨在用于使用MAF的应用程序。我使用非静态ViewModelLocator来确保每个插件实例使用不同的ViewModelLocator实例,因为插件没有自己的app.xaml(因此没有全局资源)。如您所见,我从网格中的单独程序集中放置了一个usercontrol,然后声明了它的datacontext,以便所述usercontrol与父usercontrol的ViewModelLocator进行交互。
<UserControl x:Class="TestApp.Inventory.Common.Views.MaterialsNewView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:vm="clr-namespace:TestApp.Inventory.Common.ViewModel"
xmlns:views="clr-namespace:TestApp.Inventory.Common.Views"
xmlns:viewsSupp="clr-namespace:TestApp.Supplier.Common.Views;assembly=TestApp.Supplier.Common"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" Height="607" Width="616" Loaded="UserControl_Loaded">
<UserControl.Resources>
<vm:ViewModelLocator x:Key="Locator" />
</UserControl.Resources>
<UserControl.DataContext>
<Binding Path="MaterialsNewView" Source="{StaticResource Locator}" />
</UserControl.DataContext>
<Grid>
<views:SupplierView x:Name="supplierView" Margin="145,306,0,0" HorizontalAlignment="Left" Width="328" Height="258" VerticalAlignment="Top" DataContext="{Binding Source={StaticResource Locator}, Path=SupplierView}" />
</Grid>
</UserControl>
然后我有了child usercontrol的代码。就像我之前所说的那样,子用户控件在ViewModel方面是透明的。这就是每次都应该在父usercontrol中声明datacontext的原因。
<UserControl x:Class="TestApp.Supplier.Common.Views.SupplierView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ignore="http://www.ignore.com"
mc:Ignorable="d ignore" Height="289" Width="352"
xmlns:my="clr-namespace:TestApp.Lookup.Common.Views;assembly=TestApp.Lookup.Common">
<Grid>
<my:MaterialTypeListView Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Grid, AncestorLevel=1}, Path=ActualHeight}" HorizontalAlignment="Left" Name="materialTypeListView1" VerticalAlignment="Top" Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Grid, AncestorLevel=1}, Path=ActualWidth}" />
</Grid>
</UserControl>
我的问题是当子用户控件有自己的子用户控件时。我不知道如何从父usercontrol声明其datacontext。目标是无论有多少个用户控件层,它们都应该与父用户控件的ViewModelLocator进行交互。
答案 0 :(得分:2)
将DependencyProperty
添加到名为MaterialTypeList的UserControl SupplierView。
public partial class SupplierView
{
public List<string> MaterialTypeList
{
get { return (List<string>)GetValue(MaterialTypeListProperty); }
set { SetValue(MaterialTypeListProperty, value);}
}
public static readonly DependencyProperty MaterialTypeListProperty =
DependencyProperty.Register("MaterialTypeList", typeof(string), typeof(SupplierView),
new PropertyMetadata(null));
}
在SupplierView上的UserControl MaterialNewView上添加绑定到MaterialTypeList
<UserControl x:Class="TestApp.Supplier.Common.Views.SupplierView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ignore="http://www.ignore.com"
mc:Ignorable="d ignore" Height="289" Width="352"
xmlns:my="clr-namespace:TestApp.Lookup.Common.Views;assembly=TestApp.Lookup.Common">
<Grid>
<my:MaterialTypeListView
DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl, AncestorLevel=1}, Path=MaterialTypeList}"
Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Grid, AncestorLevel=1}, Path=ActualHeight}" HorizontalAlignment="Left" Name="materialTypeListView1" VerticalAlignment="Top" Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Grid, AncestorLevel=1}, Path=ActualWidth}" />
</Grid>
</UserControl>
在MaterialTypeListView上的UserControl SupplierView上添加绑定到MaterialTypeList。
<UserControl x:Class="TestApp.Inventory.Common.Views.MaterialsNewView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:vm="clr-namespace:TestApp.Inventory.Common.ViewModel"
xmlns:views="clr-namespace:TestApp.Inventory.Common.Views"
xmlns:viewsSupp="clr-namespace:TestApp.Supplier.Common.Views;assembly=TestApp.Supplier.Common"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" Height="607" Width="616" Loaded="UserControl_Loaded">
<UserControl.Resources>
<vm:ViewModelLocator x:Key="Locator" />
</UserControl.Resources>
<UserControl.DataContext>
<Binding Path="MaterialsNewView" Source="{StaticResource Locator}" />
</UserControl.DataContext>
<Grid>
<views:SupplierView x:Name="supplierView" Margin="145,306,0,0"
MaterialTypeList="{Binding [HERE YOUR LIST OF MATERIALTYPE]}"
HorizontalAlignment="Left" Width="328" Height="258" VerticalAlignment="Top" DataContext="{Binding Source={StaticResource Locator}, Path=SupplierView}" />
</Grid>
</UserControl>