Skip to content

Commit 0dd2438

Browse files
DataGrid style cleanup (#3033)
* Introduce attached property for ComboBox column style - DataGrid Similar to text and checkbox columns, the auto-generated style can now be set using an attached property. * Introduce DataGridAssist.ApplyMaterialDesignColumnStyles attached property The attached property, when set, inspects all columns of the data grid and applies MDIX styles if the default style has not been overridden. This works both for auto-generated and explicitly-defined columns. * Fix nullability error when building in pipeline * Fixed another nullable build error found in the pipeline * Refactor DataGridAssist.ApplyMaterialDesignColumnStyles to use AP The assist class now uses the attached properties associated with the corresponding DataGrid. Introduced a ColumnUpdater type and a private DP in order to have a reference to the DataGrid in the Columns_CollectionChanged() callback and to do proper housekeeping/cleanup to avoid memory leaks. * Update MaterialDesignThemes.Wpf/DataGridAssist.cs Co-authored-by: Kevin B <[email protected]> * Refactor to use local function to capture "dataGrid" variable Removing the ColumnUpdater in place of a local function which captures the variable nicely. This removes the need for the ColumnUpdater type entirely, and removes the associated attached property. Co-authored-by: Kevin B <[email protected]>
1 parent e02fd04 commit 0dd2438

File tree

5 files changed

+171
-12
lines changed

5 files changed

+171
-12
lines changed

MainDemo.Wpf/DataGrids.xaml

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,8 @@
4343
</DataGrid.Resources>
4444

4545
<DataGrid.Columns>
46-
<DataGridCheckBoxColumn Binding="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}"
47-
EditingElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnEditingStyle}"
48-
ElementStyle="{StaticResource MaterialDesignDataGridCheckBoxColumnStyle}">
46+
<!-- by default a DataGridCheckBoxColumn will have the MaterialDesignDataGridCheckBoxColumnStyle and MaterialDesignDataGridCheckBoxColumnEditingStyle applied. See DataGridAssist.ApplyMaterialDesignColumnStyles attached property -->
47+
<DataGridCheckBoxColumn Binding="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}">
4948
<DataGridCheckBoxColumn.Header>
5049
<Border Background="Transparent">
5150
<CheckBox IsChecked="{Binding Data.IsAllItems1Selected, Source={StaticResource DataContextProxy}}" />
@@ -59,10 +58,8 @@
5958
</DataGridCheckBoxColumn.HeaderStyle>
6059
</DataGridCheckBoxColumn>
6160

62-
<DataGridTextColumn Binding="{Binding Code}"
63-
EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnEditingStyle}"
64-
ElementStyle="{StaticResource MaterialDesignDataGridTextColumnStyle}"
65-
Header="Code" />
61+
<!-- by default a DataGridTextColumn will have the MaterialDesignDataGridTextColumnStyle and MaterialDesignDataGridTextColumnEditingStyle applied. See DataGridAssist.ApplyMaterialDesignColumnStyles attached property -->
62+
<DataGridTextColumn Binding="{Binding Code}" Header="Code" />
6663

6764
<!-- if you want to use the pop up style (MaterialDesignDataGridTextColumnPopupEditingStyle), you must use MaterialDataGridTextColumn -->
6865
<materialDesign:DataGridTextColumn EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnPopupEditingStyle}"
@@ -78,9 +75,7 @@
7875
</materialDesign:DataGridTextColumn>
7976

8077
<!-- set a max length to get an indicator in the editor -->
81-
<DataGridTextColumn EditingElementStyle="{StaticResource MaterialDesignDataGridTextColumnEditingStyle}"
82-
ElementStyle="{StaticResource MaterialDesignDataGridTextColumnStyle}"
83-
Header="Description">
78+
<DataGridTextColumn Header="Description">
8479
<DataGridTextColumn.Binding>
8580
<Binding Path="Description">
8681
<Binding.ValidationRules>
@@ -188,7 +183,7 @@
188183
<smtx:XamlDisplay UniqueKey="grids_4">
189184
<DataGrid materialDesign:DataGridAssist.SelectedCellBorderBrush="Crimson"
190185
CanUserAddRows="False"
191-
ItemsSource="{Binding Items1}" />
186+
ItemsSource="{Binding Items4}" />
192187
</smtx:XamlDisplay>
193188
</StackPanel>
194189
</UserControl>

MainDemo.Wpf/Domain/ListsAndGridsViewModel.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public ListsAndGridsViewModel()
99
Items1 = CreateData();
1010
Items2 = CreateData();
1111
Items3 = CreateData();
12+
Items4 = CreateData();
1213

1314
foreach (var model in Items1)
1415
{
@@ -81,6 +82,7 @@ private static ObservableCollection<SelectableViewModel> CreateData()
8182
public ObservableCollection<SelectableViewModel> Items1 { get; }
8283
public ObservableCollection<SelectableViewModel> Items2 { get; }
8384
public ObservableCollection<SelectableViewModel> Items3 { get; }
85+
public ObservableCollection<SelectableViewModel> Items4 { get; }
8486

8587
public IEnumerable<string> Foods => new[] { "Burger", "Fries", "Shake", "Lettuce" };
8688

MainDemo.Wpf/Domain/SelectableViewModel.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public class SelectableViewModel : ViewModelBase
99
private double _numeric;
1010
private string? _food;
1111
private string? _files;
12+
private VehicleType _vehicleType;
1213

1314
public bool IsSelected
1415
{
@@ -51,4 +52,20 @@ public string? Files
5152
get => _files;
5253
set => SetProperty(ref _files, value);
5354
}
55+
56+
public VehicleType VehicleType
57+
{
58+
get => _vehicleType;
59+
set => SetProperty(ref _vehicleType, value);
60+
}
61+
}
62+
63+
public enum VehicleType
64+
{
65+
Car,
66+
Bus,
67+
Motorcycle,
68+
Van,
69+
Scooter,
70+
Truck
5471
}

MaterialDesignThemes.Wpf/DataGridAssist.cs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Collections.Specialized;
12
using System.Windows.Media;
23

34
namespace MaterialDesignThemes.Wpf;
@@ -120,6 +121,147 @@ private static void SetGeneratedTextColumnEditingStyle(object? sender, DataGridA
120121
}
121122
#endregion
122123

124+
#region AttachedProperty : AutoGeneratedComboBoxStyleProperty
125+
public static readonly DependencyProperty AutoGeneratedComboBoxStyleProperty
126+
= DependencyProperty.RegisterAttached("AutoGeneratedComboBoxStyle", typeof(Style), typeof(DataGridAssist),
127+
new PropertyMetadata(default(Style), AutoGeneratedComboBoxStylePropertyChangedCallback));
128+
129+
public static Style GetAutoGeneratedComboBoxStyle(DataGrid element)
130+
=> (Style)element.GetValue(AutoGeneratedComboBoxStyleProperty);
131+
public static void SetAutoGeneratedComboBoxStyle(DataGrid element, Style value)
132+
=> element.SetValue(AutoGeneratedComboBoxStyleProperty, value);
133+
134+
private static void AutoGeneratedComboBoxStylePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
135+
{
136+
var dataGrid = (DataGrid)d;
137+
138+
dataGrid.AutoGeneratingColumn -= SetGeneratedComboBoxColumnStyle;
139+
dataGrid.AutoGeneratingColumn += SetGeneratedComboBoxColumnStyle;
140+
}
141+
142+
private static void SetGeneratedComboBoxColumnStyle(object? sender, DataGridAutoGeneratingColumnEventArgs e)
143+
{
144+
if (e.Column is System.Windows.Controls.DataGridComboBoxColumn column &&
145+
sender is DataGrid dataGrid)
146+
{
147+
column.ElementStyle = GetAutoGeneratedComboBoxStyle(dataGrid);
148+
}
149+
}
150+
#endregion
151+
152+
#region AttachedProperty : AutoGeneratedEditingComboBoxStyleProperty
153+
public static readonly DependencyProperty AutoGeneratedEditingComboBoxStyleProperty
154+
= DependencyProperty.RegisterAttached("AutoGeneratedEditingComboBoxStyle", typeof(Style), typeof(DataGridAssist),
155+
new PropertyMetadata(default(Style), AutoGeneratedEditingComboBoxStylePropertyChangedCallback));
156+
157+
public static Style GetAutoGeneratedEditingComboBoxStyle(DataGrid element)
158+
=> (Style)element.GetValue(AutoGeneratedEditingComboBoxStyleProperty);
159+
public static void SetAutoGeneratedEditingComboBoxStyle(DataGrid element, Style value)
160+
=> element.SetValue(AutoGeneratedEditingComboBoxStyleProperty, value);
161+
162+
private static void AutoGeneratedEditingComboBoxStylePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
163+
{
164+
var dataGrid = (DataGrid)d;
165+
166+
dataGrid.AutoGeneratingColumn -= SetGeneratedComboBoxColumnEditingStyle;
167+
dataGrid.AutoGeneratingColumn += SetGeneratedComboBoxColumnEditingStyle;
168+
}
169+
170+
private static void SetGeneratedComboBoxColumnEditingStyle(object? sender, DataGridAutoGeneratingColumnEventArgs e)
171+
{
172+
if (e.Column is System.Windows.Controls.DataGridComboBoxColumn column &&
173+
sender is DataGrid dataGrid)
174+
{
175+
column.EditingElementStyle = GetAutoGeneratedEditingComboBoxStyle(dataGrid);
176+
}
177+
}
178+
#endregion
179+
180+
#region AttachedProperty : ApplyMaterialDesignColumnStylesProperty
181+
public static readonly DependencyProperty ApplyMaterialDesignColumnStylesProperty
182+
= DependencyProperty.RegisterAttached("ApplyMaterialDesignColumnStyles", typeof(bool), typeof(DataGridAssist),
183+
new PropertyMetadata(default(bool), ApplyMaterialDesignColumnStylesPropertyChangedCallback));
184+
185+
public static void SetApplyMaterialDesignColumnStyles(DataGrid element, bool value)
186+
=> element.SetValue(ApplyMaterialDesignColumnStylesProperty, value);
187+
188+
public static bool GetApplyMaterialDesignColumnStyles(DataGrid element)
189+
=> (bool) element.GetValue(ApplyMaterialDesignColumnStylesProperty);
190+
191+
private static void ApplyMaterialDesignColumnStylesPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
192+
{
193+
var dataGrid = (DataGrid)d;
194+
dataGrid.Columns.CollectionChanged -= ColumnsCollectionChanged;
195+
if (Equals(true, e.NewValue))
196+
{
197+
dataGrid.Columns.CollectionChanged += ColumnsCollectionChanged; // Auto-generated columns are added later in the chain, thus we subscribe to changes.
198+
foreach (var column in dataGrid.Columns)
199+
{
200+
ApplyMaterialDesignColumnStyleForColumn(dataGrid, column);
201+
}
202+
}
203+
204+
void ColumnsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
205+
{
206+
foreach (DataGridColumn column in e.NewItems?.OfType<DataGridColumn>() ?? Enumerable.Empty<DataGridColumn>())
207+
{
208+
ApplyMaterialDesignColumnStyleForColumn(dataGrid, column);
209+
}
210+
}
211+
}
212+
213+
private static void ApplyMaterialDesignColumnStyleForColumn(DataGrid dataGrid, DataGridColumn column)
214+
{
215+
Style defaultElementStyle = (Style)DataGridBoundColumn.ElementStyleProperty.GetMetadata(column.GetType()).DefaultValue;
216+
Style defaultEditingElementStyle = (Style)DataGridBoundColumn.EditingElementStyleProperty.GetMetadata(column.GetType()).DefaultValue;
217+
218+
bool applyElementStyle;
219+
bool applyEditingElementStyle;
220+
switch (column)
221+
{
222+
case DataGridCheckBoxColumn checkBoxColumn:
223+
applyElementStyle = Equals(checkBoxColumn.ElementStyle, defaultElementStyle);
224+
applyEditingElementStyle = Equals(checkBoxColumn.EditingElementStyle, defaultEditingElementStyle);
225+
if (applyElementStyle && GetAutoGeneratedCheckBoxStyle(dataGrid) is { } checkBoxElementStyle)
226+
{
227+
checkBoxColumn.ElementStyle = checkBoxElementStyle;
228+
}
229+
230+
if (applyEditingElementStyle && GetAutoGeneratedEditingCheckBoxStyle(dataGrid) is { } checkBoxEditingElementStyle)
231+
{
232+
checkBoxColumn.EditingElementStyle = checkBoxEditingElementStyle;
233+
}
234+
break;
235+
case System.Windows.Controls.DataGridTextColumn textColumn:
236+
applyElementStyle = Equals(textColumn.ElementStyle, defaultElementStyle);
237+
applyEditingElementStyle = Equals(textColumn.EditingElementStyle, defaultEditingElementStyle);
238+
if (applyElementStyle && GetAutoGeneratedTextStyle(dataGrid) is { } textElementStyle)
239+
{
240+
textColumn.ElementStyle = textElementStyle;
241+
}
242+
243+
if (applyEditingElementStyle && GetAutoGeneratedEditingTextStyle(dataGrid) is { } textEditingElementStyle)
244+
{
245+
textColumn.EditingElementStyle = textEditingElementStyle;
246+
}
247+
break;
248+
case System.Windows.Controls.DataGridComboBoxColumn comboBoxColumn:
249+
applyElementStyle = Equals(comboBoxColumn.ElementStyle, defaultElementStyle);
250+
applyEditingElementStyle = Equals(comboBoxColumn.EditingElementStyle, defaultEditingElementStyle);
251+
if (applyElementStyle && GetAutoGeneratedComboBoxStyle(dataGrid) is { } comboBoxElementStyle)
252+
{
253+
comboBoxColumn.ElementStyle = comboBoxElementStyle;
254+
}
255+
256+
if (applyEditingElementStyle && GetAutoGeneratedEditingComboBoxStyle(dataGrid) is { } comboBoxEditingElementStyle)
257+
{
258+
comboBoxColumn.EditingElementStyle = comboBoxEditingElementStyle;
259+
}
260+
break;
261+
}
262+
}
263+
#endregion
264+
123265
#region AttachedProperty : CellPaddingProperty
124266
public static readonly DependencyProperty CellPaddingProperty
125267
= DependencyProperty.RegisterAttached("CellPadding", typeof(Thickness), typeof(DataGridAssist),

MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.DataGrid.xaml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
1+
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
22
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
33
xmlns:converters="clr-namespace:MaterialDesignThemes.Wpf.Converters"
44
xmlns:wpf="clr-namespace:MaterialDesignThemes.Wpf">
@@ -553,6 +553,9 @@
553553
<Setter Property="wpf:DataGridAssist.AutoGeneratedEditingCheckBoxStyle" Value="{StaticResource MaterialDesignDataGridCheckBoxColumnEditingStyle}" />
554554
<Setter Property="wpf:DataGridAssist.AutoGeneratedEditingTextStyle" Value="{StaticResource MaterialDesignDataGridTextColumnEditingStyle}" />
555555
<Setter Property="wpf:DataGridAssist.AutoGeneratedTextStyle" Value="{StaticResource MaterialDesignDataGridTextColumnStyle}" />
556+
<Setter Property="wpf:DataGridAssist.AutoGeneratedEditingComboBoxStyle" Value="{x:Static wpf:DataGridComboBoxColumn.DefaultEditingElementStyle}" />
557+
<Setter Property="wpf:DataGridAssist.AutoGeneratedComboBoxStyle" Value="{x:Static wpf:DataGridComboBoxColumn.DefaultElementStyle}" />
558+
<Setter Property="wpf:DataGridAssist.ApplyMaterialDesignColumnStyles" Value="true" />
556559
<Setter Property="wpf:DataGridAssist.EnableEditBoxAssist" Value="True" />
557560
<Setter Property="wpf:DataGridAssist.SelectedCellBorderBrush" Value="{DynamicResource MaterialDesignTextBoxBorder}" />
558561
<Style.Triggers>

0 commit comments

Comments
 (0)