简单的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}"/>
等
由于
答案 0 :(得分:76)
首先在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}"/>
答案 1 :(得分:29)
我必须处理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绑定的所有复杂性。
答案 2 :(得分:29)
我认为你在寻找的是:
<Window x:Class = "blah blah all the regular stuff"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
>
答案 3 :(得分:4)
问题with naming the XAML
root element是,如果你养成了对项目中所有根使用相同名称(即“_this”,“Root”等)的习惯,那么后期绑定在嵌套模板中可能会访问错误的元素。这是因为,在{Binding}
中使用ElementName=...
Template
时,会在运行时通过向上走NameScope
树来解析名称,直到找到第一个匹配项。
Clint's solution避免命名根元素,但它将根元素设置为自己的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>
note :为清楚起见,我没有在命名空间中定义MarkupExtension
;使用如此处所示的空clr-namespace
别名确实实际上用于访问global::
命名空间(尽管VS2013设计师似乎抱怨它)。
<强>结果强>:
一个内容与自身绑定的窗口。
<强> n.b。强>
答案 4 :(得分:0)
不幸的是,使用&#34; ElementName = ..&#34;命名根元素。似乎是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>
BTW,Windows 10修复了一个错误(存在于Windows 8.1中),当相同的内部名称用于同一布局中的不同元素时。
不过,我更喜欢使用{RelativeSource Self},因为它对我来说更合乎逻辑,更安全。