まえがき
WPFでDataGridの中にコンボボックスを入れて、選んだ要素をstring変数にバインドで入れたいことは多々(?)あると思います。
その際に自分が想定した動きができず詰まってしまいましたが解決できたので、忘れないように覚え書きしたものがこの記事です。
想定した動き
実現したい動きとしましてはコンボボックスとTextを並べて、コンボボックスの要素が変更するとTextの値が変化するといったものです。またこの動きをDataGrid内でも行いたいと考えています。
ChatGPT先生に聞いてみたところ下記のようなコードを教えてくれました。
<Window
x:Class="ComboBoxValue.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:local="clr-namespace:ComboBoxValue"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" LastChildFill="false">
<ComboBox
Width="120"
ItemsSource="{Binding TypePattern}"
SelectedIndex="0"
SelectedItem="{Binding Type}" />
<TextBlock
Width="120"
Text="{Binding Type}"
TextWrapping="Wrap" />
</DockPanel>
<DataGrid
Grid.Row="1"
AutoGenerateColumns="False"
CanUserAddRows="False"
CanUserSortColumns="False"
HeadersVisibility="Column"
ItemsSource="{Binding DataGrids}"
SelectionMode="Single">
<DataGrid.Columns>
<DataGridTextColumn
Width="*"
Binding="{Binding Type}"
Header="タイプ" />
<DataGridTemplateColumn Width="*" Header="タイプ">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox
ItemsSource="{Binding TypePattern}"
SelectedIndex="0"
SelectedItem="{Binding Type}" />
<TextBlock Text="{Binding Type}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
using System.Collections.Generic;
using System.ComponentModel;
namespace ComboBoxValue
{
class MainViewModel : INotifyPropertyChanged
{
private List<DataGrid> _DataGrids = new List<DataGrid>() { new DataGrid(), new DataGrid() };
public List<DataGrid> DataGrids
{
get { return _DataGrids; }
set
{
if (value != _DataGrids)
{
_DataGrids = value;
OnPropertyChanged(nameof(DataGrids));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private List<string> _typePattern = new List<string>() { "1", "2", "3", "4", "5" };
public List<string> TypePattern
{
get { return _typePattern; }
set
{
_typePattern = value;
OnPropertyChanged(nameof(TypePattern));
}
}
private string _type = "10";
public string Type
{
get { return _type; }
set
{
if (value != _type)
{
_type = value;
OnPropertyChanged(nameof(Type));
}
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class DataGrid : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private List<string> _typePattern = new List<string>() { "1", "2", "3", "4", "5" };
public List<string> TypePattern
{
get { return _typePattern; }
set
{
_typePattern = value;
OnPropertyChanged(nameof(TypePattern));
}
}
private string _type = "1";
public string Type
{
get { return _type; }
set
{
if (value != _type)
{
_type = value;
OnPropertyChanged(nameof(Type));
}
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
このコードにより画像の上部のようにコンボボックスとTextがバインドによってコンボボックスの要素を変更するとTextの値が変化します。ChatGPT先生流石です。
DataGridの外のコンボボックスとTextではできたのでDataGrid内でも同じことができると考えたのですが、2枚目の画像のようにDataGrid内ではコンボボックスを変化させても同じセルでも違うセルでも外側のTextと同じようにバインドしても値が変化しませんでした。なぜできないのか再度ChatGPT先生に聞いてみましたが分からないとのことでした。ChatGPT先生使えねぇな。
解決策
コンボボックスのSelectIndexをバインドして、この値が変化したらTypeの値を変化させるといった方法でもよいのですが、なんか方法がありそうなのでSelectedItemを使用する方式を調査してみました。
様々なサイトを調査した結果、SelectedItemにUpdateSourceTrigger=PropertyChangedを追加したら下記画像のようにDataGrid内のコンボボックスを変化させるとTextの値が変更される想定道理の動きになりました。
変更箇所 SelectedItem="{Binding Type, UpdateSourceTrigger=PropertyChanged}"
<Window
x:Class="ComboBoxValue.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:local="clr-namespace:ComboBoxValue"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" LastChildFill="false">
<ComboBox
Width="120"
ItemsSource="{Binding TypePattern}"
SelectedIndex="0"
SelectedItem="{Binding Type}" />
<TextBlock
Width="120"
Text="{Binding Type}"
TextWrapping="Wrap" />
</DockPanel>
<DataGrid
Grid.Row="1"
AutoGenerateColumns="False"
CanUserAddRows="False"
CanUserSortColumns="False"
HeadersVisibility="Column"
ItemsSource="{Binding DataGrids}"
SelectionMode="Single">
<DataGrid.Columns>
<DataGridTextColumn
Width="*"
Binding="{Binding Type}"
Header="タイプ" />
<DataGridTemplateColumn Width="*" Header="タイプ">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox
ItemsSource="{Binding TypePattern}"
SelectedIndex="0"
SelectedItem="{Binding Type, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="{Binding Type}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
あとがき
以上がDataGrid内のコンボボックスの変更によって他のTextを変更する方法です。この記事がWPFでDataGridの中にコンボボックスを入れたいときが多々ある人の助けとなれば幸いです。