Thomasian
asked on
WPF DataGrid Binding
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 Code:
VB Code:
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 Code:
<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 Code:
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
ASKER
How do I modify the sample code to make that work?
Hi, your Person class must implement INotifyPropertyChanged, c# sample:
public class Person : EventBase
{
private string firstName;
public string FirstName
{
get { return firstName; }
set
{
firstName = value;
PropertyChangedHandler("FirstName");
}
}
public string LastName { get; set; }
}
public abstract class EventBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void PropertyChangedHandler(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
and one more:
private void TextBox1_TextChanged(object sender, TextChangedEventArgs e)
{
Dispatcher.BeginInvoke(()=>((Person) DataGrid1.SelectedItem).FirstName = TextBox1.Text);
}
ASKER
>>Dispatcher.BeginInvoke(( )=>((Perso n) DataGrid1.SelectedItem).Fi rstName = TextBox1.Text);
I couldn't make this line work so I changed it to
((Person)DataGrid1.Selecte dItem).Fir stName = TextBox1.Text;
Here's the code I tested, but it still doesn't automatically sort the datagrid.
WPF Code:
I couldn't make this line work so I changed it to
((Person)DataGrid1.Selecte
Here's the code I tested, but it still doesn't automatically sort the datagrid.
WPF Code:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" SizeToContent="WidthAndHeight" Loaded="Window_Loaded">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<DataGrid Name="DataGrid1" Grid.Column="0" ItemsSource="{Binding}" CanUserAddRows="False" />
<TextBox Name="TextBox1" Grid.Column="1" Width="100" Height="23" Margin="10"
Text="{Binding ElementName=DataGrid1, Path=SelectedItem.FirstName}"/>
</Grid>
</Window>
C# Codeusing System.Windows;
using System.Windows.Controls;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public class Person : EventBase
{
private string firstName;
public string FirstName
{
get { return firstName; }
set
{
firstName = value;
PropertyChangedHandler("FirstName");
}
}
public string LastName { get; set; }
}
public abstract class EventBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void PropertyChangedHandler(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ObservableCollection<Person> persons = new ObservableCollection<Person>
{
new Person {FirstName = "John", LastName = "Doe"},
new Person {FirstName = "James", LastName = "Long"},
new Person {FirstName = "Albert", LastName = "Rice"},
new Person {FirstName = "Jenny", LastName = "Jordan"}
};
DataContext = persons;
}
private void TextBox1_TextChanged(object sender, TextChangedEventArgs e)
{
((Person)DataGrid1.SelectedItem).FirstName = TextBox1.Text;
}
}
}
ASKER
I forgot to include
TextChanged="TextBox1_Text Changed"
on the TextBox xaml code. But it still doesn't work. The data changes but no sorting
TextChanged="TextBox1_Text
on the TextBox xaml code. But it still doesn't work. The data changes but no sorting
sorry, forgot about main:
<UserControl.Resources>
<CollectionViewSource x:Name="viewSource"></CollectionViewSource>
</UserControl.Resources>
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
Persons = new ObservableCollection<Person>
{
new Person {FirstName = "John", LastName = "Doe"},
new Person {FirstName = "James", LastName = "Long"},
new Person {FirstName = "Albert", LastName = "Rice"},
new Person {FirstName = "Jenny", LastName = "Jordan"}
};
viewSource.Source = Persons;
viewSource.View.SortDescriptions.Clear();
viewSource.View.SortDescriptions.Add(new SortDescription("FirstName",ListSortDirection.Ascending));
DataGrid1.DataContext = viewSource;
TextBox1.DataContext = DataGrid1;
}
private string last;
private int selection;
private void TextBox1_TextChanged(object sender, TextChangedEventArgs e)
{
if (last != TextBox1.Text)
{
last = TextBox1.Text;
selection = TextBox1.SelectionStart;
((Person)DataGrid1.SelectedItem).FirstName = TextBox1.Text;
viewSource.View.Refresh();
TextBox1.SelectionStart = selection;
}
}
ASKER
I changed the xaml code to:
<Window.Resources>
<CollectionViewSource x:Name="viewSource" />
</Window.Resources>
When I added the resource to the xaml code, it is giving me errors:
All objects added to an IDictionary must have a Key attribute or some other type of key associated with them. Line 6 Position 10.
Have you tried the code? If you did, can you post the whole xaml and csharp code?
Thanks
<Window.Resources>
<CollectionViewSource x:Name="viewSource" />
</Window.Resources>
When I added the resource to the xaml code, it is giving me errors:
All objects added to an IDictionary must have a Key attribute or some other type of key associated with them. Line 6 Position 10.
Have you tried the code? If you did, can you post the whole xaml and csharp code?
Thanks
Not my day. previous code was for Silverlight, this is for WPF:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="UserControl_Loaded">
<Grid x:Name="LayoutRoot" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<DataGrid Height="300" Width="300" Name="DataGrid1" Grid.Column="0" ItemsSource="{Binding}" />
<TextBox Name="TextBox1" Grid.Column="1" Width="100" Height="23" Margin="10" TextChanged="TextBox1_TextChanged"
Text="{Binding ElementName=DataGrid1, Path=SelectedItem.FirstName, Mode=TwoWay}"/>
</Grid>
</Window>
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public ObservableCollection<Person> Persons = new ObservableCollection<Person>
{
new Person {FirstName = "John", LastName = "Doe"},
new Person {FirstName = "James", LastName = "Long"},
new Person {FirstName = "Albert", LastName = "Rice"},
new Person {FirstName = "Jenny", LastName = "Jordan"}
};
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
DataGrid1.ItemsSource = Persons;
TextBox1.DataContext = DataGrid1;
}
CollectionView viewSource = null;
private string last;
private int selection;
private void TextBox1_TextChanged(object sender, TextChangedEventArgs e)
{
if (last != TextBox1.Text)
{
last = TextBox1.Text;
selection = TextBox1.SelectionStart;
((Person)DataGrid1.SelectedItem).FirstName = TextBox1.Text;
TextBox1.SelectionStart = selection;
}
}
}
public class Person : EventBase
{
private string firstName;
public string FirstName
{
get { return firstName; }
set
{
firstName = value;
PropertyChangedHandler("FirstName");
}
}
public string LastName { get; set; }
}
public abstract class EventBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void PropertyChangedHandler(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
ASKER
I copied and pasted the exact codes you posted, but still no auto sort..
To replicate:
1. Click the header button of FirstName column to sort
2. Click on item "Jenny"
3. Change the name to "Benny" using the textbox.
4. The data on the datagrid is updated but no sorting occurs
Note that if you follow the same steps but edit the name using the datagrid control, the control automatically sorts the data in the correct order.
To replicate:
1. Click the header button of FirstName column to sort
2. Click on item "Jenny"
3. Change the name to "Benny" using the textbox.
4. The data on the datagrid is updated but no sorting occurs
Note that if you follow the same steps but edit the name using the datagrid control, the control automatically sorts the data in the correct order.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
I need to be able to let the user select the sort column and direction.
i.e. The user can click the header for Last Name to sort by the last name. So changing the first name should not affect the sort order.
i.e. The user can click the header for Last Name to sort by the last name. So changing the first name should not affect the sort order.
http://www.dotnetcurry.com/ShowArticle.aspx?ID=563