我正在尝试了解 RelativeSource
的工作原理。
通过下面的设置,我希望在表单上看到“I am the MainViewModel”文本,但是我在调试器中看到一个错误,MainWindow
上没有任何文本:
无法找到引用“RelativeSource FindAncestor, AncestorType='UnderstandingBindings.ViewModels.MainViewModel', AncestorLevel='1''的绑定源。 BindingExpression:Path=SomeProperty;数据项=空;目标元素是 'TextBlock' (Name='myText');目标属性是“文本”(类型“字符串”)
我有一个这样的 ViewModel:
class MainViewModel
{
public string SomeProperty { get => "I am the MainViewModel"; }
private readonly ChildViewModel _child = new ChildViewModel();
public ChildViewModel Child => _child;
}
class ChildViewModel
{
public string SomeProperty { get => "I am the ChildViewModel"; }
}
MainWindow XAML 看起来像:
<Window x:Class="UnderstandingBindings.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:UnderstandingBindings.Views"
xmlns:vm="clr-namespace:UnderstandingBindings.ViewModels"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel x:Name="pnlMain">
<TextBlock x:Name="myText" Text="{Binding SomeProperty, RelativeSource={RelativeSource AncestorType={x:Type vm:MainViewModel}}}"/>
</StackPanel>
</Window>
数据上下文是这样分配的:
public partial class MainWindow : Window
{
private readonly MainViewModel _viewModel = new MainViewModel();
public MainWindow()
{
InitializeComponent();
this.DataContext = _viewModel.Child;
}
}
答案 0 :(得分:0)
wpf 查找声明绑定的 xaml 元素的祖先。您可以将其视为走上可视化树。
您将使用它绑定到该祖先上的属性,或者必须通过它的 DataContext 属性绑定到视图模型。例如:
<TextBlock x:Name="myText" Text="{Binding DataContext.Child.SomeProperty, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
这仅在您的示例中将 DataContext 设置为 MainViewModel 时才有效。如果您希望 Binding 朝着您预期的方向发展,那么您需要在 Child 上添加对 Parent Viewmodel 的引用。
答案 1 :(得分:0)
relative source within a binding 的声明执行以下操作。
<块引用>通过指定绑定源相对于绑定目标位置的位置来获取或设置绑定源。
这意味着它将绑定的 Source
属性设置为可视化树中的一个元素。这可以是当前元素 (Self
) 或祖先(例如,StackPanel
是它包含的 TextBlock
的祖先)或在控件模板的情况下模板化的父元素。这取决于您设置的 Mode
。相对源允许您在绑定中指定该元素的属性路径,例如其 DataContext
或 Tag
或任何其他属性。
您得到的错误转化为:我在从 MainViewModel
开始的可视化树中搜索了类型为 TextBlock
的实例。然后我检查了下一个祖先 StackPanel
,它不是 MainViewModel
。然后我检查了下一个祖先 Window
,它也不是 MainViewModel
。没有其他祖先,所以我找不到任何东西。
您在这里滥用了相对来源。视图模型不是可视化树的一部分,而是充当元素的数据上下文。对于您使用数据上下文的示例,正确的方法就足够了。一旦您在 MainWindow
上设置了数据上下文,它就会在所有子控件中继承,如果没有另外指定,例如在元素上显式分配不同的数据上下文。因此,作为 TextBlock
的子代的 MainWindow
将获得与您分配给 DataContext
的 MainWindow
属性相同的数据上下文。
示例中的数据上下文是 ChildViewModel
的一个实例,因此为了绑定到它的 SomeProperty
,您不需要相对源绑定,只需要使用自动解析的属性路径对应控件的DataContext
(设置为绑定源)。
<TextBlock x:Name="myText" Text="{Binding SomeProperty}"/>
这将导致以下文本:我是 ChildViewModel
如果您想绑定到 SomeProperty
的 MainViewModel
,您应该相应地设置 DataContext
。
public MainWindow()
{
InitializeComponent();
this.DataContext = _viewModel;
}
TextBlock
中的绑定和上面一样,如果你想显示 SomeProperty
的 MainViewModel
。
<TextBlock x:Name="myText" Text="{Binding SomeProperty}"/>
如果您想绑定 SomeProperty
的 ChildViewModel
,您可以更改路径。
<TextBlock x:Name="myText" Text="{Binding Child.SomeProperty}"/>
在这两个示例中,它将导致以下文本:I am the MainViewModel