我有一个通过单击标题按用户排序的DataGrid。 选择一个项目后,我必须从数据源刷新它。
当我替换ItemsSource中的新项目时,该行正在移动。 排序必须在一列上,该列的所有项目都必须具有相同的值。
MainWindow.xaml
<Window x:Class="WpfApp4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:WpfApp4"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
DataContext="{DynamicResource ResourceKey=viewModel}">
<Window.Resources>
<vm:MainWindowViewModel x:Key="viewModel" />
</Window.Resources>
<Grid>
<DataGrid AutoGenerateColumns="True" CanUserSortColumns="True"
ItemsSource="{Binding Persons}" SelectedItem="{Binding SelectedPerson}"/>
</Grid>
MainWindowViewModel.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace WpfApp4
{
public class MainWindowViewModel : INotifyPropertyChanged
{
public MainWindowViewModel()
{
Persons = new ObservableCollection<Person>()
{
new Person()
{
Name = "Foo", Age = 10
},
new Person()
{
Name = "Bar", Age = 10
},
new Person()
{
Name = "Yolo", Age = 10
},
};
}
private ObservableCollection<Person> _persons;
public ObservableCollection<Person> Persons
{
get => _persons;
set
{
_persons = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Persons"));
}
}
private Person _selectedPerson;
public Person SelectedPerson
{
get => _selectedPerson;
set
{
_selectedPerson = value;
SelectedPersonChanged();
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedPerson"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void SelectedPersonChanged()
{
if (SelectedPerson != null)
{
//Get a refreshed instance of person from DataSource
//For the purpose of the example, we admit that the values are the same
Person updatedPerson = new Person() { Age = SelectedPerson.Age, Name = SelectedPerson.Name };
//Update in collection
int previousIndex = Persons.IndexOf(SelectedPerson);
Persons[previousIndex] = updatedPerson;
_selectedPerson = updatedPerson;
}
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
}
实时示例:
任何想法如何在不破坏行顺序的情况下替换项目吗?
谢谢
修改
我最终使用AutoMapper将Person从数据源复制到SelectedPerson。
在ViewModel构造函数中:
Mapper.Initialize(cfg => cfg.CreateMap<Person, Person>());
private void SelectedPersonChanged()
{
if (SelectedPerson != null)
{
//Get a refreshed instance of person from DataSource
//For the purpose of the example, we admit that the values are the same
Person updatedPerson = new Person()
{
Age = SelectedPerson.Age, Name = SelectedPerson.Name
};
Mapper.Map(updatedPerson, SelectedPerson);
}
}
答案 0 :(得分:0)
我认为更好的方法是编辑现有实例,而不是删除它并添加新实例。
只需使Person实现INotifyPropertyChanged
并编辑属性即可。
private void SelectedPersonChanged()
{
if (SelectedPerson != null)
{
var personFromDB = GetFromDB(SelectedPerson.Id);
SelectedPerson.Age = personFromDB.Age;
SelectedPerson.Name = personFromDB.Name;
}
}
答案 1 :(得分:0)
您可以尝试按多个字段进行排序。如果您的数据具有一个id字段或其他唯一不变的字段,则可能效果最好。否则,如果从数据库中重新加载名称时,该名称仍可能会跳动。
在这里,您可以使用列出的两个字段(年龄/姓名)来做到这一点。当您按年龄排序时,将添加按名称的辅助排序。并且,当您按名称排序时,会添加按年龄排序的辅助排序。
xaml:
<DataGrid AutoGenerateColumns="True" CanUserSortColumns="True"
Sorting="DataGrid_Sorting"
ItemsSource="{Binding Persons}" SelectedItem="{Binding SelectedPerson}"/>
代码:
private void DataGrid_Sorting(object sender, DataGridSortingEventArgs e)
{
var v = CollectionViewSource.GetDefaultView((sender as DataGrid).ItemsSource);
v.SortDescriptions.Clear();
// Set column sort direction - otherwise you won't see the arrow on the column header
if (!e.Column.SortDirection.HasValue)
e.Column.SortDirection = ListSortDirection.Descending;
e.Column.SortDirection = e.Column.SortDirection.Value == ListSortDirection.Ascending ? ListSortDirection.Descending : ListSortDirection.Ascending;
// Add sort description
v.SortDescriptions.Add(new SortDescription(e.Column.SortMemberPath, e.Column.SortDirection.Value));
// Add secondary sort description (age or name)
var secondarySort = e.Column.SortMemberPath == "Age" ? "Name" : "Age";
v.SortDescriptions.Add(new SortDescription(secondarySort, ListSortDirection.Ascending));
// Add more sort descriptions, as needed.
// We handled it...
e.Handled = true;
}