C# | WPF Prism DataGrid Column Visibility Binding

How to bind a DataGrid column's Visibility in C# WPF Prism

TechPublished 2 min read

I'll explain how to bind the Visibility of a DataGrid column using WPF Prism in C#.

For example, when data-binding a combo box (or its options) to a column inside a DataGrid, using RelativeSource FindAncestor is one approach you might consider.
However, when data-binding to a DataGrid column's Visibility, the RelativeSource approach doesn't work.

So, we handle it by creating a class that lets us reference the ViewModel.

Target Files (Example)

The files you need to code are A through C below.

WPF/
 |-Services/
 |  |-BindingProxy.cs ・・・A
 |
 |-Views/
 |  |-SampleView.xaml ・・・B  
 |
 |-ViewModels/
 |  |-SampleViewModel.cs ・・・C  

BindingProxy.cs ・・・A

Normally, when you use ItemsSource, each element of the bound collection becomes the DataContext, so inside a DataGrid you can't bind to anything other than ItemsSource.

※DataContext: the target of a Binding

To work around this, we prepare a "BindingProxy" class that lets controls inside the DataGrid access the ViewModel's properties directly.

▼BindingProxy.cs

using System.Windows;

namespace Template2.WPF.Services
{
    /// <summary>
    /// ViewModelのバインディングソースの代理として働くクラスです。
    /// </summary>
    public class BindingProxy : Freezable
    {
        /// <summary>
        /// Freezableオブジェクトのインスタンスを生成します。
        /// </summary>
        /// <returns></returns>
        protected override Freezable CreateInstanceCore()
        {
            return new BindingProxy();
        }

        /// <summary>
        /// 間をとりもつプロパティ
        /// データバインドした場合は、このプロパティがViewModelの代わりになる。
        /// </summary>
        public object Data
        {
            get { return (object)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }

        /// <summary>
        /// Data の依存関係プロパティ定義
        /// </summary>
        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
    }
}

SampleView.xaml ・・・B

①Add a reference to the local class in the View's xaml

Add a namespace reference to the BindingProxy class on the Window or UserControl element.

Example: if the namespace of BindingProxy.cs is Template2.WPF.Services
xmlns:services="clr-namespace:Template2.WPF.Services"

▼SampleView.xaml

<UserControl x:Class="Template2.WPF.Views.Sample002View"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/"             
             prism:ViewModelLocator.AutoWireViewModel="True"
             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
             Background="{StaticResource backgroundColor}"
             xmlns:services="clr-namespace:Template2.WPF.Services"
             >

②Add a BindingProxy reference to the DataGrid's resources

Add the code below to make BindingProxy usable inside the DataGrid.

<DataGrid.Resources>
    <!--DataGridのItemSourceとは別のアイテムをBindするために必要-->
    <services:BindingProxy x:Key="Proxy" Data="{Binding}"/>
</DataGrid.Resources>

Example: incorporating it into a DataGrid

▼SampleView.xaml

<DataGrid Style="{StaticResource commonDataGrid}"
          ItemsSource="{Binding WorkerMstEntities}"
          SelectedItem="{Binding WorkerMstEntitiesSlectedItem}"
          VerticalAlignment="Top"
          HorizontalAlignment="Left"
          IsReadOnly="False"
          CanUserAddRows="False"
          Cursor="Hand">

                <DataGrid.Resources>
                    <!--DataGridのItemSourceとは別のアイテムをBindするために必要-->
                    <services:BindingProxy x:Key="Proxy" Data="{Binding}"/>
                </DataGrid.Resources>

                (省略)

③Bind the DataGrid column's Visibility

Add Visibility to the DataGrid's Column element.

Key points

  • Write Binding: Data.XXX
  • Write Source: StaticResource

▼SampleView.xaml

<DataGrid.Columns>
    <!-- カラムのVisibilityは、BindingProxyクラスを利用してViewModelのプロパティを参照する必要有り -->
    <materialDesign:DataGridTextColumn Header="作業者名称"
           Binding="{Binding WorkerName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
           Visibility="{Binding Data.WorkerNameVisibility, Source={StaticResource Proxy}}">

    (省略)

SampleViewModel.cs ・・・C

④Prepare a property on the ViewModel for the Visibility binding

Just like the usual way of data-binding a property in WPF Prism, add a property (and its backing private field) whose name matches what Visibility is bound to.

▼SampleViewModel.cs

private Visibility _workerNameVisibility = Visibility.Visible;
public Visibility WorkerNameVisibility
{
    get { return _workerNameVisibility; }
    set { SetProperty(ref _workerNameVisibility, value); }
}

That's it.