C# XAML自定义集合绑定异步集合更新
我有一个自定义类继承自C# XAML自定义集合绑定异步集合更新,c#,mvvm,data-binding,observablecollection,inotifypropertychanged,C#,Mvvm,Data Binding,Observablecollection,Inotifypropertychanged,我有一个自定义类继承自ObservableCollection和INotifyPropertyChanged(即自定义类也有属性),该类用作集合,其中T也继承自INotifyPropertyChanged: public class CustomCollection<T> : ObservableCollection<T>, INotifyPropertyChanged where T: INotifyPropertyChanged { private string _n
ObservableCollection
和INotifyPropertyChanged
(即自定义类也有属性),该类用作集合,其中T
也继承自INotifyPropertyChanged
:
public class CustomCollection<T> : ObservableCollection<T>, INotifyPropertyChanged where T: INotifyPropertyChanged {
private string _name;
public string Name {
get {
return _name;
}
set {
if (_name != value) {
_name = value;
NotifyPropertyChanged("Name");
}
}
}
private int _total;
public int Total {
get {
return _total;
}
set {
if (_total != value) {
_total = value;
NotifyPropertyChanged("Total");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName) {
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler) {
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
以及视图模型
:
public class ViewModel : ViewModelBase {
private readonly IService _dataService;
private bool _isLoading;
public bool IsLoading {
get {
return _isLoading;
}
private set {
_isLoading = value;
RaisePropertyChanged("IsLoading");
}
}
private CustomCollection<DataItem> _items;
public CustomCollection<DataItem> Items
{
get
{
return _items;
}
set
{
_items= value;
RaisePropertyChanged("Items");
}
}
public ViewModel(IService dataService) {
_dataService = dataService;
}
public void Refresh() {
if (!this.IsLoading) {
this.IsLoading = true;
_dataService.RefreshData(
this, (error) => {
if (error != null) {
return;
}
if (!IsInDesignMode)
this.IsLoading = false;
}
);
}
}
public void GetData() {
if (Games == null) {
Games = new CustomCollection<DataItem>();
} else {
Games.Clear();
}
if (!this.IsLoading) {
this.IsLoading = true;
_dataService.GetData(
this, (error) => {
if (error != null) {
return;
}
if (!IsInDesignMode)
this.IsLoading = false;
}
);
}
}
总之,考虑到我当前设置的CustomCollection
,如何使更新DataItem
的Value
立即反映在视图中?可能与async
有关?我的意思是,当调用Sleep(1000)
时,UI不会挂起,也许这与此有关
有没有办法解决这个问题?正如您可能已经猜到的,这个问题在第一次检索数据时也会出现(但在导航到视图的过程中检索/处理数据时,几乎不会引起注意)
注意:我正在使用。
谢谢。请注意:ObservableCollection已实现InotifyProperty更改。谢谢Willem,你确定吗?根据这条评论它没有?也根据那条评论它有。也根据MSDN和反射器;)啊,对不起,匆匆忙忙地浏览了一下,误读了!我在您的示例中看到的唯一循环是将服务返回的数据映射到模型项的循环。但这种逻辑应该非常快(尽管有睡眠)。所以我不认为担心UI是一次更新一个项目还是一次更新所有项目有什么意义。您是否有未提及的retrievedItems
服务结果?迭代那个对象慢吗?
public class ViewModel : ViewModelBase {
private readonly IService _dataService;
private bool _isLoading;
public bool IsLoading {
get {
return _isLoading;
}
private set {
_isLoading = value;
RaisePropertyChanged("IsLoading");
}
}
private CustomCollection<DataItem> _items;
public CustomCollection<DataItem> Items
{
get
{
return _items;
}
set
{
_items= value;
RaisePropertyChanged("Items");
}
}
public ViewModel(IService dataService) {
_dataService = dataService;
}
public void Refresh() {
if (!this.IsLoading) {
this.IsLoading = true;
_dataService.RefreshData(
this, (error) => {
if (error != null) {
return;
}
if (!IsInDesignMode)
this.IsLoading = false;
}
);
}
}
public void GetData() {
if (Games == null) {
Games = new CustomCollection<DataItem>();
} else {
Games.Clear();
}
if (!this.IsLoading) {
this.IsLoading = true;
_dataService.GetData(
this, (error) => {
if (error != null) {
return;
}
if (!IsInDesignMode)
this.IsLoading = false;
}
);
}
}
public async RefreshData(ViewModel model, Action<Exception> callback) {
if (model.Items == null) return;
// ... retrieve data from web service here (omitted) ...
foreach (DataItem item in retrievedItems) { // loop for each item in retrieved items
DataItem newItem = new DataItem() { Fname = item.Fname, Value = item.Value };
if (model.Items.contains(newItem)) { // override for .Equals in CustomCollection<T> allows for comparison by just Fname property
model.Items[model.Items.IndexOf(newItem)].Value += 10; // manual update
} else {
model.Items.Add(newItem);
}
System.Threading.Thread.Sleep(1000); // 1 second pause to "see" each item updated sequentially...
}
callback(null);
}