none
WPF DataGrid Binding

    Question

  • How can I make the DataGrid autosort when it was changed from outside the control?

    To reproduce my problem using the sample code below:
    1. Click the header of the FirstName column of DataGrid to sort
    2. In the datagrid, change "Jenny" to "Benny".
    3. Note that after chaning the FirstName, the DataGrid automatically sorts the items to the correct order.
    4. Now again select "Benny" and change the value back to "Jenny" using the bounded textbox control.
    5. Note that the DataGrid changes the value of the FirstName but without sorting the items.

    XAML:

    <Window x:Class="MainWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      Title="MainWindow" SizeToContent="WidthAndHeight">
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition/>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <DataGrid Name="DataGrid1" Grid.Column="0" ItemsSource="{Binding}"/>
        <TextBox Name="TextBox1" Grid.Column="1" Width="100" Height="23" Margin="10"
             Text="{Binding ElementName=DataGrid1, Path=SelectedItem.FirstName}"/>
      </Grid>
    </Window>

    VB

    Imports System.Collections.ObjectModel
    
    Class MainWindow
    
      Public Property Persons As ObservableCollection(Of Person)
    
      Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
        Persons = New ObservableCollection(Of Person) From
              {New Person With {.FirstName = "John", .LastName = "Doe"},
               New Person With {.FirstName = "James", .LastName = "Long"},
               New Person With {.FirstName = "Albert", .LastName = "Rice"},
               New Person With {.FirstName = "Jenny", .LastName = "Jordan"}}
    
        DataContext = Persons
      End Sub
    
    End Class
    
    Public Class Person
    
      Public Property FirstName As String
      Public Property LastName As String
    
    End Class

    Tuesday, March 22, 2011 9:38 AM

Answers

  • >>Thinking out loud here, but if your remember the sort description when its changed you could probably reapply it after
    >>the property is changed.  Not elegant.

    Hmm, I think this would work with the INotifyPropertyChanged of the class. I could create a handler to the PropertyChanged event. If the modified property is in the datagrid sortdescription, I could reapply it to force the datagrid to sort.

    >>Remember it in the Sorting event of the datagrid.

    I think I could just save the sortdescription before clearing and reapply it.
    i.e.
            Dim s As System.ComponentModel.SortDescription = DataGrid1.Items.SortDescriptions(0)
            DataGrid1.Items.SortDescriptions.Clear()
            DataGrid1.Items.SortDescriptions.Add(s)


    But I still hope that it is possible to inform the DataGrid of the update since it will be more efficient.
    Tuesday, March 22, 2011 4:32 PM

All replies

  • You just need to use Datagrid.Items.Refresh()

    I think in the CellEditEnding event.

    You might of course find some unattractive side effects.

    Tuesday, March 22, 2011 12:38 PM
  • >>I think in the CellEditEnding event.

    On the datagrid control? The control actually auto sorts when data is changed using the datagrid. But if the data was changed from outside the datagrid (i.e. TextBox), the changes is reflected on the datagrid but it doesn't automatically sort the data.

     

    Is there no way to notify the datagrid that the collection was changed? Maybe implementing INotifyPropertyChanged?


    Tuesday, March 22, 2011 1:27 PM
  • I also tried using datagrid.items.refresh on the lostfocus event of the textbox but still no sorting occurs.
    Tuesday, March 22, 2011 1:30 PM
  • Oh, sorry I was distracted by someone as I was thinking about the answer and forgot you change in a separate control.

    Datagrid.Items.Refresh()

    Should force it.  I've never relied on an automatic sort like that though.

    Maybe you need somewhat more code and a more explicit sort.

    http://waxtadpole.wordpress.com/2009/11/04/wpf-setting-default-sort-order-for-datagrid-without-using-a-static-resource/ 

    Tuesday, March 22, 2011 1:46 PM
  • Datagrid.Items.Refresh()

    I have actually tried that on the textbox's lost focus event, but it doesn't work. I even tried creating a new button just to call that function but still no sorting occurs.

     

    >>Maybe you need somewhat more code and a more explicit sort.

    I read the link you posted. But it seems that it is used for creating a default sort order. I need to allow users to click on the column header to choose the sort column, and that will override the sort order of the view.

     

    The auto sort of the datagrid work perfectly when it was modified within the control. Is there no way to notify the data grid that a specific item was updated?

    Tuesday, March 22, 2011 2:55 PM
  • Your Person class needs to Implement INotifyPropertyChanged. 

    Public Class Person
      Implements INotifyPropertyChanged
    
    
      Private _firstname As String
      Public Property FirstName As String
        Get
          Return _firstname
        End Get
        Set(ByVal value As String)
          _firstname = value
          RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("FirstName"))
        End Set
      End Property
    
      Private _lastname As String
      Public Property LastName As String
        Get
          Return _lastname
        End Get
        Set(ByVal value As String)
          _lastname = value
          RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("LastName"))
        End Set
      End Property
    
      Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
    
    End Class
    

    Tuesday, March 22, 2011 3:06 PM
  • Remember to import ComponentModel:

    Imports System.ComponentModel
    

     

    Tuesday, March 22, 2011 3:08 PM
  • I replaced the Person class in the sample code with the one you posted. But it still doesn't work. Is there anything else I need to add/change?
    Tuesday, March 22, 2011 3:22 PM
  • Sorry, the DataGrid does not have live sorting (probably for performance reasons).  I remember running into this myself a while back, I ended up managing the sorting on my List myself using a Comparer.   Persons.ToList.Sort(Comparer here).  Sorting is slow, if you have alot of rows this will become a larger issue.
    Tuesday, March 22, 2011 3:46 PM
  • Thinking out loud here, but if your remember the sort description when its changed you could probably reapply it after the property is changed.  Not elegant.

    Remember it in the Sorting event of the datagrid.

     DataGrid1.Items.SortDescriptions.Clear()
     DataGrid1.Items.SortDescriptions.Add(New SortDescription("FirstName", ListSortDirection.Descending))
    

    Tuesday, March 22, 2011 3:55 PM
  • But the DataGrid automatically sorts the updated row when modified from the DataGrid. It only sorts the modified row and not the whole collection so it should be the most efficient solution possible.

    Here's an example using my sample app to show what I mean:

    1. Click header of FirstName to sort.

    Result: Albert, James, Jenny, John

    2. Select "Jenny" and change to "Benny" using TextBox.

    Result: Albert, James, Benny, John

    3. Select "Albert" and change to "Ron" using DataGrid.

    Result: James, Benny, John, Ron

     

    The updated item "Ron" was positioned on the last row while the other rows are not sorted which shows that only a single row was actually sorted. I believe that this is the most efficient solution especially on large collections.

     

    Is this possible to "notify" the DataGrid that an item was updated even if I have to call it manually?

    Tuesday, March 22, 2011 4:08 PM
  • >>Thinking out loud here, but if your remember the sort description when its changed you could probably reapply it after
    >>the property is changed.  Not elegant.

    Hmm, I think this would work with the INotifyPropertyChanged of the class. I could create a handler to the PropertyChanged event. If the modified property is in the datagrid sortdescription, I could reapply it to force the datagrid to sort.

    >>Remember it in the Sorting event of the datagrid.

    I think I could just save the sortdescription before clearing and reapply it.
    i.e.
            Dim s As System.ComponentModel.SortDescription = DataGrid1.Items.SortDescriptions(0)
            DataGrid1.Items.SortDescriptions.Clear()
            DataGrid1.Items.SortDescriptions.Add(s)


    But I still hope that it is possible to inform the DataGrid of the update since it will be more efficient.
    Tuesday, March 22, 2011 4:32 PM
  • Hi JLH85,

    Thank you for your helpful feedback.

    On the other hand, I think your issue has been resolved, could I close this thread?

     

    Best regards,


    Sheldon _Xiao[MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, March 24, 2011 10:46 AM
    Moderator
  • I actually ended up removing the modified item from the collection and insert it back. This triggers the CollectionChanged event of the ObservableCollection and "informs" the DataGrid to sort the item.

     

    Thanks for all the suggestions. You can close this thread now.

    Thursday, March 24, 2011 1:46 PM