在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},因为它对我来说似乎更合乎逻辑和安全。