【问题标题】:Binding with relative source与相对来源绑定
【发布时间】:2021-08-27 11:58:57
【问题描述】:

我正在尝试了解 RelativeSource 的工作原理。

通过下面的设置,我希望在表单上看到文本“我是 MainViewModel”,但是我在调​​试器中看到一个错误,MainWindow 上没有文本:

找不到与引用“RelativeSource FindAncestor, AncestorType='UnderstandingBindings.ViewModels.MainViewModel', AncestorLevel='1'' 的绑定源。 BindingExpression:Path=SomeProperty;数据项=空;目标元素是'TextBlock'(名称='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;
    }
}

【问题讨论】:

    标签: c# wpf xaml data-binding


    【解决方案1】:

    wpf 查找声明绑定的 xaml 元素的祖先。你可以把它想象成在视觉树上行走。

    您可以使用它绑定到该祖先上的属性,或者必须通过它的 DataContext 属性绑定到视图模型。比如:

    <TextBlock x:Name="myText" Text="{Binding DataContext.Child.SomeProperty, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>  
    

    这仅在您的示例中将 DataContext 设置为 MainViewModel 时才有效。如果您希望 Binding 朝着您期望的方向发展,那么您需要在 Child 上添加对 Parent Viewmodel 的引用。

    【讨论】:

      【解决方案2】:

      relative source within a binding 的声明执行以下操作。

      通过指定绑定源相对于绑定目标位置的位置来获取或设置绑定源。

      这意味着它将绑定的Source 属性设置为可视树中的一个元素。这可以是当前元素 (Self) 或祖先元素(例如,StackPanel 是它包含的 TextBlock 的祖先元素)或模板化父元素(如果是控件模板)。这取决于您设置的Mode。相对源允许您在绑定中指定该元素的属性路径,例如其 DataContextTag 或任何其他属性。

      您得到的错误转换为:我在可视化树中从 TextBlock 开始搜索类型为 MainViewModel 的实例。然后我检查了下一个祖先StackPanel,它不是MainViewModel。然后我检查了下一个祖先Window,它也不是MainViewModel。没有其他祖先,所以我找不到任何东西。

      您在这里滥用了相对来源。视图模型不是可视化树的一部分,而是充当元素的数据上下文。对于您使用数据上下文的示例,正​​确的方法就足够了。在 MainWindow 上设置数据上下文后,如果未另行指定,它会在所有子控件中继承,例如在元素上显式分配不同的数据上下文。因此,TextBlockMainWindow 的子对象)将获得您分配给MainWindowDataContext 属性的相同数据上下文。

      您示例中的数据上下文是ChildViewModel 的实例,因此为了绑定到它的SomeProperty,您不需要相对源绑定,只需使用DataContext 自动解析的属性路径(设置为绑定源)对应的控件。

      <TextBlock x:Name="myText" Text="{Binding SomeProperty}"/>
      

      这将导致以下文本:我是 ChildViewModel

      如果你想绑定到MainViewModelSomeProperty,你应该相应地设置DataContext

      public MainWindow()
      {
         InitializeComponent();
         this.DataContext = _viewModel;
      }
      

      TextBlock中的绑定同上,如果要显示MainViewModelSomeProperty

      <TextBlock x:Name="myText" Text="{Binding SomeProperty}"/>
      

      如果要改为绑定ChildViewModelSomeProperty,可以更改路径。

      <TextBlock x:Name="myText" Text="{Binding Child.SomeProperty}"/>
      

      在这两个示例中,它都会导致以下文本:I am the MainViewModel

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-09-05
        • 2018-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多