C# 在usercontrol中设置usercontrol的datacontext,无论usercontrol有多少层

C# 在usercontrol中设置usercontrol的datacontext,无论usercontrol有多少层,c#,wpf,mvvm,user-controls,mvvm-light,C#,Wpf,Mvvm,User Controls,Mvvm Light,我目前正在创建一个测试WPF灵活性的应用程序。我有一些usercontrols,当涉及到它的ViewModel时,它们是非常透明的。我所说的透明是指,只要ViewModel具有绑定到该usercontrol中的控件的所有必需属性,usercontrol就可以使用任何类型的ViewModel。为此,我将ViewModel指定为特定usercontrol的datacontext 当只有两个UserControl(一个可以访问ViewModelLocator,另一个需要来自前者的datacontext

我目前正在创建一个测试WPF灵活性的应用程序。我有一些usercontrols,当涉及到它的ViewModel时,它们是非常透明的。我所说的透明是指,只要ViewModel具有绑定到该usercontrol中的控件的所有必需属性,usercontrol就可以使用任何类型的ViewModel。为此,我将ViewModel指定为特定usercontrol的datacontext

当只有两个UserControl(一个可以访问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>

然后我有了子用户控件的代码。正如我前面所说的,子用户控件在ViewModel方面是透明的。这就是每次都应该在父用户控件中声明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>


我的问题是当子用户控件有自己的子用户控件时。我不知道如何从父用户控件声明其datacontext。目标是,无论用户控件有多少层,它们都应该与父用户控件的ViewModelLocator交互。

向名为MaterialTypeList的usercontrol SupplierView添加一个
DependencyProperty

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));
}
    <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>
公共部分类供应商视图
{
公共列表材料类型列表
{
获取{return(List)GetValue(MaterialTypeListProperty);}
set{SetValue(MaterialTypeListProperty,value);}
}
公共静态只读从属属性MaterialTypeListProperty=
DependencyProperty.Register(“材料类型列表”、类型(字符串)、类型(供应商视图),
新属性元数据(空);
}
将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

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));
}
    <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>


感谢您的快速回复。但是,这两个用户控件使用不同的视图模型。我希望MaterialTypeListView能够与MaterialsNewView访问的ViewModelLocator进行通信,以获取任何适用于它的ViewModel,如果可能,还可以从MaterialsNewView声明其绑定。更改了我的答案。简而言之,在uc:Supplier视图中添加DependencyProperty,您可以将materialtypelist绑定到该视图。很抱歉,我是WPF的新手,我不太明白DependencyProperty如何解决我的问题。如果可能的话,你能详细说明一下并提供示例代码吗?非常感谢。是的,现在说得通了。我一回到办公室就试试,然后再给你打电话。成功了!我已经找了好几天了。这很有魅力。你真棒!非常感谢D