Как использовать привязки WPF с RelativeSource?

Как использовать RelativeSource с привязками WPF и каковы различные варианты использования?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
612
0
450 632
13
Перейти к ответу Данный вопрос помечен как решенный

Ответы 13

Не забывайте TemplatedParent:

<Binding RelativeSource = "{RelativeSource TemplatedParent}"/>

или же

{Binding RelativeSource = {RelativeSource TemplatedParent}}
Ответ принят как подходящий

Если вы хотите выполнить привязку к другому свойству объекта:

{Binding Path=PathToProperty, RelativeSource = {RelativeSource Self}}

Если вы хотите получить собственность на предка:

{Binding Path=PathToProperty,
    RelativeSource = {RelativeSource AncestorType = {x:Type typeOfAncestor}}}

Если вы хотите получить свойство для шаблонного родителя (чтобы вы могли делать двухсторонние привязки в ControlTemplate)

{Binding Path=PathToProperty, RelativeSource = {RelativeSource TemplatedParent}}

или, короче (это работает только для привязок OneWay):

{TemplateBinding Path=PathToProperty}

Для этого "{Binding Path = PathToProperty, RelativeSource = {RelativeSource AncestorType = {x: Type typeOfAncestor}}}", похоже, перед "AncestorType" должен быть "Mode = FindAncestor"

EdwardM 03.02.2017 00:12

Для какой технологии? В WPF это делается при указании AncestorType.

Abe Heidebrecht 08.02.2017 00:13

Я согласен с @EdwardM. Когда я опускаю FindAncestor до AncestorType, я получаю следующую ошибку: «RelativeSource не находится в режиме FindAncestor». (В VS2013, версия для сообщества)

kmote 10.04.2017 06:40

@kmote, это работает у меня с .net 3.0, и я еще раз убедился, что это работает в kaxaml ... Опять же, какую технологию вы используете? Процессор XAML отличается для WPF / Silverlight / UWP, поэтому у вас могут быть разные результаты для разных технологий. Вы также упомянули VS Community, так что, возможно, это предупреждение IDE, но работает во время выполнения?

Abe Heidebrecht 17.04.2017 23:01

Перестройка в VS Community 2018 устраняет эти (и многие другие подобные) ошибки.

will-hart 04.06.2018 12:14

Просто хотел отметить здесь, что если вы хотите привязать к свойству в DataContext RelativeSource, вы должны явно указать его: {Binding Path=DataContext.SomeProperty, RelativeSource=.... Это было несколько неожиданно для меня как новичка, когда я пытался выполнить привязку к родительскому DataContext в DataTemplate.

DrEsperanto 13.11.2018 22:04

@kmote: я получаю ту же ошибку, VS2017 с проектом WPF / .NET 4.7.1.

O. R. Mapper 17.01.2021 19:26

Binding RelativeSource = {
    RelativeSource Mode=FindAncestor, AncestorType = {x:Type ItemType}
}
...

Атрибутом RelativeSource по умолчанию является свойство Mode. Полный набор допустимых значений приведен здесь (из MSDN):

  • Предыдущие данные Позволяет вам привязать предыдущий элемент данных (не тот элемент управления, который содержит элемент данных) в списке отображаемых элементов данных.

  • TemplatedParent Относится к элементу, к которому применяется шаблон (в котором существует элемент с привязкой к данным). Это похоже на установку TemplateBindingExtension и применимо только в том случае, если привязка находится в шаблоне.

  • Себя Относится к элементу, для которого вы устанавливаете привязку, и позволяет вам привязать одно свойство этого элемента к другому свойству того же элемента.

  • FindAncestor Ссылается на предка в родительской цепочке элемента с привязкой к данным. Вы можете использовать это для привязки к предку определенного типа или его подклассов. Это режим, который вы используете, если хотите указать AncestorType и / или AncestorLevel.

Стоит отметить, что для тех, кто сталкивается с подобным мышлением о Silverlight:

Silverlight предлагает только сокращенное подмножество этих команд.

Да, я тоже искал поддержку SL. Проголосовать: connect.microsoft.com/VisualStudio/feedback/details/480603/…

TravisWhidden 18.05.2010 22:31

Я только что разместил другое решение для доступа к DataContext родительского элемента в Silverlight, который у меня работает. Он использует Binding ElementName.

Вот более наглядное объяснение в контексте архитектуры MVVM:

я что-то пропустил? Как вы можете считать это простым и понятным изображением? 1: значения полей слева на самом деле не связаны с теми, что справа (почему внутри ViewModel находится файл .cs?) 2: на что указывают эти стрелки DataContext? 3: почему свойства сообщения нет во ViewModel1? и самое главное 5. Зачем вам нужна привязка RelativeSource для доступа к DataContext окна, если TextBlock уже имеет тот же DataContext? Мне здесь явно чего-то не хватает, так что либо я довольно тупой, либо этот рисунок не такой простой и понятный, как все думают! Пожалуйста просветите меня

Markus Hütter 08.07.2016 21:09

@ MarkusHütter На диаграмме показана группа вложенных представлений и соответствующих моделей представления. DataContext View1 - это ViewModel1, но он хочет привязаться к свойству BaseViewModel. Поскольку BaseViewModel - это DataContext для BaseView (который является Window), он может сделать это, найдя первый родительский контейнер, который является Window, и взяв его DataContext.

mcargille 22.07.2016 17:37

@MatthewCargille Я очень хорошо знаю, что означает предполагаемый, я не это имел в виду. Но поставьте себя на место человека, который плохо знает XAML и MVVM, и вы увидите, что это не просто и понятно.

Markus Hütter 22.07.2016 21:36

Я должен согласиться с @ MarkusHütter, кстати, привязка слева может быть такой же простой, как это: {Binding Message} (немного проще ...)

florien 17.08.2017 19:55

@florien Я так не думаю, по крайней мере, для моего варианта использования. У меня есть DataTemplate, который должен ссылаться на DataContext MainWindow (мой класс модели просмотра), чтобы получить список параметров для раскрывающегося меню (загруженного из базы данных). DataTemplate привязан к объекту модели, который также загружается из базы данных, но имеет доступ только к выбранному параметру. Мне пришлось явно установить Path=DataContext.Message, чтобы привязка работала. Это имеет смысл, учитывая, что вы можете делать относительные привязки к ширине / высоте / и т. д. контроля.

DrEsperanto 13.11.2018 21:37

@DrEsperanto никогда не сталкивался с такой необходимостью при использовании привязок, но звучит полезно знать!

florien 13.11.2018 21:40

@florien Для привязки к DataContext? Да, это кажется очень конкретным. Большинство примеров в ответах на этот вопрос имеют дело с привязками к свойствам самих элементов управления, но если вы хотите привязать к свойству в DataContext, вы должны иметь это в пути (у Window нет свойства Message AFAIK ). Причиной моей потребности в этом было использование DataTemplate для повторяющихся записей заданного типа в моем пользовательском интерфейсе (у каждой из них много полей). В этом случае его привязка должна быть к экземпляру объекта, которому он сопоставляется, но для получения перечислений мне пришлось использовать относительную привязку.

DrEsperanto 13.11.2018 21:58

@DrEsperanto Да, я знаю это, единственное, что было для меня новым, это то, что {Binding DataContext.DataContextProperty, ElementName=...} работает, а {Binding DataContextProperty} - нет. (Я знаком с использованием модели MVVM и концепцией относительных привязок или привязок контекста данных.) Window действительно не имеет такого свойства, если я так предполагал?

florien 13.11.2018 22:11

Важная часть этого ответа, на который я тратил 10 минут, заключается в том, что вам нужен DataContext.YourProperty, поскольку относительный источник просто привязывает вас к узлу-предку (т.е. окну, сетке и т. д.).

Tomáš Zato - Reinstate Monica 11.03.2020 13:41

Я создал библиотеку, чтобы упростить синтаксис привязки WPF, в том числе упростить использование RelativeSource. Вот несколько примеров. Перед:

{Binding Path=PathToProperty, RelativeSource = {RelativeSource Self}}
{Binding Path=PathToProperty, RelativeSource = {RelativeSource AncestorType = {x:Type typeOfAncestor}}}
{Binding Path=PathToProperty, RelativeSource = {RelativeSource TemplatedParent}}
{Binding Path=Text, ElementName=MyTextBox}

После:

{BindTo PathToProperty}
{BindTo Ancestor.typeOfAncestor.PathToProperty}
{BindTo Template.PathToProperty}
{BindTo #MyTextBox.Text}

Вот пример того, как упрощается привязка метода. Перед:

// C# code
private ICommand _saveCommand;
public ICommand SaveCommand {
 get {
  if (_saveCommand == null) {
   _saveCommand = new RelayCommand(x => this.SaveObject());
  }
  return _saveCommand;
 }
}

private void SaveObject() {
 // do something
}

// XAML
{Binding Path=SaveCommand}

После:

// C# code
private void SaveObject() {
 // do something
}

// XAML
{BindTo SaveObject()}

Вы можете найти библиотеку здесь: http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html

Обратите внимание, что в примере «BEFORE», который я использую для привязки метода, код уже был оптимизирован с помощью RelayCommand, который я проверял в последний раз, не является собственной частью WPF. Без этого пример «ДО» был бы еще длиннее.

Подобные упражнения демонстрируют слабость XAML; путь слишком сложно.

dudeNumber4 04.01.2017 17:37

Некоторые полезные кусочки:

Вот как это сделать в основном в коде:

Binding b = new Binding();
b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, this.GetType(), 1);
b.Path = new PropertyPath("MyElementThatNeedsBinding");
MyLabel.SetBinding(ContentProperty, b);

Я в значительной степени скопировал это из Привязка относительного источника в коде позади.

Кроме того, страница MSDN довольно хороша в плане примеров: RelativeSource Класс

Мое смутное воспоминание о WPF заключается в том, что выполнение привязок в коде, вероятно, обычно не самое лучшее.

Nathan Cooper 22.03.2017 22:58

Бечир Бежауи раскрывает варианты использования RelativeSources в WPF в его статья здесь:

The RelativeSource is a markup extension that is used in particular binding cases when we try to bind a property of a given object to another property of the object itself, when we try to bind a property of a object to another one of its relative parents, when binding a dependency property value to a piece of XAML in case of custom control development and finally in case of using a differential of a series of a bound data. All of those situations are expressed as relative source modes. I will expose all of those cases one by one.

  1. Mode Self:

Imagine this case, a rectangle that we want that its height is always equal to its width, a square let's say. We can do this using the element name

<Rectangle Fill = "Red" Name = "rectangle" 
                Height = "100" Stroke = "Black" 
                Canvas.Top = "100" Canvas.Left = "100"
                Width = "{Binding ElementName=rectangle,
                Path=Height}"/>

But in this above case we are obliged to indicate the name of the binding object, namely the rectangle. We can reach the same purpose differently using the RelativeSource

<Rectangle Fill = "Red" Height = "100" 
               Stroke = "Black" 
               Width = "{Binding RelativeSource = {RelativeSource Self},
               Path=Height}"/>

For that case we are not obliged to mention the name of the binding object and the Width will be always equal to the Height whenever the height is changed.

If you want to parameter the Width to be the half of the height then you can do this by adding a converter to the Binding markup extension. Let's imagine another case now:

 <TextBlock Width = "{Binding RelativeSource = {RelativeSource Self},
               Path=Parent.ActualWidth}"/>

The above case is used to tie a given property of a given element to one of its direct parent ones as this element holds a property that is called Parent. This leads us to another relative source mode which is the FindAncestor one.

  1. Mode FindAncestor

In this case, a property of a given element will be tied to one of its parents, Of Corse. The main difference with the above case is the fact that, it's up to you to determine the ancestor type and the ancestor rank in the hierarchy to tie the property. By the way try to play with this piece of XAML

<Canvas Name = "Parent0">
    <Border Name = "Parent1"
             Width = "{Binding RelativeSource = {RelativeSource Self},
             Path=Parent.ActualWidth}"
             Height = "{Binding RelativeSource = {RelativeSource Self},
             Path=Parent.ActualHeight}">
        <Canvas Name = "Parent2">
            <Border Name = "Parent3"
            Width = "{Binding RelativeSource = {RelativeSource Self},
           Path=Parent.ActualWidth}"
           Height = "{Binding RelativeSource = {RelativeSource Self},
              Path=Parent.ActualHeight}">
               <Canvas Name = "Parent4">
               <TextBlock FontSize = "16" 
               Margin = "5" Text = "Display the name of the ancestor"/>
               <TextBlock FontSize = "16" 
                 Margin = "50" 
            Text = "{Binding RelativeSource = {RelativeSource  
                       FindAncestor,
                       AncestorType = {x:Type Border}, 
                       AncestorLevel=2},Path=Name}" 
                       Width = "200"/>
                </Canvas>
            </Border>
        </Canvas>
     </Border>
   </Canvas>

The above situation is of two TextBlock elements those are embedded within a series of borders and canvas elements those represent their hierarchical parents. The second TextBlock will display the name of the given parent at the relative source level.

So try to change AncestorLevel=2 to AncestorLevel=1 and see what happens. Then try to change the type of the ancestor from AncestorType=Border to AncestorType=Canvas and see what's happens.

The displayed text will change according to the Ancestor type and level. Then what's happen if the ancestor level is not suitable to the ancestor type? This is a good question, I know that you're about to ask it. The response is no exceptions will be thrown and nothings will be displayed at the TextBlock level.

  1. TemplatedParent

This mode enables tie a given ControlTemplate property to a property of the control that the ControlTemplate is applied to. To well understand the issue here is an example bellow

<Window.Resources>
<ControlTemplate x:Key = "template">
        <Canvas>
            <Canvas.RenderTransform>
                <RotateTransform Angle = "20"/>
                </Canvas.RenderTransform>
            <Ellipse Height = "100" Width = "150" 
                 Fill = "{Binding 
            RelativeSource = {RelativeSource TemplatedParent},
            Path=Background}">

              </Ellipse>
            <ContentPresenter Margin = "35" 
                  Content = "{Binding RelativeSource = {RelativeSource  
                  TemplatedParent},Path=Content}"/>
        </Canvas>
    </ControlTemplate>
</Window.Resources>
    <Canvas Name = "Parent0">
    <Button   Margin = "50" 
              Template = "{StaticResource template}" Height = "0" 
              Canvas.Left = "0" Canvas.Top = "0" Width = "0">
        <TextBlock FontSize = "22">Click me</TextBlock>
    </Button>
 </Canvas>

If I want to apply the properties of a given control to its control template then I can use the TemplatedParent mode. There is also a similar one to this markup extension which is the TemplateBinding which is a kind of short hand of the first one, but the TemplateBinding is evaluated at compile time at the contrast of the TemplatedParent which is evaluated just after the first run time. As you can remark in the bellow figure, the background and the content are applied from within the button to the control template.

Для меня очень хорошие примеры, когда я использовал Find Ancestor для привязки к команде в контексте данных родительского ListView. У родителя есть еще 2 уровня ListView ниже. Это помогло мне предотвратить передачу данных в каждую последующую виртуальную машину каждого ListViewDataTemplate.

Caleb W. 07.05.2020 01:14

Это пример использования этого шаблона, который работал у меня на пустых таблицах данных.

<Style.Triggers>
    <DataTrigger Binding = "{Binding Items.Count, RelativeSource = {RelativeSource Self}}" Value = "0">
        <Setter Property = "Background">
            <Setter.Value>
                <VisualBrush Stretch = "None">
                    <VisualBrush.Visual>
                        <TextBlock Text = "We did't find any matching records for your search..." FontSize = "16" FontWeight = "SemiBold" Foreground = "LightCoral"/>
                    </VisualBrush.Visual>
                </VisualBrush>
            </Setter.Value>
        </Setter>
    </DataTrigger>
</Style.Triggers>

В WPF привязка RelativeSource предоставляет три properties для установки:

1. Режим: Это enum, который может иметь четыре значения:

a. PreviousData(value=0): It assigns the previous value of the property to the bound one

b. TemplatedParent(value=1): This is used when defining the templates of any control and want to bind to a value/Property of the control.

For example, define ControlTemplate:

  <ControlTemplate>
        <CheckBox IsChecked = "{Binding RelativeSource = {RelativeSource TemplatedParent}, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
 </ControlTemplate>

c. Self(value=2): When we want to bind from a self or a property of self.

For example: Send checked state of checkbox as CommandParameter while setting the Command on CheckBox

<CheckBox ...... CommandParameter = "{Binding RelativeSource = {RelativeSource Self},Path=IsChecked}" />

d. FindAncestor(value=3): When want to bind from a parent control in Visual Tree.

For example: Bind a checkbox in records if a grid,if headercheckbox is checked

<CheckBox IsChecked = "{Binding RelativeSource = {RelativeSource Mode=FindAncestor, AncestorType = {x:Type iDP:XamDataGrid}}, Path=DataContext.IsHeaderChecked, Mode=TwoWay}" />

2. AncestorType:, когда режим FindAncestor, тогда определите, какой тип предка

RelativeSource = {RelativeSource Mode=FindAncestor, AncestorType = {x:Type iDP:XamDataGrid}}

3. AncestorLevel:, когда режим FindAncestor, то какой уровень предка (если в visual tree есть два родителя одного и того же типа)

RelativeSource = {RelativeSource Mode=FindAncestor, AncestorType = {x:Type iDP:XamDataGrid, AncestorLevel=1}}

Above are all use-cases for RelativeSource binding.

Вот справочная ссылка.

Потрясающе .. это сработало для меня: <DataGridCheckBoxColumn Header = "Paid" Width = "35" Binding = "{Binding RelativeSource = {RelativeSource Mode = FindAncestor, AncestorType = {x: Type Window}}, Path = DataContext.SelectedBuyer.IsPaid , Mode = OneWay} "/> где я пытался выполнить привязку к свойству selectedbuyer.IsPaid родительского окна.

Michael K 25.10.2018 03:21

Я не читал все ответы, но я просто хочу добавить эту информацию в случае привязки команды относительного источника к кнопке.

Когда вы используете относительный источник с Mode=FindAncestor, привязка должна быть такой:

Command = "{Binding Path=DataContext.CommandProperty, RelativeSource = {...}}"

Если вы не добавите DataContext в свой путь, во время выполнения он не сможет получить свойство.

Если элемент не является частью визуального дерева, RelativeSource никогда не будет работать.

В этом случае вам нужно попробовать другую технику, разработанную Томасом Левеском.

У него есть решение в его блоге под [WPF] Как выполнить привязку к данным, когда DataContext не наследуется. И работает абсолютно гениально!

В том маловероятном случае, если его блог не работает, Приложение A содержит зеркальную копию его статья.

Пожалуйста, не комментируйте здесь, пожалуйста прокомментируйте его сообщение в блоге.

Приложение A. Зеркало сообщения в блоге

Свойство DataContext в WPF чрезвычайно удобно, поскольку оно автоматически наследуется всеми дочерними элементами элемента, которому вы его назначаете; поэтому вам не нужно повторно устанавливать его для каждого элемента, который вы хотите привязать. Однако в некоторых случаях DataContext недоступен: это происходит для элементов, которые не являются частью визуального или логического дерева. Тогда может быть очень сложно привязать свойство к этим элементам ...

Давайте проиллюстрируем это на простом примере: мы хотим отобразить список продуктов в DataGrid. В сетке мы хотим иметь возможность отображать или скрывать столбец Price в зависимости от значения свойства ShowPrice, предоставляемого ViewModel. Очевидный подход - привязать видимость столбца к свойству ShowPrice:

<DataGridTextColumn Header = "Price" Binding = "{Binding Price}" IsReadOnly = "False"
                Visibility = "{Binding ShowPrice,
                Converter = {StaticResource visibilityConverter}}"/>

К сожалению, изменение значения ShowPrice не имеет никакого эффекта, и столбец всегда виден… почему? Если мы посмотрим на окно вывода в Visual Studio, мы заметим следующую строку:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=ShowPrice; DataItem=null; target element is ‘DataGridTextColumn’ (HashCode=32685253); target property is ‘Visibility’ (type ‘Visibility’)

The message is rather cryptic, but the meaning is actually quite simple: WPF doesn’t know which FrameworkElement to use to get the DataContext, because the column doesn’t belong to the visual or logical tree of the DataGrid.

Мы можем попытаться настроить привязку, чтобы получить желаемый результат, например, установив RelativeSource на сам DataGrid:

<DataGridTextColumn Header = "Price" Binding = "{Binding Price}" IsReadOnly = "False"
                Visibility = "{Binding DataContext.ShowPrice,
                Converter = {StaticResource visibilityConverter},
                RelativeSource = {RelativeSource FindAncestor, AncestorType=DataGrid}}"/>

Или мы можем добавить CheckBox, привязанный к ShowPrice, и попытаться привязать видимость столбца к свойству IsChecked, указав имя элемента:

<DataGridTextColumn Header = "Price" Binding = "{Binding Price}" IsReadOnly = "False"
                Visibility = "{Binding IsChecked,
                Converter = {StaticResource visibilityConverter},
                ElementName=chkShowPrice}"/>

Но, похоже, ни один из этих обходных путей не работает, мы всегда получаем один и тот же результат ...

На данный момент кажется, что единственным жизнеспособным подходом было бы изменить видимость столбцов в коде программной части, чего мы обычно предпочитаем избегать при использовании шаблона MVVM ... Но я не собираюсь сдаваться так скоро, по крайней мере, не пока есть другие варианты, которые стоит рассмотреть ?

Решение нашей проблемы на самом деле довольно простое и использует класс Freezable. Основная цель этого класса - определить объекты, которые имеют изменяемое состояние и состояние только для чтения, но интересная особенность в нашем случае заключается в том, что объекты Freezable могут наследовать DataContext, даже если они не находятся в визуальном или логическом дереве. Я не знаю точного механизма, который обеспечивает такое поведение, но мы собираемся воспользоваться этим, чтобы заставить нашу привязку работать ...

Идея состоит в том, чтобы создать класс (я назвал его BindingProxy по причинам, которые вскоре должны стать очевидными), который наследует Freezable и объявляет свойство зависимости данных:

public class BindingProxy : Freezable
{
    #region Overrides of Freezable
 
    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }
 
    #endregion
 
    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }
 
    // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}

Затем мы можем объявить экземпляр этого класса в ресурсах DataGrid и привязать свойство Data к текущему DataContext:

<DataGrid.Resources>
    <local:BindingProxy x:Key = "proxy" Data = "{Binding}" />
</DataGrid.Resources>

Последний шаг - указать этот объект BindingProxy (легко доступный с помощью StaticResource) в качестве источника для привязки:

<DataGridTextColumn Header = "Price" Binding = "{Binding Price}" IsReadOnly = "False"
                Visibility = "{Binding Data.ShowPrice,
                Converter = {StaticResource visibilityConverter},
                Source = {StaticResource proxy}}"/>

Обратите внимание, что путь привязки имеет префикс «Data», поскольку теперь путь указывается относительно объекта BindingProxy.

Привязка теперь работает правильно, и столбец правильно отображается или скрывается в зависимости от свойства ShowPrice.

Другие вопросы по теме