【问题标题】:What exactly does WPF Data Binding's "RelativeSource FindAncestor" do?WPF 数据绑定的“RelativeSource FindAncestor”究竟是做什么的?
【发布时间】:2010-12-10 20:15:24
【问题描述】:

我目前正在使用 WPF 用户控件(我的 XAML 文件的根元素是“UserControl”),我知道它托管在 Window 中。如何使用数据绑定访问 Window 的属性?

有谁知道为什么这么简单

<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Window}}" Path="..." />

不工作?我得到的错误信息是:

System.Windows.Data 警告:4 : 无法通过引用 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1'' 找到绑定源。

编辑:我最终使用了 ArsenMkrt 方法的变体,因此接受了他的回答。但是,我仍然有兴趣找出 FindAncestor 不能“正常工作”的原因。

【问题讨论】:

  • 你说你改变了他的答案,你能发布你实际做了什么吗?
  • 请注意,我在 MVVM 模式的上下文中寻找解决此问题的方法。我想绑定的 Window 的属性实际上是 Window 的 ViewModel 的属性。
  • ArsenMkrt 建议在 UserControl 中创建一个属性并绑定到该属性,然后(在 XAML 中)将该属性绑定到所需的 Window 属性。然而,对于 MVVM 模式,UserControl 从未出现在 XAML 中,因此第二部分是不可能的。
  • 所以,我按照建议创建了一个要绑定的新属性,但我没有将它放在 UserControl 中,而是将它放在 UserControl 的 ViewModel 中。这个属性只是持有对 Window 的 ViewModel 的直接引用,允许直接访问所需的属性。新属性很容易初始化:使用的引用可以直接传递到 UserControl 的 ViewModel 的构造函数中。

标签: wpf data-binding xaml relativesource findancestor


【解决方案1】:

最好的办法是给 UserControl 起个名字

在UserControl中使用两种方式绑定创建依赖属性MyProperty并在主窗口中绑定它,而不是像这样在UserControl中绑定

<UserControl x:Name = "myControl">
     <Label Content={Binding ElementName= myControl, Path=MyProperty}/>
</UserControl>

【讨论】:

  • 但我想绑定到包含 Window 上的属性(在另一个 XAML 文件中定义),而不是 UserControl。
  • 比在用户控件中拥有属性并将该属性与窗口的属性绑定会更好
  • 你能在 UserControl 中创建依赖属性吗?你不在窗口中添加用户控件吗?
  • 我明白了,谢谢。但是有谁知道为什么 FindAncestor 不能“正常工作”?它的范围是否以某种方式限制在单个 XAML 文件中?
  • 老实说,我不知道为什么它不起作用,但是我的答案是更好的解决方案,因为可以在开发期间更改父类型
【解决方案2】:

我认为你应该像这样设置 Mode="OneWayToSource":

<TextBox Text="{Binding RelativeSource={RelativeSource FindAncestor ,AncestorType={x:Type Grid}},Path=BackGround , Mode=OneWayToSource , UpdateSourceTrigger = PropertyChanged}" />

【讨论】:

    【解决方案3】:

    如果您尝试从ItemsControlDataGridView '逃逸' 到Window,您可能会发现x:Type Window 的AncestorType 不起作用。或者至少似乎没有……

    如果是这种情况,您可能正在运行 Blend 或 Visual Studio,并希望数据在设计时可见 - 但事实并非如此,因为 VS + Blend 都创建了它们自己的实例,这些实例并不是真正的 Windows。它可以在运行时正常工作,但不能在设计模式下工作。

    你可以做几件事:

    • 包装在用户控件中

    • 这是我想出的另一种解决方案。它的一个优点是您不直接引用UserControlWindow,因此如果您更改父容器,您的代码不会中断。

      <Window
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      xmlns:views="clr-namespace:MyWPFApplication.Views"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"                  
      x:Class="MyWPFApplication.Views.UPCLabelPrinterWindow"
      mc:Ignorable="d"
      x:Name="LayoutRoot"
      Title="UPCLabelPrinterWindow">
      
      <views:DataContextWrapper>
          <DockPanel>
              ...
          </DockPanel>
      </views:DataContextWrapper>
      

    DataContextWrapper 只是一个网格

    namespace MyWPFApplication.Views {
       public class DataContextWrapper : Grid
       {
    
       }
    }
    

    然后当你绑定你这样做:

    <TextBlock Text="{Binding="{Binding DataContext.SomeText, 
      RelativeSource={RelativeSource AncestorType={x:Type views:DataContextWrapper}, 
      Mode=FindAncestor}}" />
    

    注意:如果您想绑定到 ON Window 本身的属性,则比较棘手,您可能应该通过依赖属性或类似的方式进行绑定。但是,如果您使用的是 MVVM,那么这是我找到的一种解决方案。

    【讨论】:

    • 在我的情况下,AncestorType={x:Type Window} 非常有帮助,因为 AncestorType=UserControl 不知何故没有指向我的窗口——尽管它通常会指向。
    【解决方案4】:

    如果您使用视图模型作为 Window 的 DataContext,并且您需要绑定的属性来自该视图模型,那么您应该在路径前加上 DataContext.MyPropertyPath,如下所示:

    <TextBox Text="{Binding DataContext.MyProperty, RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}"/>
    

    这翻译为“为我找到一个祖先窗口,然后在它的数据上下文中查找 MyProperty”

    【讨论】:

      猜你喜欢
      • 2013-05-27
      • 2011-01-18
      • 2011-09-05
      • 1970-01-01
      • 1970-01-01
      • 2013-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多