いろんなスレッドからObservableCollectionを操作する時コレクション操作するとDispatcher.Invokeとかで書かなきゃいけないので
http://okazuki.hatenablog.com/entry/20100112/1263267397
な感じでやったりしてました。
けど開発を進めていくと、一連の処理をロックした状態で行いたいケースが結構あるんですよね。
あとは重いコレクション操作処理をDispathcerスレッドで行いたくないときとか。
変更と削除と追加を一つの処理として行いたいとか。
lock(hogelock)
{
// 変更処理
// 削除処理
// 追加処理
}
とか書けばよいんですけど、ロックオブジェクトの管理が・・・・
いろいろなスレッドからコレクション操作したい。
複数のコレクション操作にてデータの整合性を確保したい。
という要件を満たすための付け焼刃です。
public class TransactionDispatchObservableCollection<T> : ObservableCollection<T>
{
/// <summary>
/// コレクションディスパッチャー
/// </summary>
public Dispatcher Dispatch { get; set; }
public DispatcherPriority Priority { get; set; } = DispatcherPriority.Background;
private object TransactLock = new object();
#region コンストラクタ
public TransactionDispatchObservableCollection(Dispatcher Dispatch)
{
this.Dispatch = Dispatch;
}
public TransactionDispatchObservableCollection(Dispatcher Dispatch, IEnumerable<T> collection) : base(collection)
{
this.Dispatch = Dispatch;
}
#endregion
/// <summary>
/// 関連処理を排他制御しながら実行します。
/// </summary>
/// <param name="action"></param>
public void TransactExcution(Action action)
{
lock (TransactLock)
{
action();
}
}
/// <summary>
/// 関連処理を排他制御しながら実行します。(非同期)
/// </summary>
public async Task TransactExcutionAsync(Action action)
{
await Task.Run(() => {
lock (TransactLock)
{
action();
}
});
}
protected override void ClearItems()
{
TransactExcution(() => base.ClearItems());
}
protected override void InsertItem(int index, T item)
{
TransactExcution(() => base.InsertItem(index, item));
}
protected override void MoveItem(int oldIndex, int newIndex)
{
TransactExcution(() => base.MoveItem(oldIndex, newIndex));
}
protected override void SetItem(int index, T item)
{
TransactExcution(() => base.SetItem(index, item));
}
protected override void RemoveItem(int index)
{
TransactExcution(() => base.RemoveItem(index));
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (this.Dispatch.Thread == Thread.CurrentThread)
{
base.OnCollectionChanged(e);
}
else
{
Action<NotifyCollectionChangedEventArgs> changed = OnCollectionChanged;
this.Dispatch.Invoke(changed, Priority, e);
}
}
}
こんな感じで
await list.TransactExcutionAsync(() =>
{
if (!list.Any((x => x.Name == "Test")))
{
list.Add(model);
}
});
色々ダメなんですが限定用とであれば使えるかなぁと。