【问题标题】:Set the datacontext of a usercontrol within a usercontrol no matter how many layers of usercontrol无论用户控件有多少层,在用户控件内设置用户控件的数据上下文
【发布时间】:2013-04-15 10:24:22
【问题描述】:

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

这适用于只有两个用户控件(一个可以访问 ViewModelLocator,一个需要前者的数据上下文声明)。当它达到 3 层或更多的用户控件时,我不知道该怎么办。有没有办法在用户控件中设置用户控件的数据上下文,该用户控件位于有权访问 ViewModelLocator 的用户控件中?

下面是一些可以澄清我的问题的代码。

此代码是父用户控件。它旨在用于使用 MAF 的应用程序。我使用了非静态 ViewModelLocator 来确保每个插件实例使用不同的 ViewModelLocator 实例,并且因为插件没有自己的 app.xaml(因此没有全局资源)。如您所见,我在网格中放置了一个来自单独程序集的用户控件,然后声明其数据上下文,以便所述用户控件与父用户控件的 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 而言是透明的。这就是为什么每次都要在父用户控件中声明数据上下文的原因。

<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>

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

【问题讨论】:

    标签: c# wpf mvvm user-controls mvvm-light


    【解决方案1】:

    将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>
    

    【讨论】:

    • 感谢您的快速回复。然而,这两个用户控件使用不同的 ViewModel。我希望 MaterialTypeListView 有一种方法可以与 MaterialsNewView 访问的 ViewModelLocator 进行通信,以获取适合它的任何 ViewModel,如果可能的话,从 MaterialsNewView 声明它的绑定。
    • 改变了我的答案。简而言之,将 DependencyProperty 添加到您绑定材料类型列表的 uc:SupplierView。
    • 很抱歉,我是 WPF 新手,我不太明白 DependencyProperty 将如何解决我的问题。如果可能的话,你能详细说明一下并提供示例代码吗?非常感谢。
    • 是的,现在说得通了。回到办公室后,我会尝试一下,然后再回复您。
    • 成功了!这几天我一直在寻找方法。这就像一个魅力。你真棒!非常感谢! :D
    猜你喜欢
    • 2012-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-28
    • 1970-01-01
    相关资源
    最近更新 更多