在XAML中绑定到Self /'this'

简单的WPF / XAML问题。 在XAML中,如何在给定的上下文中引用Self / this对象? 在一个非常基本的应用程序中,窗口的主窗口,一个控件和一个编码的C#属性,我想将控件的属性绑定到窗口的手工编码属性。

在代码中,这很容易 – 在Window的构造函数中,我添加了这个:

Binding bind = new Binding(); bind.Source = this; bind.Path = new PropertyPath("ButtonWidth"); button1.SetBinding(WidthProperty, bind); 

很明显,我有一个名为ButtonWidth的属性,以及一个名为button1的控件。 我无法弄清楚如何在XAML中做到这一点。 像下面的例子的各种尝试没有奏效:

 <Button x:Name="button1" Width="{Binding Source=Self Path=ButtonWidth}"/> <Button x:Name="button1" Width="{Binding RelativeSource={RelativeSource Self} Path=ButtonWidth}"/> 

等等

谢谢

首先在Binding中使用RelativeSource和Path之间的逗号:

 <Button x:Name="button1" Width="{Binding RelativeSource={RelativeSource Self}, Path=ButtonWidth}"/> 

其次,RelativeSource绑定到Button。 Button没有名为ButtonWidth的属性。 我猜你需要绑定到你的父母控制。

所以试试这个RelativeSource绑定:

 <Button x:Name="button1" Width="{Binding RelativeSource= {RelativeSource FindAncestor, AncestorType={x:Type YourNamespace:YourParentControl}}, Path=ButtonWidth}"/> 

我得到处理RelativeSource等的一种方法是命名根XAML元素:

 <Window x:Class="TestApp2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" x:Name="_this" > <Grid> <Button x:Name="button" Width="{Binding ElementName=_this,Path=ButtonWidth}" /> </Grid> </Window> 

如果你想设置DataContext你也可以这样做:

 <Window x:Class="TestApp2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" x:Name="_this" > <Grid DataContext="{Binding ElementName=_this}"> <Button x:Name="button" Width="{Binding Path=ButtonWidth}" /> </Grid> </Window> 

我觉得这是一个很好的技巧,不必记住RelativeSource绑定的所有复杂性。

我觉得你要找的是这样的:

 <Window x:Class = "blah blah all the regular stuff" DataContext="{Binding RelativeSource={RelativeSource Self}}" > 

命名XAML根元素的问题在于,如果您习惯于为项目中的所有根使用相同的名称(即“_this”,“Root”等),则在嵌套中进行后期绑定模板可能会访问错误的元素。 这是因为,当在Template使用{Binding} ElementName=...时,通过在NameScope树上向上走直到find第一个匹配,在运行时parsing名称。

Clint的解决scheme避免了命名根元素,但是它将根元素设置为它自己的DataContext ,如果数据需要DataContext ,这可能不是一个选项。 为了提供对元素的访问,为了引入另一个元素绑定也似乎有点过分。 后来,如果不再需要访问, {Binding}将变得混乱:访问的责任正确地属于目标和绑定。

因此,下面是一个简单的标记扩展来访问XAML根元素而不用命名它:

 using System.Xaml; using System.Windows.Markup; public sealed class XamlRootExtension : MarkupExtension { public override Object ProvideValue(IServiceProvider sp) { var rop = sp.GetService(typeof(IRootObjectProvider)) as IRootObjectProvider; return rop == null ? null : rop.RootObject; } }; 

XAML:

 <Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:global="clr-namespace:"> <TextBlock Text="{Binding Source={global:XamlRoot},Mode=OneTime}" /> </Window> 

结果:

在这里输入图像说明


NB

为了清楚起见,没有使用clr-namespace ,但是请注意,这里显示的XAML确实可以用于访问global名称空间(尽pipeVS2013devise者抱怨)

不幸的是,用“ElementName = ..”命名根元素似乎是UWP的唯一方法,因为{RelativeSource Self}在那里不受支持。

奇怪的是,这个名称在布局中被覆盖时仍然有效,例如

 <UserControl x:Class="Path.MyClass" x:Name="internalName"> <Border Background={Binding Path=Background, ElementName=internalName}" ... 

然后

 <Page> <local:MyClass x:Name=externalName /> </Page> 

顺便说一句,Windows 10修复了一个错误(出现在Windows 8.1),当相同的内部名称用于不同的元素在相同的布局。

不过,我宁愿使用{RelativeSource Self},因为它对我来说似乎更合乎逻辑和安全。