ReactiveUI を勉強するための簡単な WP7 アプリを書いています。画面にコレクションを表示したい、アイテムを選択可能にする必要があり、選択したすべてのアイテムをコレクションから削除するコマンドが必要です。また、コマンドは、選択された項目が少なくとも 1 つある場合にのみ実行可能でなければなりません。私はこのように定義されたコレクションを持っています:
Persons = model.Persons
.CreateDerivedCollection(x => new PersonViewModel(x));
私はPersonViewModel
プロパティを持っています:
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set { this.RaiseAndSetIfChanged(x => x.IsSelected, ref _isSelected, value); }
}
モデルの選択状態に関する情報はなく、viewModel だけです。Page ViewModel には、次のコードがあります。
Persons = model.Persons.CreateDerivedCollection(x => new PersonViewModel(x));
Persons.ChangeTrackingEnabled = true;
var deleteSelectedCanExecute = Persons.ItemChanged
.Select(_ => Persons .Any(p => p.IsSelected));
DeleteSelectedCommand = new ReactiveCommand
(
deleteSelectedCanExecute
);
DeleteSelectedCommand.Subscribe(
x => RemoveSelected()
);
そして方法:
private void RemoveSelected()
{
var res = Persons.Where(p => p.IsSelected)
.Select(x => x.Model).ToList();
foreach (var person in res)
{
_model.Persons.Remove(person);
}
}
最初の質問 (それほど重要ではありません。自分で解決策を見つけることができると思います): アプリを実行すると、DeleteSelected ボタンが Active.DeleteSelectedCommand.CanExecute になりません。ただし、アイテムを選択/選択解除した後、ボタンの状態は正常に機能します。
そして主な問題:
DeleteSelectedCommand を実行すると、選択したすべての項目が削除されます (デバッガーに表示されます)。そして、次のスタック トレースで「NotSupportedException」を取得しました。
at System.Threading.Interlocked.Decrement(Int64& location)
at ReactiveUI.RefcountDisposeWrapper.Release()
at ReactiveUI.ReactiveCollection`1.removeItemFromPropertyTracking(PersonViewModel toUntrack)
at ReactiveUI.ReactiveCollection`1.<setupRx>b__18(PersonViewModelx)
at System.Reactive.AnonymousObserver`1.Next(PersonViewModelvalue)
at System.Reactive.AbstractObserver`1.OnNext(PersonViewModelvalue)
at System.Reactive.AutoDetachObserver`1.Next(PersonViewModelvalue)
at System.Reactive.AbstractObserver`1.OnNext(PersonViewModelvalue)
at System.Reactive.ScheduledObserver`1.<>c__DisplayClass4.<Next>b__2()
at System.Reactive.ScheduledObserver`1.<EnsureActive>b__0(Action self)
at System.Reactive.Concurrency.Scheduler.<Schedule>b__0(Action`1 _action, Action`1 self)
at System.Reactive.Concurrency.Scheduler.<>c__DisplayClass9`1.<InvokeRec1>b__6(Action`1 state1)
at System.Reactive.Concurrency.Scheduler.InvokeRec1[TState](IScheduler scheduler, Pair`2 pair)
at System.Reactive.Concurrency.DispatcherScheduler.<>c__DisplayClass1`1.<Schedule>b__0()
at System.Reflection.RuntimeMethodInfo.InternalInvoke(RuntimeMethodInfo rtmi, Object obj, BindingFlags invokeAttr, Binder binder, Object parameters, CultureInfo culture, Boolean isBinderDefault, Assembly caller, Boolean verifyAccess, StackCrawlMark& stackMark)
at System.Reflection.RuntimeMethodInfo.InternalInvoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, StackCrawlMark& stackMark)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at System.Delegate.DynamicInvokeOne(Object[] args)
at System.MulticastDelegate.DynamicInvokeImpl(Object[] args)
at System.Delegate.DynamicInvoke(Object[] args)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.Dispatch(DispatcherPriority priority)
at System.Windows.Threading.Dispatcher.OnInvoke(Object context)
at System.Windows.Hosting.CallbackCookie.Invoke(Object[] args)
at System.Windows.Hosting.DelegateWrapper.InternalInvoke(Object[] args)
at System.Windows.RuntimeHost.ManagedHost.InvokeDelegate(IntPtr pHandle, Int32 nParamCount, ScriptParam[] pParams, ScriptParam& pResult)
だから私はそれを間違っていますが、何が問題なのですか?STからはわかりません。この動作を実装する正しい方法は何ですか。それはとても一般的ですよね?
更新
deleteSelectedCanExecute に関するすべてのコードを削除してプログラムを実行すると、クラッシュします。削除するParticipants.ChangeTrackingEnabled = true;
と、期待どおりに機能します。