【问题标题】:Changing content changes DataContext when using DataTemplate使用 DataTemplate 时更改内容会更改 DataContext
【发布时间】:2016-06-08 08:55:33
【问题描述】:

X 问题。

我想暂时放大(让它占据整个可用空间)窗口内容的一部分。

窗口布局相当复杂:许多嵌套面板、拆分器、要放大的内容有 10 级深。将 Visibility 更改为拉伸内容是不够的(感谢拆分器),而且看起来非常复杂。

你的问题

我决定将该内容移动到用户控件中并执行类似(伪代码)之类的操作

if(IsEnlarged)
{
    oldContent = window.Content; // store
    window.Content = newContent;
}
else
    window.Content = oldContent; // restore

没问题。它在测试项目中运行良好......直到我开始使用数据模板。

问题:如果使用数据模板,那么一旦出现window.Content = newContent,那么newContent.DataContext 就会丢失并与window.DataContext 相同。这将触发各种绑定错误,附加行为突然更改为默认值等等。所有类型的坏东西。

问题:为什么DataContext 会发生变化?如何预防/解决此问题?


这是一个复制品(抱歉,不能再短了):

MainWindow.xaml 包含

<Window.Resources>
    <DataTemplate DataType="{x:Type local:ViewModel}">
        <local:UserControl1 />
    </DataTemplate>
</Window.Resources>
<Grid Background="Gray">
    <ContentControl Content="{Binding ViewModel}" />
</Grid>

MainWindow.cs 包含

public ViewModel ViewModel { get; } = new ViewModel();

public MainWindow()
{
    InitializeComponent();
    DataContext = this;
}

UserControl1.xaml 包含

<Button Width="100"
        Height="100"
        CommandParameter="{Binding RelativeSource={RelativeSource Self}}"
        Command="{Binding Command}" />

ViewModel(使用DelegateCommand

public class ViewModel
{
    public DelegateCommand Command { get; set; }

    bool _set;
    object _content;

    public ViewModel()
    {
        Command = new DelegateCommand(o =>
        {
            var button = (Button)o;
            var window = Window.GetWindow(button);
            _set = !_set;
            if (_set)
            {
                _content = window.Content;
                var a = button.DataContext; // a == ViewModel
                window.Content = button;
                var b = button.DataContext; // b == MainWindow ??? why???
            }
            else
                window.Content = _content;
        });
    }
}

var a = ...设置断点,启动程序,点击按钮,执行步骤,观察button.DataContext以及Output窗口中的绑定错误。

【问题讨论】:

  • 还在您设置 DC 的位置添加 UserControl1 代码,以及使用 DataTemplate 的原因和位置?
  • @AnjumSKhan,不需要设置UserControl1.DataContext,因为数据模板。一切正常,直到您单击按钮。这是一个演示案例的重现,而不是真实的项目(必须使用数据模板)。
  • DataTemplate 是在 MainWindow 中使用的,所以它自然会从 MainWindow 中获取它的 DC。如果你在 UC 代码中设置了 UC 的 DC,那就不一样了。在您的 UC 中,不会有任何 DC,因为您没有设置它。一旦它成为 MainWindow 的一部分,它将获得它的 DC。
  • @AnjumSKhan,然后告诉我为什么a == ViewModel?提问前可以先试一下代码吗?
  • 带有控件洞察力的 mvvm 复制品,它不是 mvvm 复制品,抱歉。

标签: wpf mvvm datacontext


【解决方案1】:

好的,这里有一些一般性的想法。

如果您将对象(视图模型)绑定到 contentcontrol 的 Content 属性,则 wpf 使用 DataTemplate 来可视化对象。如果您没有 DataTemplate,您只会看到 object.ToString()。 DataContext继承意味着DataContext被继承到子元素。所以 real 用户控件将从父控件继承 DataContext。创建 UserControl 时在 stackoverflow 上发现的常见错误 - 它们经常破坏 DataContext 继承并将 DataContext 设置为 self 或新的 DataContext。

UserControl DataContext Binding

【讨论】:

  • button.DataContext = button.DataContext 已修复。感谢您的解释。
【解决方案2】:

您必须尝试将您的DataTemplate 用作ContentTemplate 用于您的ContentControl。由于ContentTemplateContent 上运行,因此它将使用Content 作为其DataContext。而您的Content 包含ViewModel

一旦您的 Button 不再属于您的 DataTemplate,那么它将使用 MainWindow's DataContext

没有看到您的 cmets,我假设您希望 UserControl 中的 DataContext 保持不变,即使您的 UserControl 不是 DataTemplate 的一部分。

因此,使用RelativeSource 显式使用XAML 设置ButtonDataContext

例子,

<Button Content="{Binding Data}" DataContext="{Binding vm1, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}" /> 

在代码中使用DataContext 不是一个好主意。

【讨论】:

    猜你喜欢
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-01
    • 2013-03-06
    • 1970-01-01
    • 2018-08-13
    • 2013-03-12
    相关资源
    最近更新 更多