
前提・実現したいこと
重い処理の処理中に、UI操作を行いたいのですが、処理がブロックされ上手く行きません。
ブロックされないようにするために、ソースコードには
・イベントプロシージャにasync を付ける。
・重い処理(WEBページアクセス)をawait Task.Runの中に記述する。
を反映しています。
どのようにすれば、ブロックされずにUI操作できるようになりますでしょうか?
よろしくお願いします。
下に画面イメージとソースコードを載せておきます。
左のボタンがWEBページにアクセスするボタン
右のボタンがUI操作を確認するためのボタンです。
ソースコードは、Windows Formsアプリ、及びC#です。
該当のソースコード
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Net; using System.IO; using System.Text.RegularExpressions; namespace Asynctest { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private async void Button1_Click(object sender, EventArgs e) { const string url = @"http://192.168.0.99/"; //レスポンスを遅くするために、意図的にこのURLにアクセス //スレッド起動 await Task.Run(() => { //UIスレッドにアクセスするためにInvokeを使用 this.Invoke(new Action(() => { //Task.Delay(1000).Wait(); byte[] data; WebRequest req = null; WebResponse res = null; string str = null; try { req = WebRequest.Create(url); res = req.GetResponse(); Stream st = res.GetResponseStream(); data = ReadBinaryData(st); str = System.Text.Encoding.GetEncoding("csISO2022JP").GetString(data); } catch (Exception ex) { Console.WriteLine(ex.Message); listBox1.Items.Insert(listBox1.Items.Count , ex.Message); return; } finally { if (res != null) res.Close(); } listBox1.Items.Insert(listBox1.Items.Count, str); })); }); } static byte[] ReadBinaryData(Stream st) { byte[] buf = new byte[32768]; using (MemoryStream ms = new MemoryStream()) { while (true) { int r = st.Read(buf, 0, buf.Length); //一時バッファの内容をメモリ・ストリームに書き込む if (r > 0) { ms.Write(buf, 0, r); } else { break; } } return ms.ToArray(); } } //リストボックスに1行追加するだけ private void Button2_Click(object sender, EventArgs e) { listBox1.Items.Insert(listBox1.Items.Count - 1, "!"); } } }
問題解決後のソースコード
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using System.Net; using System.IO; using System.Text.RegularExpressions; namespace Asynctest { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private async void Button1_Click(object sender, EventArgs e) { const string url = @"http://192.168.0.99/"; // スレッドを起動し、以降のコードを実行する前に呼び出し元へ戻る await Task.Run(() => { //非同期で実行したい重い処理 //Task.Delay(1000).Wait(); byte[] data; WebRequest req = null; WebResponse res = null; string str = null; try { req = WebRequest.Create(url); res = req.GetResponse(); Stream st = res.GetResponseStream(); data = ReadBinaryData(st); str = System.Text.Encoding.GetEncoding("csISO2022JP").GetString(data); } catch (Exception ex) { Console.WriteLine(ex.Message); //UI要素へのアクセス(非同期で実行したい処理と混ぜずに、単独で行う。) this.Invoke(new Action(() => { listBox1.Items.Insert(listBox1.Items.Count, ex.Message); })); return; } finally { if (res != null) res.Close(); } //UI要素へのアクセス(非同期で実行したい処理と混ぜずに、単独で行う。) this.Invoke(new Action(() => { listBox1.Items.Insert(listBox1.Items.Count, str); })); }); } static byte[] ReadBinaryData(Stream st) { byte[] buf = new byte[32768]; using (MemoryStream ms = new MemoryStream()) { while (true) { int r = st.Read(buf, 0, buf.Length); //一時バッファの内容をメモリ・ストリームに書き込む if (r > 0) { ms.Write(buf, 0, r); } else { break; } } return ms.ToArray(); } } private void Button2_Click(object sender, EventArgs e) { listBox1.Items.Insert(listBox1.Items.Count, "!"); } } }
環境
Microsoft Windows 10 Pro (Version 1809)
Microsoft Visual Studio Community 2017(Version 15.9.4)
Microsoft .NET Framework(Version 4.7.03190)
回答3件
あなたの回答
tips
プレビュー