Bagaimana cara menggunakan binding WPF dengan RelativeSource?

Jawaban:

783

Jika Anda ingin mengikat ke properti lain di objek:

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

Jika Anda ingin mendapatkan properti pada leluhur:

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

Jika Anda ingin mendapatkan properti di induk templated (sehingga Anda dapat melakukan binding 2 arah di ControlTemplate)

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

atau, lebih pendek (ini hanya berfungsi untuk ikatan OneWay):

{TemplateBinding Path=PathToProperty}
Abe Heidebrecht
sumber
15
Untuk yang satu ini "{Binding Path = PathToProperty, RelativeSource = {RelativeSource AncestorType = {x: Ketik typeOfAncestor}}}", sepertinya perlu memiliki "Mode = FindAncestor," sebelum "AncestorType"
EdwardM
1
Untuk teknologi apa? Di WPF, itu disimpulkan ketika Anda menentukan AncestorType.
Abe Heidebrecht
2
Saya setuju dengan @EdwardM. Ketika saya menghilangkan FindAncestor, sebelumnya AncestorType, saya mendapatkan kesalahan berikut: "RelativeSource tidak dalam mode FindAncestor". (Dalam VS2013, versi Komunitas)
kmote
1
@kmote, ini telah bekerja untuk saya sejak .net 3.0, dan saya sekali lagi memverifikasi bahwa ini berfungsi seperti ini di kaxaml ... Sekali lagi, teknologi apa yang Anda gunakan? Prosesor XAML berbeda untuk WPF / Silverlight / UWP, jadi Anda mungkin memiliki hasil berbeda pada teknologi yang berbeda. Anda juga menyebutkan VS Community, jadi mungkin itu adalah peringatan IDE, tetapi berfungsi saat runtime?
Abe Heidebrecht
6
Hanya ingin untuk dicatat di sini bahwa jika Anda ingin mengikat sebuah properti di DataContext dari RelativeSource maka Anda harus secara eksplisit menentukan itu: {Binding Path=DataContext.SomeProperty, RelativeSource=.... Ini agak tak terduga bagi saya sebagai pemula ketika saya mencoba untuk mengikat DataContext orangtua dalam DataTemplate.
DrEsperanto
133
Binding RelativeSource={
    RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemType}
}
...

Atribut default RelativeSourceadalah Modeproperti. Satu set lengkap nilai valid diberikan di sini ( dari MSDN ):

  • PreviousData Memungkinkan Anda untuk mengikat item data sebelumnya (bukan kontrol yang berisi item data) dalam daftar item data yang sedang ditampilkan.

  • TemplatedParent Mengacu pada elemen yang menjadi templat (di mana elemen terikat data) diterapkan. Ini mirip dengan pengaturan TemplateBindingExtension dan hanya berlaku jika Binding ada di dalam templat.

  • Diri Mengacu pada elemen yang Anda atur pengikatannya dan memungkinkan Anda untuk mengikat satu properti elemen tersebut ke properti lain pada elemen yang sama.

  • FindAncestor Mengacu pada leluhur dalam rantai induk elemen terikat data. Anda dapat menggunakan ini untuk mengikat leluhur dari jenis tertentu atau subkelasnya. Ini adalah mode yang Anda gunakan jika Anda ingin menentukan AncestorType dan / atau AncestorLevel.

Drew Noakes
sumber
128

Berikut adalah penjelasan yang lebih visual dalam konteks arsitektur MVVM:

masukkan deskripsi gambar di sini

Jeffrey Knight
sumber
19
apakah saya melewatkan sesuatu? Bagaimana Anda bisa menganggap itu grafik yang sederhana dan jelas? 1: kotak-kotak di makna sebelah kiri tidak benar-benar terkait dengan yang di sebelah kanan (mengapa ada file .cs di dalam ViewModel?) 2: apa yang ditunjukkan oleh tanda panah DataContext ini? 3: mengapa properti Message tidak ada di ViewModel1? dan yang paling penting 5: Mengapa Anda memerlukan RelativeSource Binding untuk sampai ke WindowContext Window jika TextBlock sudah memiliki DataContext yang sama? Saya jelas kehilangan sesuatu di sini sehingga saya cukup bodoh atau grafik ini tidak sesederhana dan sejelas yang dipikirkan semua orang! Tolong beri tahu saya
Markus Hütter
2
@ MarkusHütter Diagram ini menunjukkan kepada grup tampilan bersarang dan ViewModels yang sesuai. DataContext View1 adalah ViewModel1, tetapi ia ingin mengikat ke properti BaseViewModel. Karena BaseViewModel adalah DataContext dari BaseView (yang merupakan Window), ia dapat melakukannya dengan menemukan wadah induk pertama yang merupakan Window dan mengambil DataContext-nya.
mcargille
6
@MatthewCargille Aku tahu betul apa itu seharusnya berarti, itu bukan poin saya. Tetapi tempatkan diri Anda pada posisi seseorang yang tidak mengenal XAML dan MVVM dengan baik dan Anda akan melihat bahwa ini tidak sederhana dan jelas .
Markus Hütter
1
Saya harus setuju dengan @ MarkusHütter, omong-omong, pengikatan di sebelah kiri bisa sesederhana ini: {Binding Message}(sedikit lebih sederhana ...)
florien
@ Florien Saya rasa tidak, setidaknya untuk kasus penggunaan saya. Saya memiliki DataTemplate yang perlu merujuk ke DataContext MainWindow (kelas viewmodel saya) untuk mendapatkan daftar opsi untuk menu dropdown (diambil dari database). DataTemplate terikat ke objek model yang juga diambil dari database, tetapi hanya memiliki akses ke opsi yang dipilih. Saya harus secara eksplisit mengatur Path=DataContext.Messageagar ikatannya bekerja. Ini masuk akal, mengingat bahwa Anda dapat melakukan binding relatif dengan lebar / tinggi / dll. sebuah kontrol.
DrEsperanto
47

Bechir Bejaoui memaparkan kasus penggunaan RelativeSources di WPF dalam artikelnya di sini :

RelativeSource adalah ekstensi markup yang digunakan dalam kasus-kasus pengikatan tertentu ketika kami mencoba untuk mengikat properti dari objek yang diberikan ke properti lain dari objek itu sendiri, ketika kami mencoba untuk mengikat properti dari objek ke yang lain dari orang tua relatifnya, ketika mengikat nilai properti dependensi ke sepotong XAML dalam kasus pengembangan kontrol kustom dan akhirnya dalam kasus menggunakan diferensial dari serangkaian data terikat. Semua situasi tersebut dinyatakan sebagai mode sumber relatif. Saya akan membuka semua kasus itu satu per satu.

  1. Mode Diri:

Bayangkan kasus ini, persegi panjang yang kita inginkan tingginya selalu sama dengan lebarnya, katakanlah bujur sangkar. Kita bisa melakukan ini menggunakan nama elemen

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

Tetapi dalam kasus di atas kita wajib menunjukkan nama objek yang mengikat, yaitu persegi panjang. Kita dapat mencapai tujuan yang sama secara berbeda menggunakan RelativeSource

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

Untuk kasus itu kami tidak berkewajiban untuk menyebutkan nama objek yang mengikat dan Lebar akan selalu sama dengan Ketinggian setiap kali ketinggian diubah.

Jika Anda ingin parameter Lebar menjadi setengah dari tinggi maka Anda dapat melakukan ini dengan menambahkan konverter ke ekstensi markup Binding. Mari kita bayangkan kasus lain sekarang:

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

Kasing di atas digunakan untuk mengikat properti yang diberikan dari elemen yang diberikan ke salah satu orang tua langsung sebagai elemen ini memegang properti yang disebut Parent. Ini membawa kita ke mode sumber relatif lain yang merupakan FindAncestor.

  1. Mode FindAncestor

Dalam hal ini, properti dari elemen yang diberikan akan diikat ke salah satu orang tuanya, Of Corse. Perbedaan utama dengan kasus di atas adalah kenyataan bahwa, terserah Anda untuk menentukan jenis leluhur dan peringkat leluhur dalam hierarki untuk mengikat properti. Omong-omong cobalah bermain dengan XAML ini

<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>

Situasi di atas adalah dari dua elemen TextBlock yang tertanam dalam serangkaian perbatasan dan elemen kanvas yang mewakili orang tua hierarkis mereka. TextBlock kedua akan menampilkan nama induk yang diberikan pada tingkat sumber relatif.

Jadi coba ubah AncestorLevel = 2 menjadi AncestorLevel = 1 dan lihat apa yang terjadi. Kemudian cobalah untuk mengubah jenis leluhur dari AncestorType = Border ke AncestorType = Kanvas dan lihat apa yang terjadi.

Teks yang ditampilkan akan berubah sesuai dengan jenis dan level Ancestor. Lalu apa yang terjadi jika level leluhur tidak cocok dengan tipe leluhur? Ini pertanyaan yang bagus, saya tahu Anda akan menanyakannya. Responsnya adalah tidak ada pengecualian yang akan dilemparkan dan tak berguna akan ditampilkan di tingkat TextBlock.

  1. TemplatedParent

Mode ini memungkinkan untuk mengikat properti ControlTemplate yang diberikan ke properti kontrol yang diterapkan ControlTemplate. Untuk memahami dengan baik masalah di sini adalah contoh di bawah ini

<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>

Jika saya ingin menerapkan properti dari kontrol yang diberikan ke template kontrolnya maka saya dapat menggunakan mode TemplatedParent. Ada juga yang mirip dengan ekstensi markup ini yang merupakan Templat Binding yang merupakan semacam kependekan dari yang pertama, tetapi Templat Binding dievaluasi pada waktu kompilasi pada kontras TemplatedParent yang dievaluasi tepat setelah run time pertama. Seperti yang Anda dapat katakan pada gambar di bawah, latar belakang dan konten diterapkan dari dalam tombol ke templat kontrol.

Cornel Marian
sumber
Contoh yang sangat bagus bagi saya, menggunakan Find Ancestor untuk mengikat ke sebuah perintah dalam konteks data orang tua ListView. Orang tua memiliki 2 ListViewlevel lebih di bawahnya. Ini membantu saya mencegah melewati data ke masing-masing vm berikutnya masing-masing ListView'sDataTemplate
Caleb W.
34

Dalam WPF RelativeSourcebinding memperlihatkan tiga propertiesuntuk mengatur:

1. Mode: Ini adalah enumyang bisa memiliki empat nilai:

Sebuah. PreviousData ( value=0): Ini memberikan nilai sebelumnya daripropertyyang terikat

b. TemplatedParent ( value=1): Ini digunakan ketika mendefinisikantemplateskontrol apa saja dan ingin mengikat ke nilai / Properticontrol.

Misalnya, tentukan ControlTemplate:

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

c. Self ( value=2): Ketika kita ingin mengikat dariselfataupropertydari diri.

Sebagai contoh: Kirim keadaan dicentang checkboxsebagai CommandParametersaat mengatur CommandpadaCheckBox

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

d. FindAncestor ( value=3): Saat ingin mengikat dari orang tuacontrol diVisual Tree.

Misalnya: Bind a checkboxin recordsif a grid, if header checkboxdicentang

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

2. AncestorType: ketika mode FindAncestorkemudian menentukan tipe leluhur apa

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

3. AncestorLevel: ketika modeFindAncestormaka tingkat leluhur apa (jika ada dua tipe induk yang samavisual tree)

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

Di atas semuanya ada use case RelativeSource binding.

Berikut ini tautan referensi .

Kylo Ren
sumber
2
Luar biasa .. ini bekerja untuk saya: <DataGridCheckBoxColumn Header = "Lebar Dibayar =" 35 "Binding =" {Binding RelativeSource = {Mode RelatifSource = FindAncestor, AncestorType = {x: Jenis Window}}, Path = DataContext.SelectedBuyer.IsPaid , Mode = OneWay} "/> di mana saya mencoba untuk mengikat ke pembeli yang dipilih jendela induk. PropertiPaid
Michael K
21

Jangan lupa TemplatedParent:

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

atau

{Binding RelativeSource={RelativeSource TemplatedParent}}
Bob King
sumber
16

Saya membuat perpustakaan untuk menyederhanakan sintaks WPF yang mengikat termasuk membuatnya lebih mudah untuk menggunakan RelativeSource. Berikut ini beberapa contohnya. Sebelum:

{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}

Setelah:

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

Berikut adalah contoh bagaimana metode pengikatan disederhanakan. Sebelum:

// 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}

Setelah:

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

// XAML
{BindTo SaveObject()}

Anda dapat menemukan perpustakaan di sini: http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html

Catatan dalam contoh 'SEBELUM' yang saya gunakan untuk metode yang mengikat kode itu sudah dioptimalkan dengan menggunakan RelayCommandyang terakhir saya periksa bukan bagian asli WPF. Tanpa itu contoh 'SEBELUM' akan lebih lama.

Luis Perez
sumber
2
Jenis latihan tangan seperti ini menunjukkan kelemahan XAML; cara terlalu rumit.
dudeNumber4
16

Beberapa potongan berguna:

Berikut cara melakukannya sebagian besar dalam kode:

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

Saya sebagian besar menyalin ini dari Binding Relative Source dalam kode Behind .

Juga, halaman MSDN cukup bagus sejauh contoh: RelativeSource Class

Nathan Cooper
sumber
5
Memori samar saya dari WPF adalah bahwa melakukan binding dalam kode mungkin bukan yang terbaik.
Nathan Cooper
12

Saya baru saja memposting solusi lain untuk mengakses DataContext dari elemen induk di Silverlight yang berfungsi untuk saya. Itu menggunakanBinding ElementName .

Juve
sumber
10

Saya tidak membaca setiap jawaban, tetapi saya hanya ingin menambahkan informasi ini dalam kasus pengikatan perintah sumber relatif tombol.

Saat Anda menggunakan sumber relatif dengan Mode=FindAncestor, ikatan harus seperti:

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

Jika Anda tidak menambahkan DataContext di jalur Anda, pada saat eksekusi tidak dapat mengambil properti.

Kevin VDF
sumber
9

Ini adalah contoh penggunaan pola ini yang bekerja untuk saya di datagrid kosong.

<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>
Edd
sumber
6

Jika elemen bukan bagian dari pohon visual, maka RelativeSource tidak akan pernah berfungsi.

Dalam hal ini, Anda perlu mencoba teknik yang berbeda, dipelopori oleh Thomas Levesque.

Dia memiliki solusi di blognya di bawah [WPF] Cara mengikat data ketika DataContext tidak diwarisi . Dan itu bekerja dengan sangat brilian!

Jika blognya sedang down, Lampiran A berisi salinan mirror dari artikelnya .

Tolong jangan berkomentar di sini, silakan komentar langsung di posting blog-nya .

Lampiran A: Cermin posting blog

Properti DataContext di WPF sangat berguna, karena ia secara otomatis diwarisi oleh semua anak dari elemen tempat Anda menetapkannya; karena itu Anda tidak perlu mengaturnya lagi pada setiap elemen yang ingin Anda ikat. Namun, dalam beberapa kasus, DataContext tidak dapat diakses: itu terjadi untuk elemen yang bukan bagian dari pohon visual atau logis. Maka bisa sangat sulit untuk mengikat properti pada elemen-elemen itu ...

Mari kita ilustrasikan dengan contoh sederhana: kami ingin menampilkan daftar produk di DataGrid. Di kisi, kami ingin dapat menampilkan atau menyembunyikan kolom Harga, berdasarkan nilai properti ShowPrice yang diekspos oleh ViewModel. Pendekatan yang jelas adalah untuk mengikat Visibilitas kolom ke properti ShowPrice:

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

Sayangnya, mengubah nilai ShowPrice tidak berpengaruh, dan kolom selalu terlihat ... mengapa? Jika kita melihat jendela Output di Visual Studio, kita perhatikan baris berikut:

Kesalahan System.Windows.Data: 2: Tidak dapat menemukan mengatur FrameworkElement atau FrameworkContentElement untuk elemen target. BindingExpression: Path = ShowPrice; DataItem = null; elemen target adalah 'DataGridTextColumn' (HashCode = 32685253); properti target adalah 'Visibilitas' (ketik 'Visibilitas')

Pesannya agak samar, tetapi artinya sebenarnya cukup sederhana: WPF tidak tahu FrameworkElement mana yang harus digunakan untuk mendapatkan DataContext, karena kolom itu bukan milik pohon visual atau logis dari DataGrid.

Kita dapat mencoba mengubah ikatan untuk mendapatkan hasil yang diinginkan, misalnya dengan mengatur RelativeSource ke DataGrid itu sendiri:

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

Atau kita dapat menambahkan Kotak Centang terikat ke ShowPrice, dan mencoba mengikat visibilitas kolom ke properti IsChecked dengan menentukan nama elemen:

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

Tapi tidak satu pun dari solusi ini yang berhasil, kami selalu mendapatkan hasil yang sama ...

Pada titik ini, tampaknya satu-satunya pendekatan yang dapat dilakukan adalah mengubah visibilitas kolom dalam kode-belakang, yang biasanya kita lebih suka hindari ketika menggunakan pola MVVM ... Tapi saya tidak akan menyerah begitu cepat, setidaknya tidak sementara ada opsi lain untuk dipertimbangkan 😉

Solusi untuk masalah kita sebenarnya cukup sederhana, dan memanfaatkan kelas Freezable. Tujuan utama kelas ini adalah untuk mendefinisikan objek yang memiliki keadaan yang dapat dimodifikasi dan hanya-baca, tetapi fitur yang menarik dalam kasus kami adalah bahwa objek Freezable dapat mewarisi DataContext bahkan ketika mereka tidak berada di pohon visual atau logis. Saya tidak tahu mekanisme pasti yang memungkinkan perilaku ini, tetapi kita akan memanfaatkannya untuk membuat pekerjaan mengikat kita ...

Idenya adalah untuk membuat kelas (saya menyebutnya BindingProxy untuk alasan yang harus segera menjadi jelas) yang mewarisi Freezable dan mendeklarasikan properti ketergantungan data:

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));
}

Kami kemudian dapat mendeklarasikan instance kelas ini di sumber daya DataGrid, dan mengikat properti Data ke DataContext saat ini:

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

Langkah terakhir adalah menentukan objek BindingProxy ini (mudah diakses dengan StaticResource) sebagai Sumber untuk pengikatan:

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

Perhatikan bahwa jalur pengikatan telah diawali dengan "Data", karena jalur sekarang relatif terhadap objek BindingProxy.

Pengikatan sekarang berfungsi dengan benar, dan kolom ditampilkan dengan benar atau disembunyikan berdasarkan properti ShowPrice.

Contango
sumber