WPF DataGrid: Automatically re-sort on a DataGridTemplateColumn
In WPF's DataGrid control, if you set a column to one of the default column types (like DataGridTextColumn or DataGridCheckBoxColumn), sort on that column, and then change its value, the grid will automatically be re-sorted.
However, if you use a DataGridTemplateColumn (and allow the column to be sorted), it can be sorted, but changing the value of a cell in this column does not cause the grid is not re-sorted. How can I coax it into automatically triggering a re-sort?
XAML:
<DataGrid Name="grid" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="First name" Binding="{Binding First}"/>
<DataGridTemplateColumn Header="Last name" SortMemberPath="Last">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Last}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Binding:
ObservableCollection items = new ObservableCollection();
grid.ItemsSource = items;
items.Add(new Character() { First = "Homer", Last = "Simpson" });
items.Add(new Character() { First = "Kent", Last = "Brockman" });
items.Add(new Character() { First = "Montgomery", Last = "Burns" });
Here's my item class, just in case that's relevant:
public class Character : INotifyPropertyChanged {
private string first, last;
public event PropertyChangedEventHandler PropertyChanged;
private void Notify(string name) {
if (PropertyChanged != null)
PropertyChan开发者_如何学Goged(this, new PropertyChangedEventArgs(name));
}
public string First { get { return first; } set { first = value; Notify("First"); } }
public string Last { get { return last; } set { last = value; Notify("Last"); } }
}
I'm also looking the answer to this. I found one solution: (not happy with it but...)
When your collection is updated you can do this:
SortDescription sortDescription = grdData.Items.SortDescriptions[0];
grdData.ItemsSource = null;
grdData.ItemsSource = Data;
grdData.Items.SortDescriptions.Add(sortDescription);
Ugly but it does work. You will want to store the whole collection unlike my example that does just first item.
One problem with it though is that the DataGrid looses the header that indicates the sort, so although it resorts correctly the column header is no longer selected with the arrow showing the direction of the sort.
I know this is old but also I got this DataGridTemplateColumn re-sort problem. This does not happen on DataGridTextColumn. The way I fix it with intact sort direction on column header is:
// after updating the collection, remove all SortDescription and add'em back.
SortDescriptionCollection sortDescriptions = new SortDescriptionCollection();
foreach (SortDescription sd in dataGrid.Items.SortDescriptions)
{
sortDescriptions.Add(sd);
}
dataGrid.Items.SortDescriptions.Clear();
foreach (SortDescription sd in sortDescriptions)
{
dataGrid.Items.SortDescriptions.Add(sd);
}
Hope this helps people.
None of theses answers worked for me in 2016.
After some try&error I came up with this and it seems to work just fine:
dataGrid.Items.IsLiveSorting = true;
I had a DataGrid in C# WPF under VS2010 that would not sort regardless of the XAML settings. For some reason this hidden DataGrid (on a secondary tab) was having issues with sort order where the primary DataGrid was fine with similar settings. As such I had to diagrammatically sort the DataGrid. Here are my notes:
First the XAML for the two DataGrids (primary and secondary, we'll only be sorting the second "extended names" grid:
<TabControl Grid.Row="1" Name="tabControl1" VerticalAlignment="Top" Style="{StaticResource Section}" Margin="3" Padding="0" FontFamily="Arial" FontSize="10" BorderThickness="0" >
<TabItem Name="tabCommon" Style="{StaticResource NameTab}">
<DataGrid Name="grdCommonNames" SelectionChanged="grdCommonNames_SelectionChanged" PreviewKeyDown="grdCommonNames_PreviewKeyDown" Style="{StaticResource NameListGrid}" Focusable="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name, NotifyOnTargetUpdated=True}" Width="SizeToCells" Header="Name" CellStyle="{StaticResource NameListCol}" SortDirection="Ascending" />
<DataGridTextColumn Binding="{Binding Pronunciation, NotifyOnTargetUpdated=True}" Width="SizeToCells" Header="Pronunciation" CellStyle="{StaticResource NameListRightCol}"/>
</DataGrid.Columns>
</DataGrid>
</TabItem>
<TabItem Name="tabExtended" Style="{StaticResource NameTab}">
<DataGrid Name="grdExtendedNames" SelectionChanged="grdCommonNames_SelectionChanged" PreviewKeyDown="grdCommonNames_PreviewKeyDown" Style="{StaticResource NameListGrid}" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name, NotifyOnTargetUpdated=True}" Width="SizeToCells" Header="Name" CellStyle="{StaticResource NameListCol}" SortDirection="Descending" SortMemberPath="Name"/>
<DataGridTextColumn Binding="{Binding Pronunciation, NotifyOnTargetUpdated=True}" Width="SizeToCells" Header="Pronunciation" CellStyle="{StaticResource NameListRightCol}"/>
</DataGrid.Columns>
</DataGrid>
</TabItem>
</TabControl>
Then the code snippet to sort the second tab Datagrid after an on-click. We only sort the first time, which is why the boolean is here. That way if they sort on the other column(s) manually it is retained even if they go back to the first tab and then re-visit the 2nd tab.
Here our first column in the Datagrid is named "Name". The On Click snippet:
if (!extendSorted)
{
SortDescription extSort = new SortDescription("Name", ListSortDirection.Ascending);
grdExtendedNames.Items.SortDescriptions.Add(extSort);
extendSorted = true;
}
Hope that helps someone else sort their datagrid via code. Most of the other examples we found worked fine for simple setups, but in this dual-datagrid tabbed setup it threw the sorting out of whack.
I had a similar problem, when inserting a new row into a DataGrid. I solved this issue by refreshing the items of the DataGrid.
dataGrid.Items.Refresh(). This restores also the sorting.
Don't forget to set the SortDirection at the DataGridColumn (in this case it's a DataGridTextColumn)
DataGrid definition:
<DataGrid x:Name="dgCustomers" ItemsSource="{Binding CustomerTable}" AutoGenerateColumns="False" CanUserDeleteRows="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Kunden ID" Binding="{Binding Path=KundenID,Mode=TwoWay}" SortDirection="Ascending" />
<DataGridTextColumn Header="Name" Binding="{Binding Path=Kundenname,Mode=TwoWay}"/>
</DataGrid.Columns>
</DataGrid>
CS file:
private void btnSavecustomerChanges_Click(object sender, RoutedEventArgs e)
{
try
{
BL.UpdateCustomerChanges();
dgCustomers.Items.Refresh();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Fehler beim Speichern", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
If DataGridMain.Items.SortDescriptions.Count > 0 Then
Dim vSortDescColl As New SortDescriptionCollection
For Each vSortDesc In DataGridMain.Items.SortDescriptions
vSortDescColl.Add(vSortDesc)
Next
DataGridMain.ItemsSource = Nothing
DataGridMain.ItemsSource = vCallColl
For Each vSortDesc In vSortDescColl
DataGridMain.Items.SortDescriptions.Add(vSortDesc)
For Each vColumn In DataGridMain.Columns
If vColumn.SortMemberPath = vSortDesc.PropertyName Then
vColumn.SortDirection = vSortDesc.Direction
Exit For
End If
Next
Next
End If
精彩评论