Skip to content

Commit 02e1e70

Browse files
committed
Fix #27: Change notification for SourceValues when collection of item changes.
1 parent 810f708 commit 02e1e70

File tree

8 files changed

+87
-65
lines changed

8 files changed

+87
-65
lines changed

DataGridExtensions/DataGridExtensions.csproj

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,15 @@ The current version supports the following features:
2828
</PropertyGroup>
2929

3030
<ItemGroup>
31+
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.6">
32+
<PrivateAssets>all</PrivateAssets>
33+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
34+
</PackageReference>
3135
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.3" />
32-
<PackageReference Include="Fody" Version="6.0.2" PrivateAssets="All" />
36+
<PackageReference Include="Fody" Version="6.0.3" PrivateAssets="All" />
3337
<PackageReference Include="JetBrainsAnnotations.Fody" Version="2.14.0" PrivateAssets="All" />
3438
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-19367-01" PrivateAssets="All" />
39+
<PackageReference Include="Throttle.Fody" Version="1.5.0" PrivateAssets="All" />
3540
</ItemGroup>
3641

3742
<ItemGroup>

DataGridExtensions/DataGridFilterColumnControl.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{
33
using System;
44
using System.Collections.Generic;
5+
using System.Collections.Specialized;
56
using System.ComponentModel;
67
using System.Linq;
78
using System.Windows;
@@ -10,8 +11,12 @@
1011
using System.Windows.Data;
1112
using System.Windows.Threading;
1213

14+
using DataGridExtensions.Framework;
15+
1316
using JetBrains.Annotations;
1417

18+
using Throttle;
19+
1520
/// <summary>
1621
/// This class is the control hosting all information needed for filtering of one column.
1722
/// Filtering is enabled by simply adding this control to the header template of the DataGridColumn.
@@ -72,6 +77,7 @@ private void Self_Loaded([NotNull] object sender, [NotNull] RoutedEventArgs e)
7277
DataGrid.SourceUpdated += DataGrid_SourceOrTargetUpdated;
7378
DataGrid.TargetUpdated += DataGrid_SourceOrTargetUpdated;
7479
DataGrid.RowEditEnding += DataGrid_RowEditEnding;
80+
((INotifyCollectionChanged)DataGrid.Items).CollectionChanged += DataGrid_CollectionChanged;
7581
// ReSharper restore PossibleNullReferenceException
7682

7783
// Must set a non-null empty template here, else we won't get the coerce value callback when the columns attached property is null!
@@ -103,6 +109,7 @@ private void Self_Unloaded([NotNull] object sender, [NotNull] RoutedEventArgs e)
103109
dataGrid.SourceUpdated -= DataGrid_SourceOrTargetUpdated;
104110
dataGrid.TargetUpdated -= DataGrid_SourceOrTargetUpdated;
105111
dataGrid.RowEditEnding -= DataGrid_RowEditEnding;
112+
((INotifyCollectionChanged)dataGrid.Items).CollectionChanged -= DataGrid_CollectionChanged;
106113
}
107114

108115
// Clear all bindings generated during load.
@@ -123,9 +130,15 @@ private void DataGrid_SourceOrTargetUpdated([NotNull] object sender, [NotNull] D
123130

124131
private void DataGrid_RowEditEnding([NotNull] object sender, [NotNull] DataGridRowEditEndingEventArgs e)
125132
{
126-
this.BeginInvoke(DispatcherPriority.Background, ValuesUpdated);
133+
ValuesUpdated();
134+
}
135+
136+
private void DataGrid_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
137+
{
138+
ValuesUpdated();
127139
}
128140

141+
129142
/// <summary>
130143
/// The user provided filter (IFilter) or content (usually a string) used to filter this column.
131144
/// If the filter object implements IFilter, it will be used directly as the filter,
@@ -259,6 +272,7 @@ internal bool Matches([CanBeNull] object item)
259272
/// <summary>
260273
/// Notification of the filter that the content of the values might have changed.
261274
/// </summary>
275+
[Throttled(typeof(DispatcherThrottle), (int)DispatcherPriority.Background)]
262276
internal void ValuesUpdated()
263277
{
264278
// We simply raise a change event for the properties and create the output on the fly in the getter of the properties;

DataGridExtensions/FodyWeavers.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
3+
<Throttle />
34
<JetBrainsAnnotations />
45
</Weavers>

DataGridExtensions/FodyWeavers.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<xs:element name="Weavers">
55
<xs:complexType>
66
<xs:all>
7+
<xs:element name="Throttle" minOccurs="0" maxOccurs="1" type="xs:anyType" />
78
<xs:element name="JetBrainsAnnotations" minOccurs="0" maxOccurs="1" type="xs:anyType" />
89
</xs:all>
910
<xs:attribute name="VerifyAssembly" type="xs:boolean">

DataGridExtensionsSample/DataGridExtensionsSample.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@
125125
<Resource Include="SampleList.xml" />
126126
</ItemGroup>
127127
<ItemGroup>
128+
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers">
129+
<Version>2.9.6</Version>
130+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
131+
<PrivateAssets>all</PrivateAssets>
132+
</PackageReference>
128133
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf">
129134
<Version>1.1.3</Version>
130135
</PackageReference>

DataGridExtensionsSample/DataItem.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,19 @@ namespace DataGridExtensionsSample
77
{
88
public class DataItem
99
{
10-
private static string[] _samples = new[] {"lorem", "ipsum", "dolor", "sit", "amet"};
10+
private static readonly Random _rand = new Random();
11+
private static readonly string[] _samples = new[] {"lorem", "ipsum", "dolor", "sit", "amet"};
1112

12-
public DataItem(Random rand, int index)
13+
public DataItem(int index)
1314
{
14-
Flag = rand.Next(2) == 0;
15+
Flag = _rand.Next(2) == 0;
1516
Index = index;
1617
Column1 = Guid.NewGuid().ToString();
17-
Column2 = rand.Next(20) == 0 ? null : Guid.NewGuid().ToString();
18+
Column2 = _rand.Next(20) == 0 ? null : Guid.NewGuid().ToString();
1819
Column3 = Guid.NewGuid().ToString();
1920
Column4 = Guid.NewGuid().ToString();
20-
Column5 = _samples[rand.Next(_samples.Length)];
21-
Probability = rand.NextDouble();
21+
Column5 = _samples[_rand.Next(_samples.Length)];
22+
Probability = _rand.NextDouble();
2223
}
2324

2425
public bool Flag { get; private set; }

DataGridExtensionsSample/MainWindow.xaml

Lines changed: 40 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,17 @@
2121
</ControlTemplate>
2222

2323
<ControlTemplate x:Key="FilterWithPopup">
24-
<src:FilterWithPopupControl Filter="{Binding Path=Filter, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dgx:DataGridFilterColumnControl}}"/>
24+
<src:FilterWithPopupControl Filter="{Binding Path=Filter, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dgx:DataGridFilterColumnControl}}" />
2525
</ControlTemplate>
2626

2727
<ControlTemplate x:Key="MultipleChoiceFilter">
28-
<src:MultipleChoiceFilter Filter="{Binding Path=Filter, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dgx:DataGridFilterColumnControl}}"/>
28+
<src:MultipleChoiceFilter Filter="{Binding Path=Filter, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dgx:DataGridFilterColumnControl}}" />
2929
</ControlTemplate>
3030

3131
<ControlTemplate x:Key="ComboboxFilter">
3232
<Grid d:DataContext="{d:DesignInstance dgx:DataGridFilterColumnControl}">
3333
<Grid>
34-
<Control Style="{DynamicResource {x:Static dgx:DataGridFilter.IconStyleKey}}"/>
34+
<Control Style="{DynamicResource {x:Static dgx:DataGridFilter.IconStyleKey}}" />
3535
<ComboBox x:Name="ComboBox" Text="{Binding Path=Filter, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding SourceValues}" IsEditable="True" />
3636
</Grid>
3737
</Grid>
@@ -56,21 +56,21 @@
5656
<Setter Property="VerticalGridLinesBrush" Value="LightGray" />
5757
</Style>
5858

59-
<XmlDataProvider x:Key="ComboBoxSource" Source="SampleList.xml" XPath="Items/Item"/>
59+
<XmlDataProvider x:Key="ComboBoxSource" Source="SampleList.xml" XPath="Items/Item" />
6060

6161
<CollectionViewSource x:Key="SortedItems" Source="{Binding Items}">
6262
<CollectionViewSource.SortDescriptions>
63-
<componentModel:SortDescription PropertyName="Column1"/>
63+
<componentModel:SortDescription PropertyName="Column1" />
6464
</CollectionViewSource.SortDescriptions>
6565
</CollectionViewSource>
6666

6767
<Style x:Key="DataGridComboBoxStyle" TargetType="ComboBox">
68-
<Setter Property="BorderThickness" Value="0"/>
69-
<Setter Property="Padding" Value="3,2,0,0"/>
70-
<Setter Property="Foreground" Value="Green"/>
68+
<Setter Property="BorderThickness" Value="0" />
69+
<Setter Property="Padding" Value="3,2,0,0" />
70+
<Setter Property="Foreground" Value="Green" />
7171
</Style>
7272
<Style x:Key="DataGridTextBlockStyle" TargetType="TextBlock">
73-
<Setter Property="Foreground" Value="Blue"/>
73+
<Setter Property="Foreground" Value="Blue" />
7474
</Style>
7575

7676
</Window.Resources>
@@ -90,7 +90,7 @@
9090
<Decorator Height="10" />
9191
<StackPanel Orientation="Horizontal">
9292
<CheckBox x:Name="IsFilterEnabled" DockPanel.Dock="Top" IsChecked="True" Content="Enable filters" VerticalAlignment="Center" />
93-
<Decorator Width="20"/>
93+
<Decorator Width="20" />
9494
<Button Click="ClearAllFilters_Click">Clear all filters</Button>
9595
</StackPanel>
9696
</StackPanel>
@@ -99,17 +99,18 @@
9999
dgx:DataGridFilter.IsAutoFilterEnabled="{Binding Path=IsChecked, ElementName=IsFilterEnabled}">
100100
<DataGrid.ItemsPanel>
101101
<ItemsPanelTemplate>
102-
<VirtualizingStackPanel KeyboardNavigation.DirectionalNavigation="Contained"/>
102+
<VirtualizingStackPanel KeyboardNavigation.DirectionalNavigation="Contained" />
103103
</ItemsPanelTemplate>
104104
</DataGrid.ItemsPanel>
105-
</DataGrid></DockPanel>
105+
</DataGrid>
106+
</DockPanel>
106107
</TabItem>
107108

108109
<TabItem Header="Extended 1">
109110
<DockPanel>
110111
<TextBlock DockPanel.Dock="Top" Margin="10" TextWrapping="WrapWithOverflow">
111-
<Run>This tab shows how to customize the filters when using auto generated columns. See the DataGrid_AutoGeneratingColumn event handler for details.</Run><LineBreak/>
112-
<Run>- Overrides the content filter factory to use the regex matching instead of the default simple "string contains" matching.</Run><LineBreak/>
112+
<Run>This tab shows how to customize the filters when using auto generated columns. See the DataGrid_AutoGeneratingColumn event handler for details.</Run><LineBreak />
113+
<Run>- Overrides the content filter factory to use the regex matching instead of the default simple "string contains" matching.</Run><LineBreak />
113114
<Run>- Uses the sample IntergerFilter for the Index column.</Run>
114115
</TextBlock>
115116
<DataGrid ItemsSource="{Binding Items}"
@@ -119,14 +120,14 @@
119120
<DataGrid.Resources>
120121
<!-- Override the filter icon used in the default templates with a fat orange symbol; active for this grid only -->
121122
<ControlTemplate x:Key="{x:Static dgx:DataGridFilter.IconTemplateKey}">
122-
<Path Data="M0,0 L10,0 7,5 7,9 3,9 3,5 Z" Fill="Orange" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2,0"/>
123+
<Path Data="M0,0 L10,0 7,5 7,9 3,9 3,5 Z" Fill="Orange" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="2,0" />
123124
</ControlTemplate>
124125
</DataGrid.Resources>
125126

126127
<i:Interaction.Behaviors>
127-
<dgx:ExtendedStarSizeBehavior/>
128-
<dgx:BeginEditOnCtrlEnterBehavior/>
129-
<dgx:DisableTargetWhileEditingBehavior Target="{Binding ElementName=ReloadButton}"/>
128+
<dgx:ExtendedStarSizeBehavior />
129+
<dgx:BeginEditOnCtrlEnterBehavior />
130+
<dgx:DisableTargetWhileEditingBehavior Target="{Binding ElementName=ReloadButton}" />
130131
</i:Interaction.Behaviors>
131132

132133
</DataGrid>
@@ -135,25 +136,28 @@
135136

136137
<TabItem Header="Extended 2">
137138
<DockPanel>
138-
<TextBlock DockPanel.Dock="Top" Margin="10" TextWrapping="WrapWithOverflow">
139-
<Run>This tab shows how to customize the filters in XAML when using explicit generated columns. Read the comments in the XAML for details.</Run><LineBreak/>
140-
<Run>Overrides the icon template to show an orange filter symbol.</Run>
141-
</TextBlock>
139+
<DockPanel DockPanel.Dock="Top" Margin="10">
140+
<Button DockPanel.Dock="Right" VerticalAlignment="Top" Padding="5,2" Click="ClearIpsum_Click">Clear Ipsum</Button>
141+
<TextBlock TextWrapping="WrapWithOverflow">
142+
<Run>This tab shows how to customize the filters in XAML when using explicit generated columns. Read the comments in the XAML for details.</Run><LineBreak />
143+
<Run>Overrides the icon template to show an orange filter symbol.</Run>
144+
</TextBlock>
145+
</DockPanel>
142146
<DataGrid ItemsSource="{Binding Source={StaticResource SortedItems}}" AutoGenerateColumns="False" FrozenColumnCount="2"
143147
dgx:DataGridFilter.GlobalFilter="{Binding ExternalFilter}"
144148
dgx:DataGridFilter.IsAutoFilterEnabled="True"
145149
dgx:Tools.ApplyInitialSorting="True"
146150
dgx:DataGridFilter.FilterEvaluationDelay="0:0:0">
147151
<i:Interaction.Behaviors>
148-
<dgx:ExtendedStarSizeBehavior/>
149-
<dgx:BeginEditOnCtrlEnterBehavior/>
152+
<dgx:ExtendedStarSizeBehavior />
153+
<dgx:BeginEditOnCtrlEnterBehavior />
150154
</i:Interaction.Behaviors>
151155

152156
<!-- Override the default styles for some columns... -->
153157
<dgx:ColumnStyles.DefaultColumnStyles>
154158
<dgx:DataGridColumnStyleCollection>
155-
<dgx:DataGridColumnStyle ColumnType="DataGridComboBoxColumn" EditingElementStyle="{StaticResource DataGridComboBoxStyle}"/>
156-
<dgx:DataGridColumnStyle ColumnType="DataGridTextColumn" ElementStyle="{StaticResource DataGridTextBlockStyle}"/>
159+
<dgx:DataGridColumnStyle ColumnType="DataGridComboBoxColumn" EditingElementStyle="{StaticResource DataGridComboBoxStyle}" />
160+
<dgx:DataGridColumnStyle ColumnType="DataGridTextColumn" ElementStyle="{StaticResource DataGridTextBlockStyle}" />
157161
</dgx:DataGridColumnStyleCollection>
158162
</dgx:ColumnStyles.DefaultColumnStyles>
159163

@@ -192,43 +196,30 @@
192196
<DataGridTextColumn Header="Integer/Custom"
193197
Binding="{Binding Index, Mode=OneWay}"
194198
Width="*"
195-
dgx:DataGridFilterColumn.Template="{StaticResource IntegerFilter}"
196-
/>
199+
dgx:DataGridFilterColumn.Template="{StaticResource IntegerFilter}" />
197200
<!-- Hide the filter for this column. -->
198-
<DataGridTextColumn Header="Text/No Filter" Binding="{Binding Column1}" Width="*"
201+
<DataGridTextColumn Header="Text/No Filter" Binding="{Binding Column5}" Width="*"
199202
dgx:DataGridFilterColumn.IsFilterVisible="False"
200203
dgx:Tools.IsMultilineEditingEnabled="True"
201204
SortDirection="Descending" />
202205
<!-- Use the default filter for this column. -->
203-
<DataGridTextColumn x:Name="Column2" Header="Text/Text" Binding="{Binding Column2, Mode=OneWay}" Width="*" />
204-
<!-- Use a simple combo box for filtering -->
206+
<DataGridTextColumn x:Name="Column2" Header="Text/Text" Binding="{Binding Column2, Mode=OneWay}" Width="*" />
207+
<!-- Use a MultipleChoiceFilter for filtering -->
205208
<DataGridComboBoxColumn Header="Text/Custom" SelectedValueBinding="{Binding Column5}"
206209
Width="*" dgx:DataGridFilterColumn.Template="{StaticResource MultipleChoiceFilter}"
207-
ItemsSource="{Binding Source={StaticResource ComboBoxSource}}"/>
208-
<!-- Use a simple combo box for filtering, but override the editing element style -->
210+
ItemsSource="{Binding Source={StaticResource ComboBoxSource}}" />
211+
<!-- Use a simple combo box for filtering -->
209212
<DataGridComboBoxColumn Header="Text/Custom" SelectedValueBinding="{Binding Column5}"
210213
Width="*" dgx:DataGridFilterColumn.Template="{StaticResource ComboboxFilter}"
211-
ItemsSource="{Binding Source={StaticResource ComboBoxSource}}">
212-
<DataGridComboBoxColumn.ElementStyle>
213-
<Style TargetType="ComboBox">
214-
<Setter Property="ItemTemplate">
215-
<Setter.Value>
216-
<DataTemplate>
217-
<TextBlock Text="{Binding InnerText}" Background="BlueViolet"/>
218-
</DataTemplate>
219-
</Setter.Value>
220-
</Setter>
221-
</Style>
222-
</DataGridComboBoxColumn.ElementStyle>
223-
</DataGridComboBoxColumn>
214+
ItemsSource="{Binding Source={StaticResource ComboBoxSource}}" />
224215
<!-- Use a special filter using a toggle button with a popup to enter more than one condition. -->
225216
<DataGridTextColumn Header="Double/Custom" Binding="{Binding Probability, Mode=OneWay}" Width="*"
226217
dgx:DataGridFilterColumn.Template="{StaticResource FilterWithPopup}" />
227218
<!-- A template column may contain everything, so we need to specify the SortMemberPath explicitly...-->
228219
<DataGridTemplateColumn Header="Template" SortMemberPath="Probability">
229220
<DataGridTemplateColumn.CellTemplate>
230221
<DataTemplate>
231-
<TextBlock Margin="2" Text="{Binding Probability}"/>
222+
<TextBlock Margin="2" Text="{Binding Probability}" />
232223
</DataTemplate>
233224
</DataGridTemplateColumn.CellTemplate>
234225
</DataGridTemplateColumn>
@@ -241,8 +232,8 @@
241232
<DataGrid x:Name="CopyPasteDataGrid" SelectionUnit="Cell" ItemsSource="{Binding Items}">
242233
<DataGrid.ContextMenu>
243234
<ContextMenu>
244-
<MenuItem Header="Copy" Click="Copy_Click"/>
245-
<MenuItem Header="Paste" Click="Paste_Click"/>
235+
<MenuItem Header="Copy" Click="Copy_Click" />
236+
<MenuItem Header="Paste" Click="Paste_Click" />
246237
</ContextMenu>
247238
</DataGrid.ContextMenu>
248239
</DataGrid>

0 commit comments

Comments
 (0)