Reputation: 99
I have a DataGrid binded to a DataTable that I've called "GridCollection" :
<!--DataGrid-->
<DataGrid Name="DataGrid" ItemsSource="{Binding GridCollection}" >
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<ComboBox ItemsSource="{Binding SelectionOptions}">
<ComboBox.Style>
<Style TargetType="ComboBox">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Caption, Mode=TwoWay}" Value="ShowComboBox">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
I want to be able to dynamically update the DataGrid Column Cell Template to display comboboxes.
I've tried to achieve this by adding a DataTrigger binded to a property of the DataTable column ("Caption"), and then updating the Visibility of the combobox accordingly.
My understanding is that the DataContext in this case is the DataTable's Columns.
I have tried setting the "Caption" property of the DataTable's Columns to match the value speicified in the DataTrigger ("ShowComboBox") :
ViewModel.GridCollection.Columns[index].Caption = "ShowComboBox";
After confirming that this line of code is being executed and that the Caption property is being updated, this is still making no change to the DataGrid. No columns are showing a combo box.
I'm not sure if there is a problem with the binding, or if it is something else.
Any help is appreciated!
Upvotes: 0
Views: 1017
Reputation: 169240
Since the DataColumn
doesn't implement the INotifyPropertyChanged interface and raise property change notifications to WPF, this won't work.
If you however add a column to the DataTable
and bind to this one, it will work:
ViewModel.GridCollection.Columns.Add(new DataColumn("Caption"));
The difference is that the DataRowView
class implements the INotifyPropertyChanged
interface. This is required for WPF to be able to listen to changes to a source property and update the view dynamically.
Upvotes: 1
Reputation: 89
If you change the layout you need to reset your binding. Remove the binding / data source from you datagrid. Change the Caption value and bind the source again to your datagrid.
Here the code which works for me:
The XAML of the window
Window x:Class="WpfApplication7.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:WpfApplication7"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<DataGrid Name="grd" AutoGenerateColumns="False" ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}, Path=DataContext}">
<DataGrid.Columns>
<DataGridTextColumn Header="01" Binding="{Binding Name}" />
<DataGridTextColumn Header="02" Binding="{Binding LastName}" />
<DataGridTemplateColumn Header="CBX">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox>
<ComboBox.Style>
<Style TargetType="ComboBox">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Caption, Mode=TwoWay}" Value="ShowCombobox">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button Content="Click" Click="Button_Click" Grid.Row="1"/>
</Grid>
</Window>
The code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication7
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
items soureitems = new items();
for(int i = 0; i <= 10; i++)
{
item sourceitem = new item();
sourceitem.Name = "John";
sourceitem.LastName = "Doe";
sourceitem.Caption = "";
soureitems.Add(sourceitem);
}
this.DataContext = soureitems;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
items sourceitems = (items)(this.DataContext);
this.DataContext = null;
foreach (item sourceitem in sourceitems)
{
if(sourceitem.Caption != "ShowCombobox")
{
sourceitem.Caption = "ShowCombobox";
} else
{
sourceitem.Caption = "";
}
}
this.DataContext = sourceitems;
}
}
public class items : System.Collections.ObjectModel.ObservableCollection<item> { }
public class item
{
string _Name;
string _LastName;
string _Caption;
public string Name {
get { return _Name; }
set { _Name = value; }
}
public string LastName
{
get { return _LastName; }
set { _LastName = value; }
}
public string Caption
{
get { return _Caption; }
set { _Caption = value; }
}
}
}
Upvotes: 0