【问题标题】:Set DataContext in the logic tree in WPF Blend在 WPF Blend 的逻辑树中设置 DataContext
【发布时间】:2014-05-11 17:03:01
【问题描述】:

我有一个关于窗口的数据上下文以及子控件如何继承它的问题。

如果我有一个窗口,其DataContext 属性在 XAML 中设置如下:

<Window.DataContext>
    <local:SomeViewModel />
</Window.DataContext>

通过向窗口添加用户控件,我了解用户控件的数据上下文将从窗口继承(除非我另有说明)。

<local:MyUserControl />

在用户控件中呢?由于它是一个不同的 XAML 文件,我如何在用户控件中强烈键入数据上下文?因此,如果我在控件中指定数据上下文:

<UserControl.DataContext>
    <local:SomeViewModel />
</UserControl.DataContext>

这是否会覆盖 Window 的视图模型实例,在内存中创建一个新实例?我认为确实如此,如果是这样,我如何通过 xaml 将视图模型传递给子视图?我知道我可以通过直接分配在代码隐藏中做到这一点,但我希望这可以在 xaml 中处理。

我们已经隔离了大部分 UI,目前必须在后面的代码中手动分配上下文。

我尝试使用RelativeSource,但它似乎不起作用。也许我用错了,但上下文从未传递过。

有什么想法吗?

更新 1

为了澄清,我展示了一个简单的窗口,其中 DataContext 设置为自定义视图模型。

<Window x:Class="MyProject.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:viewModels="clr-namespace:MyProject.ViewModels"
        xmlns:views="clr-namespace:MyProject.MyCustomView">

    <Window.DataContext>
        <viewModels:ProjectViewModel />
    </Window.DataContext>

    <StackPanel>
        <views:MyCustomView />
    </StackPanel>
<Window>

现在在我的MyCustomView 用户控件中,其他开发它的开发人员不会知道数据上下文的类型是什么,而无需手动遍历所有可能的父窗口以查看它被使用的位置。我想要的是在我的 UserControl 中执行以下操作:

<UserControl x:Class="MyProject.Views.DiaryDetailsDescription"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         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" >

<UserControl.DataContext Type="viewModels:ProjectViewModel />

</UserControl>

因此,处理该用户控件的设计人员/开发人员知道该用户控件的数据上下文将是 ProjectViewModel 类型,由拥有的 Window 继承。

更新 2

所以为了进一步澄清,我想要在我的用户控件 XAML 中执行的操作等同于以下 C# 代码。

return (SingleViewModel)this.DataContext;

因此,Blend 中的设计器确切地知道 DataContext 将是什么类型。对他来说,DataContext 只是用户控件中的一个对象,尽管它从 Window 继承了SingleViewModel 上下文。

【问题讨论】:

  • how can I pass around a ViewModel to children views via xaml? - 你能详细写一下吗?
  • 如果默认继承,那还需要手动传递什么呢?
  • 问题是用户控件不知道数据上下文的类型。它使智能感觉毫无价值且难以编码。如果我可以在用户控件 xaml 中强烈键入上下文,使用父类型会很好。
  • 另一个原因是设计师和其他开发人员需要这个。如果我将控件添加到主窗口,那么我知道上下文将是什么。如果另一个开发人员发现布局问题并打开控件 xaml 来修复它,则不会有任何强类型来让他/她知道上下文是什么类型。
  • 我应@Anatoliy 的要求添加了额外的说明。

标签: wpf xaml mvvm datacontext


【解决方案1】:

也许你应该尝试使用一堆DataTemplate + UserControl?在资源例如在窗口中使用您的 UserControl 创建DataTemplate

<Window.Resources>
    <DataTemplate DataType="{x:Type vm:SingleViewModel}">
        <vw:SingleView /> <!-- Your UserControl -->
    </DataTemplate>
</Window.Resources>

并在根面板中添加ContentControl,如下所示:

<ContentControl Name="MyContent"  
                Content="{Binding Path=CurrentViewModel}" />

CurrentViewModel 可能是 SingleViewModel 类型。

在这种情况下,我们立即看到 SingleView DataContext 使用 vm:SingleViewModel 类型。有关详细信息,请参阅 thisthis

Edit: more suitable option

你也可以试试d:DesignInstance:

使用d:DesignInstance 在设计时为运行时分配的DataContext 创建数据绑定。要创建数据绑定,您可以使用数据绑定构建器来创建特殊的设计时数据上下文并将 DesignInstance 设置为业务对象类型。 DesignInstance 是设计时属性。

它在 Blend 中成功用于分配 DataContext。 d:DesignInstance 提供了一种创建非人造类型的技术,将 d:DesignInstance 上的属性 IsDesignTimeCreatable 设置为 True 可以实现这一点。

欲了解更多信息,请参阅:

d:DesignInstance, d:DesignData in Visual Studio 2010 Beta2

【讨论】:

  • 我不确定使用 ContentControl 是我想要的。也许是;这允许我基于与当前窗口关联的 ViewModel 实例化一个视图。我已经准备好了。我的问题是,如何在我的自定义用户控件 XAML 中强烈键入数据上下文,以便设计器(在 Blend 中)知道数据上下文类型是什么。还在使用从窗口继承的数据上下文?
  • 因此在您的示例中,vw:SingleView 用户控件用于SingleViewModel,但vm:SingleView 用户控件 XAML 不知道它的 DataContext 被强类型化为vm:SingleViewModel。这是我试图解决的问题。因此,使用 Blend 的设计人员将知道自定义用户控件的实际数据上下文是什么,而不必爬过所有可能使用该控件的窗口,读取 XAML。
  • @Johnathon Sullinger:也许你适合DesignInstance DataContext
  • 这正是我想要的。谢谢阿纳托利!您能否将该链接添加到您的答案中,以便我将其标记为已回答?
  • @Johnathon Sullinger:是的,我将此链接添加到我的答案中,请查看我的编辑。
猜你喜欢
  • 1970-01-01
  • 2014-07-06
  • 1970-01-01
  • 2016-04-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-06
  • 2015-03-19
相关资源
最近更新 更多