给出以下视图模型:
public class AttachmentsViewModel : ReactiveObject, ISupportsActivation
{
private ReactiveList<Attachment> _attachments;
public ReactiveList<Attachment> Attachments
{
get => _attachments;
set => this.RaiseAndSetIfChanged( ref _attachments, value );
}
private IReactiveDerivedList<AttachmentViewModel> _attachmentViewModels;
public IReactiveDerivedList<AttachmentViewModel> AttachmentViewModels
{
get => _attachmentViewModels;
set => this.RaiseAndSetIfChanged(ref _attachmentViewModels, value );
}
private AttachmentViewModel _selected;
public AttachmentViewModel Selected
{
get => _selected;
set => this.RaiseAndSetIfChanged( ref _selected, value );
}
}
使用以下代码设置 Attachments
和AttachmentViewModels
:
var items = DataManager.GetAttachmentsList();
Attachments = new ReactiveList<Attachment>( items ) { ChangeTrackingEnabled = true };
AttachmentViewModels = Attachments.CreateDerivedCollection( x => new AttachmentViewModel(x) );
AttachmentViewModels
绑定到ListView
:
this.OneWayBind( ViewModel, vm => vm.AttachmentViewModels, v => v.List.ItemsSource );
this.Bind( ViewModel, vm => vm.Selected, v => v.List.SelectedItem );
但是,如果我通过AttachmentViewModel更新其中一个附件,那么因为Attachments.ChangeTrackingEnabled
设置为true,所以AttachmentViewModels.CollectionChanged
被触发。出于某种原因,这会将List.SelectedItem
设置为null
。
有没有办法避免这种行为?另一个SO post意味着这可能是因为我没有在AttachmentViewModel
中实现适当的相等运算符。我试着遵循这个建议,但似乎没有帮助。
另外,我必须将ListView.IsSynchronizedWithCurrentItem
设置为true - 否则ListView
将无法保留原始选择。但是,这不会阻止SelectedItem
设置为null
,只是意味着它被设置了两次。一次到null
,然后再回到原始选择。这没关系,除非在SelectedItem
更改时导致UI出现视觉故障。
答案 0 :(得分:1)
当ReactiveList
中的项目的属性发生变化且ChangeTrackingEnabled
为true
时,CollectionChanged
事件将被触发。对于关联的IReactiveDerivedList
,这意味着将重新创建整个集合。由于生成了新的AttachmentViewModel
(对于相同的Attachment
),SelectedItem
不再指向列表中的项目。它的默认行为是成为null
。
通过实现缓存,可以重新设置相同的AttachmentViewModel
- 尽管收集更改事件。
基于此ReactiveUI issue,这是我实施的内容:
public class AttachmentsViewModel : ReactiveObject
{
private readonly Dictionary<Attachment, AttachmentViewModel> _cache = new Dictionary<Attachment, AttachmentViewModel>();
private ReactiveList<Attachment> _attachments;
public ReactiveList<Attachment> Attachments
{
get => _attachments;
set => this.RaiseAndSetIfChanged( ref _attachments, value );
}
private IReactiveDerivedList<AttachmentViewModel> _attachmentViewModels;
public IReactiveDerivedList<AttachmentViewModel> AttachmentViewModels
{
get => _attachmentViewModels;
set => this.RaiseAndSetIfChanged(ref _attachmentViewModels, value );
}
private AttachmentViewModel _selected;
public AttachmentViewModel Selected
{
get => _selected;
set => this.RaiseAndSetIfChanged( ref _selected, value );
}
public void LoadAttachments()
{
_cache.Clear();
var items = DataManager.GetAttachmentsList();
Attachments = new ReactiveList<Attachment>( items ) { ChangeTrackingEnabled = true };
AttachmentViewModels = Attachments.CreateDerivedCollection( x => {
AttachmentViewModel viewModel;
if ( _cache.ContainsKey(x) ) {
viewModel = _cache[x];
} else {
viewModel = new AttachmentViewModel( x );
_cache.Add( x, viewModel );
}
return viewModel;
});
}
}
请注意,Attachment
对象具有自己的相等运算符(基于ID
属性)。用户可以还原他们的更改,因此我必须添加_cache.Clear()
来补偿。