Dispatcherを作ってモデルを単一スレッドで実行したり画像をバックグラウンドでダウンロードしたり
ちゃんとした文献が見つからなかったから本当に問題ないかは知らない
Dispatcherを作って
App.xaml.cs
public partial class App : Application
{
public static Dispatcher BackgroundDispatcher => CreateBackgroundDispatcherAsync().Result;
static Task<Dispatcher> CreateBackgroundDispatcherAsync()
{
var tcs = new TaskCompletionSource<Dispatcher>();
var th = new Thread(() => {
var d = Dispatcher.CurrentDispatcher;
tcs.SetResult(d);
Current.Dispatcher.InvokeAsync(() => {
Current.Exit += (sender, e) =>
{
d.InvokeShutdown();
};
});
Dispatcher.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
return tcs.Task;
}
}
モデルを単一スレッドで実行したり
モデルクラスを作って
Counter.cs
class Counter : DispatcherObject
{
int _Count = 0;
public int Count
{
get
{
VerifyAccess();
return _Count;
}
}
public void Add(int n)
{
VerifyAccess();
_Count += n;
}
}
何時も通りDispatcher経由で触る
async void btnCounter_Click(object sender, RoutedEventArgs e)
{
var cnt = await App.BackgroundDispatcher.InvokeAsync(() => new Counter());
await Task.WhenAll(Enumerable.Range(0, 10).Select(i => Task.Run(async () =>
{
foreach (var j in Enumerable.Range(0, 1000))
{
await cnt.Dispatcher.InvokeAsync(() => cnt.Add(1));
}
})));
MessageBox.Show($"{ await cnt.Dispatcher.InvokeAsync(() => cnt.Count) }");
}
画像をバックグラウンドでダウンロードしたり
async void btnDownloadImage_Click(object sender, RoutedEventArgs e)
{
imgMain.Source = await DownloadImageAsync(new Uri(txtUri.Text));
}
Task<BitmapImage> DownloadImageAsync(Uri uri)
{
var tcs = new TaskCompletionSource<BitmapImage>();
App.BackgroundDispatcher.InvokeAsync(() => {
var bmp = new BitmapImage(uri);
void handler(object sender, EventArgs e)
{
bmp.DownloadCompleted -= handler;
bmp.Freeze();
tcs.SetResult(bmp);
}
bmp.DownloadCompleted += handler;
});
return tcs.Task;
}
ソースコード