【问题标题】:How to use DataTemplate to set DataContext如何使用 DataTemplate 设置 DataContext
【发布时间】:2016-02-06 15:20:50
【问题描述】:

有人告诉我,在 MVVM 中为视图设置 DataContext 的最佳方法是使用 DataTemplate。所以我试图通过使用 DataTemplate 将 MainWindow 的 DataContext 设置为 MainWindowViewModel 的一个实例。

我一直无法弄清楚如何。

我尝试将 ResourceDictionary 放在不同的地方(在 App.xaml 中,在 Window.Resources 标记中......)

我用谷歌搜索无济于事。这就是我所拥有的......(它不起作用,但是,它在这里)

App.xaml:

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Dictionary1.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

Dictionary1.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:local="clr-namespace:DataTemplateTesting" >

    <DataTemplate DataType="{x:Type local:MainViewModel}">
        <local:MainWindow/>
    </DataTemplate>

</ResourceDictionary>

MainViewModel.cs

namespace DataTemplateTesting
{
    public class MainViewModel
    {
        public MainViewModel() { }
    }
}

我唯一做的另一件事是在 MainWindow 中为 DataContextChanged 事件添加一个处理程序,这样我就可以查看它是否触发了......它没有。

有什么办法解决这个问题吗?

编辑: 并不是说这里有什么不能生成的,而是……这是 MainWindow 代码。

MainWindow.xaml

<Window x:Class="DataTemplateTesting.MainWindow"
        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:local="clr-namespace:DataTemplateTesting"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        DataContextChanged="Window_DataContextChanged"        >
    <Grid>

    </Grid>
</Window>

MainWindow.xaml.cs

namespace DataTemplateTesting
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            int i = 10; //This line exists solely to put a debug stop on.
        }
    }
}

【问题讨论】:

  • 你能添加MainWindow代码吗?
  • 没有任何 MainWindow 代码。我唯一做的就是为 DataContextChanged 添加一个事件处理程序,这样我就可以看到它了。最好没有 MainWindow 代码。
  • 有一个MainWindow 控件,对吧?那么,必须有一些xaml代码来定义它。
  • 你去...我猜。自动生成的相同代码加上一个事件处理程序。

标签: wpf data-binding datatemplate datacontext


【解决方案1】:
<DataTemplate DataType="{x:Type local:MainViewModel}">
    <local:MainWindow/>
</DataTemplate>

首先,此语句并不意味着“创建一个MainWindow 并将其DataContext 设置为MainViewModel”。这实际上意味着每当您看到 MainViewModel 时,只需将 MainWindow 放入可视化树中即可。

其次,您不能将 Window 类作为子类添加到另一个 Visual。如果你尝试,你会得到一个异常Window must be the root of the tree. Cannot add Window as a child of Visual

正确的做法是这样的:

<Window x:Class="DataTemplateTesting.MainWindow"
    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:local="clr-namespace:DataTemplateTesting"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <ContentControl>
        <ContentControl.Content>
            <local:MainViewModel/>
        </ContentControl>
    </ContentControl>
</Grid>

在资源字典中定义:

<DataTemplate DataType="{x:Type local:MainViewModel}">
    <local:SomeUserControl/>
</DataTemplate>

并创建一个用户控件:

<UserControl x:Class="DataTemplateTesting.SomeUserControl"
         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" 
         d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBox/>
    </Grid>
</UserControl>

如果您的内容动态更改或您正在定义视图的ItemTemplate,这很有用。否则,只需手动设置WindowDataContext

<Window x:Class="DataTemplateTesting.MainWindow"
        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:local="clr-namespace:DataTemplateTesting"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">

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

    <Grid>

    </Grid>

【讨论】:

  • 经过一些实验,我意识到这种方法的酷炫之处。您可以将 绑定到您的视图模型的属性。大量的控制和视图模型中没有视图“垃圾”。
  • 声明First, this statement does not mean "Create a MainWindow and set its DataContext to MainViewModel". It actually means whenever you see a MainViewModel just put MainWindow in the visual tree. 并不完全正确,因为它实际上将DataContext 设置为触发数据模板的MainViewModel 实例。我不知道它是在哪里完成的,但它已经完成了。
  • 酷,是的。我们应该这样做吗?不,您应该从另一个地方实例化您的视图模型,以便您可以将依赖项注入其中。如果您从 XAML 实例化视图模型,那么您将在测试视图模型时遇到问题,并且可能会出现大量 new() 和对静态项的调用,这些都应该避免。
猜你喜欢
  • 1970-01-01
  • 2013-12-04
  • 2016-09-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多