Что именно делает "RelativeSource FindAncestor" WPF Data Binding?

В настоящее время я работаю в пользовательском элементе управления WPF (корневым элементом моего файла XAML является "UserControl"), который, как я знаю, размещается в окне. Как я могу получить доступ к свойству окна, используя привязку данных?

Кто-нибудь знает почему просто

<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type Window}}" Path="..." />

не работает? Я получаю сообщение об ошибке:

Предупреждение System.Windows.Data: 4: Не удается найти источник для привязки со ссылкой 'RelativeSource FindAncestor, AncestorType='System.Windows.Window', AncestorLevel='1''.

Изменить: я в конечном итоге использовал вариант подхода ArsenMkrt, поэтому принял его ответ. Тем не менее, мне все еще интересно выяснить, почему FindAncestor не "просто работает".

3 ответа

Решение

Лучший способ - дать имя UserControl

Создайте свойство зависимостей MyProperty в UserControl с двухсторонним связыванием и привяжите его в главном окне, чем связать в UserControl следующим образом

<UserControl x:Name = "myControl">
     <Label Content={Binding ElementName= myControl, Path=MyProperty}/>
</UserControl>

Если вы пытаетесь "сбежать" от ItemsControl или же DataGridView чтобы добраться до Window вы можете обнаружить, что AncestorType x:Type Window не работает Или, по крайней мере, не кажется...

В этом случае вы, вероятно, используете Blend или Visual Studio и ожидаете, что данные будут видны во время разработки, чего не будет, потому что VS + Blend создает свои собственные экземпляры, которые на самом деле не являются Windows. Он будет хорошо работать во время выполнения, но не в режиме разработки.

Есть пара вещей, которые вы можете сделать:

  • Завернуть в UserControl

  • Вот альтернативное решение, которое я придумала. Это имеет одно преимущество в том, что вы не ссылаетесь на UserControl или же Window напрямую, поэтому если вы измените родительский контейнер, ваш код не сломается.

    <Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:views="clr-namespace:MyWPFApplication.Views"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"                  
    x:Class="MyWPFApplication.Views.UPCLabelPrinterWindow"
    mc:Ignorable="d"
    x:Name="LayoutRoot"
    Title="UPCLabelPrinterWindow">
    
    <views:DataContextWrapper>
        <DockPanel>
            ...
        </DockPanel>
    </views:DataContextWrapper>
    

куда DataContextWrapper это просто сетка

namespace MyWPFApplication.Views {
   public class DataContextWrapper : Grid
   {

   }
}

Затем, когда вы связываете, вы делаете это:

<TextBlock Text="{Binding="{Binding DataContext.SomeText, 
  RelativeSource={RelativeSource AncestorType={x:Type views:DataContextWrapper}, 
  Mode=FindAncestor}}" />

Примечание: если вы хотите привязать свойство к самому окну, это сложнее, и вам, вероятно, следует выполнить привязку через свойство зависимости или что-то в этом роде. Но если вы используете MVVM, то это единственное решение, которое я нашел.

Если вы используете модель представления в качестве DataContext вашего окна, а свойство, к которому вам нужно привязаться, относится к этой модели представления, тогда вы должны префикс пути с DataContext.MyPropertyPath, примерно так:

<TextBox Text="{Binding DataContext.MyProperty, RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}"/>

это переводится как "Найдите мне окно предка, а затем посмотрите в его контексте данных на MyProperty".

Я думаю, что вы должны SET Mode="OneWayToSource" Вот так:

<TextBox Text="{Binding RelativeSource={RelativeSource FindAncestor ,AncestorType={x:Type Grid}},Path=BackGround , Mode=OneWayToSource , UpdateSourceTrigger = PropertyChanged}" />
Другие вопросы по тегам