2018-06-13 (水)
[WPF] C#でDataGridColumnのHeaderとVisibilityをバインドする例
DataTable
をDataGrid
にAutoGeneratingColumn
で自動作成させたケースで、列のヘッダー名と非表示の設定をバインドで制御する例です。
環境
- Windows 10 Pro 64bit 1709
- Visual Studio Community 2017 15.7.3
- .NET Framework 4.6.1
- C# 7.0
結果
初期表示の状態
ボタンをクリック後
実装
このDictionary
を使用してバインドします。Key
はColumnName
です。
// ColumnHeaderの表示文言
public Dictionary<string, string> ColumnHeader { get; }
// Columnの表示/非表示
public Dictionary<string, BindableValue<Visibility>> ColumnVisibility { get; }
通常のDictionary<string, string>
ではValue
を更新した際に、明示的にINotifyPropertyChanged
を通知してあげる必要があります。Dictionary<string, BindableValue<T>>
を使用する方法であれば通知は不要ですが、BindableValue<T>
のインスタンスが必要になります。
BindableBase.cs
この基底クラスを使用しています。
[C#] INotifyPropertyChangedを楽に実装し、ReSharperのTemplateも作る
BindableValue.cs (Model)
namespace WpfDataGridStudy
{
public class BindableValue<T> : BindableBase
{
public T Value
{
get => _value;
set => SetProperty(ref _value, value);
}
private T _value;
public BindableValue()
{
}
public BindableValue(T value)
{
Value = Value;
}
}
public static class BindableValue
{
public static BindableValue<T> Create<T>(T value) => new BindableValue<T>(value);
}
}
ViewModel.cs (ViewModel)
using System.Collections.Generic;
using System.Data;
using System.Windows;
namespace WpfDataGridStudy
{
public class ViewModel : BindableBase
{
public DataTable Table { get; } = new DataTable();
public Dictionary<string, string> ColumnHeader { get; } = new Dictionary<string, string>();
public Dictionary<string, BindableValue<Visibility>> ColumnVisibility { get; } = new Dictionary<string, BindableValue<Visibility>>();
public ViewModel()
{
// DataTableなデータを取得したとする
Table.Columns.Add("A");
Table.Columns.Add("B");
Table.Columns.Add("C");
for (int i = 0; i < 10; i++)
{
Table.Rows.Add($"A-{i}", $"B-{i}", $"C-{i}");
}
// DataTableと同じColumnNameをキーとして作成
foreach (DataColumn column in Table.Columns)
{
ColumnHeader.Add(column.ColumnName, $"{column.ColumnName}列ですよ");
ColumnVisibility.Add(column.ColumnName, BindableValue.Create(Visibility.Visible));
}
}
public void SetHeader()
{
ColumnHeader["A"] = "A列のヘッダー変更したよ";
// A列しか変更していないが、Dictionary全体として通知する必要がある
OnPropertyChanged(nameof(ColumnHeader));
}
public void SetVisible()
{
ColumnVisibility["B"].Value = Visibility.Collapsed;
}
}
}
MainWindow.xaml (View)
<Window x:Class="WpfDataGridStudy.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:WpfDataGridStudy"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
d:DataContext="{d:DesignInstance {x:Type local:ViewModel}}">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<StackPanel>
<Button Content="バインドにより、A列ヘッダーを変更して、B列を非表示に変更します"
Click="Button_OnClick"/>
<DataGrid IsReadOnly="True"
ItemsSource="{Binding Table}"
AutoGeneratingColumn="DataGrid_OnAutoGeneratingColumn"/>
</StackPanel>
</Window>
MainWindow.xaml.cs (Viewのコードビハインド)
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfDataGridStudy
{
public partial class MainWindow : Window
{
private readonly ViewModel _viewModel;
public MainWindow()
{
InitializeComponent();
_viewModel = (ViewModel)DataContext;
}
private void DataGrid_OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
// Dictionary<string, string> ColumnHeader とバインド
BindingOperations.SetBinding(e.Column,
DataGridColumn.HeaderProperty,
new Binding($"{nameof(ViewModel.ColumnHeader)}[{e.PropertyName}]")
{
Source = _viewModel
});
// Dictionary<string, BindableValue<Visibility>> ColumnVisibility とバインド
BindingOperations.SetBinding(e.Column,
DataGridColumn.VisibilityProperty,
new Binding($"{nameof(ViewModel.ColumnVisibility)}[{e.PropertyName}].{nameof(BindableValue<Visibility>.Value)}")
{
Source = _viewModel
});
}
private void Button_OnClick(object sender, RoutedEventArgs e)
{
_viewModel.SetHeader();
_viewModel.SetVisible();
}
}
}
感謝
関連記事
新着記事