关于c#:WPF DataGrid绑定到ItemsSource项目属性

您所在的位置:网站首页 wpfdatagrid异步绑定 关于c#:WPF DataGrid绑定到ItemsSource项目属性

关于c#:WPF DataGrid绑定到ItemsSource项目属性

2023-08-23 22:27| 来源: 网络整理| 查看: 265

我有实现IList的集合,该集合从服务器异步加载数据。 当索引访问该集合时,它将返回一个存根对象,并在后台启动数据请求。 请求完成后,集合将刷新内部状态并调用PropertyChanged事件。 现在,集合返回的项目如下所示:

12345678public class VirtualCollectionItem {     // actual entity     public object Item { get; }     // some metadata properties     public bool IsLoading { get; } }

问题是我无法意识到如何将此类集合绑定到DataGrid。 我想以某种方式将DataGrid.ItemsSource设置为VirtualCollectionItem的集合,使DataGrid显示实际项目(也在SelectedItem中),并保留使用元数据的可能性(即使用IsLoading可视化数据加载)。 我试图在DataGrid.RowStyle中设置DataGridRow.Item绑定,但是没有用。

123456789101112                                                      

另一个选择是将VirtualCollectionItem属性展平为VirtualCollection本身:

1234567891011class VirtualCollection {     // ...     // wrapper around VirtualCollectionItem     public IList Items { get; }     public IList IsLoadingItems { get; }     // ... }

并在DataGrid中使用这些属性,但是我还没有意识到如何使它起作用。

好的,因此您可以从服务器加载实体,但是仍然需要从ViewModel访问集合。让我们将此功能移至服务。该服务允许您异步加载实体ID列表,或加载特定的实体详细信息:

1234567891011121314151617181920212223242526272829303132333435363738using AsyncLoadingCollection.DTO; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; public class PeopleService {     private List _people;     public PeopleService()     {         InitializePeople();     }     public async Task GetIds()     {         // simulate async loading delay         await Task.Delay(1000);         var result = _people.Select(p => p.Id).ToList();         return result;     }     public async Task GetPersonDetail(int id)     {         // simulate async loading delay         await Task.Delay(3000);         var person = _people.Where(p => p.Id == id).First();         return person;     }     private void InitializePeople()     {         // poor person's database         _people = new List();         _people.Add(new PersonDTO { Name ="Homer", Age = 39, Id = 1 });         _people.Add(new PersonDTO { Name ="Marge", Age = 37, Id = 2 });         _people.Add(new PersonDTO { Name ="Bart", Age = 12, Id = 3 });         _people.Add(new PersonDTO { Name ="Lisa", Age = 10, Id = 4 });     } }

GetPersonDetail方法返回一个DTO:

1234567public class PersonDTO {     public string Name { get; set; }     public int Age { get; set; }     public int Id { get; set; } }

可以将DTO转换为您的ViewModel所需的对象(并且我将Prism用作MVVM框架):

1234567891011121314151617181920212223242526272829303132using Prism.Mvvm; public class Person : BindableBase {     private string _name;     public string Name     {         get { return _name; }         set { SetProperty(ref _name, value); }     }     private int _age;     public int Age     {         get { return _age; }         set { SetProperty(ref _age, value); }     }     private int _id;     public int Id     {         get { return _id; }         set { SetProperty(ref _id, value); }     }     private bool _isLoaded;     public bool IsLoaded     {         get { return _isLoaded; }         set { SetProperty(ref _isLoaded, value); }     } }

您可以像这样将DTO对象转换为Model:

1234567891011121314151617using DTO; using Model; // we might use AutoMapper instead public static class PersonConverter {     public static Person ToModel(this PersonDTO dto)     {         Person result = new Person         {             Id = dto.Id,             Name = dto.Name,             Age = dto.Age         };         return result;     } }

这就是我们在ViewModel中定义命令(使用项目检索服务)的方式:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091using Helpers; using Model; using Prism.Commands; using Prism.Mvvm; using Services; using System.Collections.ObjectModel; using System.Linq; public class MainWindowViewModel : BindableBase {     #region Fields     private  PeopleService _peopleService;     #endregion // Fields     #region Constructors     public MainWindowViewModel()     {         // we might use dependency injection instead         _peopleService = new PeopleService();         People = new ObservableCollection();         LoadListCommand = new DelegateCommand(LoadList);         LoadPersonDetailsCommand = new DelegateCommand(LoadPersonDetails, CanLoadPersonDetails)             .ObservesProperty(() => CurrentPerson)             .ObservesProperty(() => IsBusy);     }     #endregion // Constructors     #region Properties     private string _title ="Prism Unity Application";     public string Title     {         get { return _title; }         set { SetProperty(ref _title, value); }     }     private Person _currentPerson;     public Person CurrentPerson     {         get { return _currentPerson; }         set { SetProperty(ref _currentPerson, value); }     }     private bool _isBusy;     public bool IsBusy     {         get { return _isBusy; }         set { SetProperty(ref _isBusy, value); }     }     public ObservableCollection People { get; private set; }     #endregion // Properties     #region Commands     public DelegateCommand LoadListCommand { get; private set; }     private async void LoadList()     {         // reset the collection         People.Clear();         var ids = await _peopleService.GetIds();         var peopleListStub = ids.Select(i => new Person { Id = i, IsLoaded = false, Name ="No details" });         People.AddRange(peopleListStub);     }     public DelegateCommand LoadPersonDetailsCommand { get; private set; }     private bool CanLoadPersonDetails()     {         return ((CurrentPerson != null) && !IsBusy);     }     private async void LoadPersonDetails()     {         IsBusy = true;         var personDTO = await _peopleService.GetPersonDetail(CurrentPerson.Id);         var updatedPerson = personDTO.ToModel();         updatedPerson.IsLoaded = true;         var oldPersonIndex = People.IndexOf(CurrentPerson);         People.RemoveAt(oldPersonIndex);         People.Insert(oldPersonIndex, updatedPerson);         CurrentPerson = updatedPerson;         IsBusy = false;     }     #endregion // Commands }

最后,View可能像这样简单:

1234567891011121314151617181920212223242526272829303132333435363738394041                                                                                                                                                                                                                                                    

我决定用ViewModel包装DataGrid:

1234567891011121314151617181920public class DataGridAsyncViewModel : Notifier {   public VirtualCollection ItemsProvider { get; }   private VirtualCollectionItem _selectedGridItem;   public VirtualCollectionItem SelectedGridItem   {     get { return _selectedGridItem; }     set { Set(ref _selectedGridItem, value); }   }   public object SelectedItem => SelectedGridItem?.IsLoading == false ? SelectedGridItem?.Item : null;   public DataGridAsyncViewModel([NotNull] VirtualCollection itemsProvider)   {     if (itemsProvider == null) throw new ArgumentNullException(nameof(itemsProvider));     ItemsProvider = itemsProvider;   } }

并将其绑定到DataGrid:

12345678910111213141516                                                          

您可以将VirtualCollection直接绑定到DataGrid.ItemsSource属性。然后也绑定SelectedItem属性:

1

然后是ViewModel:

123456789101112131415161718192021222324252627282930313233public class MyViewModel : INotifyPropertyChanged {     public event PropertyChangedEventHandler PropertyChanged;     protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)     {         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));     }     private VirtualCollection _myVirtualCollectionList;     public VirtualCollection MyVirtualCollectionList     {         get { return _myVirtualCollectionList; }         set         {             _myVirtualCollectionList = value;             OnPropertyChanged();         }     }     private VirtualCollectionItem _selectedItem;     public VirtualCollectionItem SelectedItem     {         get { return _selectedItem; }         set         {             _selectedItem = value;             OnPropertyChanged();         }     } }

您必须在加载列表后触发OnPropertyChanged事件,并且必须从MyViewModel对象执行此操作(我认为您不这样做)!您也可以使用ObservableCollection(可以扩展它)。然后,您不需要OnPropertyChange事件。从集合中添加/删除项目会自动通知UI。

SelectedItem与列表无关。在数据模板的一行中,您将使用{Binding IsLoading}和{Binding Item.SomeProperty}。

相关讨论 在我的情况下,DataGrids Items / SelectedItem(s)必须是从服务器加载的实际实体,因此我可以使用它而无需重写大量现有代码库。 我还在需要时调用PropertyChanged和CollectionChanged事件。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3