この記事は、Windows WPFアプリ (.NET Framework)の話です。 Windows フォームアプリケーション (.NET Framework) の場合
HeavyTask_Error だと
System.InvalidOperationException: 'このオブジェクトは別のスレッドに所有されているため、呼び出しスレッドはこのオブジェクトにアクセスできません。'
というエラーが出る。
正しくUIを操作するには、HeavyTask_Fixed のように修正する。Dispatcher.BeginInvoke
でデリゲートを非同期に実行している。
//エラーが出る Othersbutton.IsEnabled = false; // 修正後 {内は複数行でも可} awaitなので関数の属性にもawaitを付ける await Dispatcher.BeginInvoke(new Action(() =>{ Othersbutton.IsEnabled = false; }));
コード全体は以下の通り
using System; using System.Threading.Tasks; using System.Windows; namespace WpfApp1 { /// <summary> /// MainWindow.xaml の相互作用ロジック /// </summary> public partial class MainWindow : Window { bool stop = false; public MainWindow() { InitializeComponent(); } void HeavyTask_Error() { Othersbutton.IsEnabled = false; for (int i = 0; i < 30; i++) { System.Threading.Thread.Sleep(100); if (stop) break; label1.Text = i.ToString(); } if (stop) { label1.Text = "Stop!"; } else { label1.Text = "Completed!"; } Othersbutton.IsEnabled = true; } delegate void MethodInvoker(); async Task HeavyTask_FixedAsync() { await Dispatcher.BeginInvoke(new Action(() =>{ Othersbutton.IsEnabled = false; })); for (int i = 0; i < 30; i++) { System.Threading.Thread.Sleep(100); if (stop) break; await Dispatcher.BeginInvoke(new Action(() => { label1.Text = i.ToString(); })); } if (stop) { await Dispatcher.BeginInvoke(new Action(() => { label1.Text = "Stop!"; })); } else { await Dispatcher.BeginInvoke(new Action(() => { label1.Text = "Completed!"; })); } await Dispatcher.BeginInvoke(new Action(() => { Othersbutton.IsEnabled = true; })); } private void StartError_Click(object sender, RoutedEventArgs e) { stop = false; Task.Run(() => HeavyTask_Error()); } private void StartFixed_Click(object sender, RoutedEventArgs e) { stop = false; Task.Run(() => HeavyTask_FixedAsync()); } private void Stop_Click(object sender, RoutedEventArgs e) { stop = true; } } }