【问题标题】:WPF: Setting DataContext of a UserControl with Binding not working in XAMLWPF:使用绑定设置用户控件的 DataContext 在 XAML 中不起作用
【发布时间】:2011-02-09 08:37:24
【问题描述】:

我正在尝试让我的第一个 WPF 应用程序使用 MVVM 运行,但遇到了一些绑定问题。

设置是我有一个视图和 viewModel,其中包含用户详细信息(父级),为了保持简单,我将该视图的一部分放入单独的视图和 viewModel(子级)中。子视图被定义为 UserControl。

我遇到的问题是如何设置子视图(UserControl)的 DataContext。我的父 ViewModel 有一个公开子 ViewModel 的属性,如下所示:

class ParentViewModel: INotifyPropertyChanged
{
    public ChildViewModel childViewModel { get; set; }
    //...
}

在我的父视图的 XAML 中(它的 DataContext 设置为 ParentViewModel),我尝试如下设置子视图的 DataContext:

<views:ChildView 
    x:Name="ChildView"
    DataContext="{Binding childViewModel}"/>

但是,这不起作用。子视图的 DataContext 设置为与父视图(即 ParentViewModel)相同的 DataContext,就好像我根本没有设置它一样。我还尝试在子视图本身中设置 DataContext,这也不起作用:

<UserControl x:Class="DietRecorder.Client.View.ChildView"
    DataContext="childViewModel"

我找到了几种解决方法。在子视图中,我可以通过在路径中包含 ChildViewModel 来绑定所有内容:

<SomeControl Visibility="{Binding Path=childViewModel.IsVisible}">

但我不希望子视图具有这种层次结构的意识。在代码中设置 DataContext 也可以 - 但是,我必须在显示父视图后执行此操作,否则当我调用 Show() 时 DataContext 会被覆盖:

parentView.Show();
parentView.ChildView.DataContext = parentViewModel.childViewModel;

这段代码也让我感到不安,违反了LOD等等。

这似乎只是 DataContext 的问题 - 我可以在孩子中绑定其他东西,例如我尝试将 FontSize 绑定到一个 int 属性只是为了测试它:

<views:ChildView 
    x:Name="ChildView"
    FontSize="{Binding Path=someVal}"/>

而且效果很好。

但我确信绑定 DataContext 应该可以工作 - 我见过类似的例子。我在这里错过了什么明显的东西吗?有没有理由这不起作用?某处有拼写错误吗? (为了您的利益,我重命名了一些东西,所以无论如何您都无法帮助我)。

欢迎任何想法。

编辑

再次查看此代码,我似乎在某处犯了错误,因为父视图中的以下 XAML 现在似乎可以工作:

<views:ChildView 
    x:Name="ChildView"
    DataContext="{Binding childViewModel}"/>

我不知道为什么我最初不能让它工作,或者我可能做了什么改变才能让它工作。可能是答案之一所暗示的 INotifyPropertyChanged 问题。哦,好吧,向上和向上..

【问题讨论】:

    标签: mvvm binding


    【解决方案1】:

    我一直在寻找同样的东西,但我找到了一种方法。基本上,我使用

    将子项的 DataContext 绑定到某个父项(窗口)的 DataContext
    DataContext="{Binding ElementName=_topLevel, Path=DataContext.childViewModel}"
    

    我在某些父控件(窗口)上设置了x:Name="_topLevel"

    我尝试使用 RelativeSource/FindAncestor 代替 ElementName 但它不起作用 - 但这可能是我的错。

    对我来说感觉像是一个 hack,但比绑定到顶级视图模型更好。

    【讨论】:

    • 虽然我没有尝试过,但应该可以,所以我会为你的努力+1 - 但这个解决方案与我建议的解决方案之一有同样的问题以上,就是孩子对父母的了解。这要么只是一种难闻的气味,要么是一个真正的问题,这取决于您是否在不同的父母视图中使用孩子。在检查我的代码以获取此答案时,我发现它现在可以工作了,尽管我不确定为什么 - 请参阅编辑了解详细信息。
    【解决方案2】:

    这不是问题的答案,但可能会在相同情况下帮助其他人。

    我正好遇到了这个问题,发现

    parentView.ChildView.DataContext = parentViewModel.childViewModel;
    

    方法有效(虽然我发现它在执行 Show() 之前有效),但对它的疑虑与原始提问者相同,因此尝试了

    DataContext="{Binding ElementName=_topLevel, Path=DataContext.childViewModel}"
    

    方法,这似乎也有效。但后来我尝试再次回到原始代码和原始 XAML,现在它突然也起作用了。这反映了原始提问者的行为,作者认为他们在某处犯了错误,因为 XAML 似乎无缘无故地开始工作。

    我能看到的唯一变化是 Visual Studio 现在在设计时在 UserControl 中显示示例数据,因此它在某处缓存了一些示例数据,这似乎使它工作。不幸的是,我不确定这两个更改中的哪一个。

    示例数据的出现让我想知道这个问题是否与我在父 XAML 文件和子 XAML 文件中的 d:DataContext 的使用有关,但这只是猜测。

    【讨论】:

      【解决方案3】:

      我怀疑这是因为 childViewModel 属性没有引发 PropertyChanged 事件。评估绑定时,此属性可能为 null(在这种情况下,DataContext 将回退到父级的属性)。稍后实例化 childViewModel 时,不会引发 PropertyChanged 事件,并且永远不会通知绑定现在有一个 DataContext。

      尝试在 childViewModel 属性中引发 PropertyChanged 事件。

      干杯, 洛朗

      【讨论】:

      • 好主意,但恐怕没有乐趣。我在想这可能与订单有关,但是当绑定发生时子 viewModel 应该可用 - 当我使用 int 属性设置字体大小时它可以工作,这同时发生,而这并不t 使用 PropertyChanged。
      猜你喜欢
      • 2016-04-10
      • 2011-08-11
      • 2013-01-15
      • 2012-04-15
      • 2016-03-10
      • 1970-01-01
      • 1970-01-01
      • 2014-09-09
      • 2015-12-10
      相关资源
      最近更新 更多