我在ViewModel中订购一个可观察的集合时遇到了一些困难。 这是我的情况:
在我的视图模型中,我有以下列表:
public List<TicketModel> Tickets
{
get { return _Tickets.Value; }
set
{
{
this.RaiseAndSetIfChanged(c => c.Tickets, value);
}
}
}
private ObservableAsPropertyHelper<List<TicketModel>> _Tickets;
此列表使用ReactiveAsyncCommand
:
LoadTickets.RegisterAsyncFunction(x => loadTickets())
.ToProperty(this, x => x.Tickets);
到目前为止一直有效。
我有另一个命令SortByCommand
,只要用户想要对集合进行排序,就会调用它。该命令如下所示:
SortByCommand = new ReactiveCommand(this.WhenAny(c => c.Tickets, ((tickets) => tickets.Value != null && tickets.Value.Count > 0)));
SortByCommand.Subscribe(c => sortTickets((SortByModel)c));
该命令还调用一个函数,该函数使用order by子句对集合进行排序:
private void sortTickets(SortByModel model)
{
Tickets = Tickets.OrderBy(model.Selector).ToList();
}
每当调用sortTickets
函数时,都会抛出一个异常:
Unable to cast object of type 'ReactiveUI.ObservableAsPropertyHelper`1[System.Collections.Generic.List`1[Bugmine.Modules.MyPage.Models.TicketModel]]' to type 'System.Collections.Generic.List`1[Bugmine.Modules.MyPage.Models.TicketModel]'.
我有几个问题:
1)为什么我不能直接设置Tickets
模型?我是否需要先将OrderBy
的结果转换为某种可观察的集合?
2)有更好的方法吗?
编辑:澄清
我现在采取的方法是:
一旦调用Tickets
函数,我将按以下方式对此集合进行排序和重置:
sortTickets
再次加载Tickets = Tickets.OrderBy(c => c.Name).ToList(); //for example
集合时,我会检查是否应对其进行排序并在设置Tickets
属性之前对其进行排序。
这感觉有点hacky因为我基本上设置了两个点 - 在加载和排序时。此外,加载后我使用ReactiveUI帮助程序 - &gt; ToProperty:
Tickets
然而,在排序时我自己也这样做了:
LoadTickets.RegisterAsyncFunction(x => loadTickets())
.ToProperty(this, x => x.Tickets);
我想知道是否有更好的方法使用我在加载时已经使用的ReactiveUI方法进行排序。
提前致谢!
答案 0 :(得分:2)
//
// This is the canonical way to make a read-only property whose value
// is backed by an IObservable
//
ObservableAsPropertyHelper<List<FlickrPhoto>> _Photos;
我认为只读是那里的重点。
相反,您可以尝试使用普通的observable,您可以使用OnNext来推送新值
private Observable<List<TicketModel>> _Tickets = new Observable<Lis<TicketModel>>();
_Tickets.OnNext(newValue);
或使用ObservableForProperty&lt;&gt;并且通常只使用该属性
public List<TicketModel> _Tickets { get;set;}
private Observable<List<TicketModel>> _ticketsObservable= ObservableForProperty<..>(x=>x.Tickets);
这两个方法都公开了一个Observable,我们可以在以后的排序中使用它。
为什么不尝试以同样的方式处理你的排序中的两个输入,然后它不会觉得如此hacky。那样你也会有一个
public SortModel SortModel {get;set;}
您的排序命令实现变为
SortByCommand.Subscribe(c => _Sort = c));
但随后您将票证更改和排序条件更改合并为一个,请参阅http://rxwiki.wikidot.com/101samples#toc44了解CombineLatest
new ObservableForProperty<..>(x=>x.SortModel)
.CombineLatest(_ticketsObservable)
.Subscribe( (x,y)=>
{
//Refactor to SortMethod
_tickets = y.OrderBy(x.Selector);
});
答案 1 :(得分:2)
解决此问题的另一种方法是通过CreateDerivedCollection
:
SortedTickets = Tickets.CreateDerivedCollection(
x => new TicketViewModel(x),
orderer: (l,r) => SortModel.Selector(l, r), // Returns CompareTo() result
signalReset: this.WhenAny(x => x.SortModel, x => x.Value)); // Reorder on SortModel change
请注意,如果Tickets
重复设置(在这种情况下),则会出现故障 - 您可能会将模型更改为初始化ctor中的Tickets
,然后清除并添加所有项目,即
LoadTickets.RegisterAsyncFunction(x => loadTickets())
.Subscribe(x => {
// TODO: Make sure Tickets is a ReactiveCollection
Tickets.Clear();
Tickets.AddRange(x); // Will trigger resorting of SortedTickets
});
答案 2 :(得分:0)
Tickets = new ObservableCollection&lt; ...&gt;(Tickets.OrderBy(...));
P.S。另外,请确保在添加其他故障单时测试了排序列表中发生的情况,但不能只是