WPF 数据绑定的“RelativeSource FindAncestor”究竟是做什么的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1636807/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 21:08:28  来源:igfitidea点击:

What exactly does WPF Data Binding's "RelativeSource FindAncestor" do?

wpfdata-bindingxamlrelativesourcefindancestor

提问by user200783

I am currently working within a WPF user control (the root element of my XAML file is "UserControl"), which I know is being hosted inside a Window. How can I access a property of the Window using data binding?

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

Does anyone know why simply

有谁知道为什么简单

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

does not work? The error message I get is:

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

System.Windows.Data Warning: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1''.

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

Edit:I ended up using a variation on ArsenMkrt's approach, so have accepted his answer. However, I am still interested in finding out why FindAncestor does not "just work".

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

采纳答案by Arsen Mkrtchyan

The best way is to give a name to UserControl

最好的方法是给 UserControl 起一个名字

Create dependency property MyProperty in UserControl with two way binding and bind it in main Window, than bind in UserControl like this

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

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

回答by Simon_Weaver

If you're trying to 'escape' from an ItemsControlor DataGridViewto get to a Windowyou may be finding that AncestorType of x:Type Windowdoesn't work. Or at least doesn't seem to...

如果您试图从 anItemsControlDataGridView到达 a 中“逃脱”,Window您可能会发现 AncestorTypex:Type Window不起作用。或者至少似乎没有……

If this is the case you're probably running Blend or Visual Studio and expecting the data to be visible at design time - which it won't because VS + Blend both create their own instances that aren't really Windows. It will work at runtime just fine, but not during design mode.

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

There's a couple things you can do:

您可以做以下几件事:

  • Wrap in a UserControl

  • Here's an alternative solution I've come up with. It has one advantage in that you're not referencing a UserControlor Windowdirectly, so if you change the parent container your code won't break.

    <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>
    

  • 包装在用户控件中

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

    <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>
    

Where DataContextWrapperis just a Grid

哪里DataContextWrapper只是一个网格

namespace MyWPFApplication.Views {
   public class DataContextWrapper : Grid
   {

   }
}

Then when you bind you do this :

然后当你绑定你这样做:

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

Note: if you want to bind to a property ON Window itself it's trickier and you should probably bind via a dependency property or something like that. But if you are using MVVM then this is one solution I found.

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

回答by MahmudReza Tari

I Think You Should SET Mode="OneWayToSource" Like this:

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

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