質問するログイン新規登録

回答編集履歴

1

Invoke,BeginInvokeについて追記

2015/07/18 01:51

投稿

wakuwaku
wakuwaku

スコア386

answer CHANGED
@@ -3,4 +3,105 @@
3
3
  staticメソッド内で参照できるのはstaticなメンバやプロパティに限られます。
4
4
 
5
5
  ざっと見た感じp_OutputDataReceivedはprivateで問題なさそうですが、
6
- staticにしてある理由があれば追記してください。
6
+ staticにしてある理由があれば追記してください。
7
+
8
+ 追記
9
+
10
+ 今回はFormアプリなのでDispatcherクラスではなく、ContorolクラスのInvoke,BeginInvokeを使用します。
11
+ 間違った情報失礼しました。
12
+
13
+
14
+ まず、C#がマルチスレッドで動作することはご存知と思います。[マルチスレッド](http://ufcpp.net/study/csharp/sp_thread.html)
15
+ Formアプリでは、アプリを起動すると必ずUIスレッドというものがただ1つだけ起動します。
16
+ UIスレッドは、ユーザからの入力(TextBoxへの入力やButtonクリックの処理など)の受付や出力(TextBoxへのTextの設定など)を制御するスレッドです。
17
+ 逆にいうと、UIスレッド以外からUIの更新をすることはできません。
18
+
19
+
20
+ 今回の場合、画面入出力を制御するUIスレッドとは別のスレッドでDOMコマンドの処理を行うことで、UIがフリーズしないようにしているわけです。
21
+
22
+ ただ、
23
+ p.WaitForExit();
24
+ とあるように、プロセスが終了するまでUIスレッドをロックしたまま待機していますので、実はフリーズしているんですが。。。
25
+
26
+
27
+ では、どのようにUIスレッドとは別のスレッドからUIの更新を行うかといいますと、
28
+ ここで、Invoke,BeginInvokeメソッドが登場するわけです。
29
+
30
+ 先述した通り、実はUIスレッドはロックされているので、今回はInvoke(同期)は使うことはできません。
31
+ BeginInvoke(非同期)で説明します。
32
+
33
+ BeginInvokeメソッドを理解するうえで、delegate(デリゲート)の理解が必須になってきます。[処理を委譲するdelegate](http://www.atmarkit.co.jp/fdotnet/csharp_abc/csharp_abc_017/csharp_abc01.html)
34
+ こちらについても、調べてみてください。
35
+
36
+ さて、BeginInvokeメソッドの使い方ですが、BeginInvokeメソッドにUIスレッドで実行したい処理のdelegateを引数に渡します。
37
+ 今回の場合、「textBox.Text = e.Data」をUIスレッド上で実行してもらいたいので、以下のようにします。
38
+ (目的の動作となるよう、少し処理を変えています。TextBoxをMultiLineにして、十分に大きくしておいてください。dirコマンドの出力結果をTextBoxに出力します。)
39
+
40
+
41
+ ```C#
42
+ public partial class Form1 : Form
43
+ {
44
+ public Form1()
45
+ {
46
+ InitializeComponent();
47
+ }
48
+
49
+ private void Form1_Load(object sender, EventArgs e)
50
+ {
51
+
52
+ }
53
+
54
+ private void button1_Click(object sender, EventArgs e)
55
+ {
56
+ //Processオブジェクトを作成
57
+ System.Diagnostics.Process p = new System.Diagnostics.Process();
58
+
59
+ //出力をストリームに書き込むようにする
60
+ p.StartInfo.UseShellExecute = false;
61
+ p.StartInfo.RedirectStandardOutput = true;
62
+ //OutputDataReceivedイベントハンドラを追加
63
+ p.OutputDataReceived += p_OutputDataReceived;
64
+
65
+ p.StartInfo.FileName =
66
+ System.Environment.GetEnvironmentVariable("ComSpec");
67
+ p.StartInfo.RedirectStandardInput = false;
68
+ p.StartInfo.CreateNoWindow = true;
69
+ p.StartInfo.Arguments = @"/c dir";
70
+
71
+ //起動
72
+ p.Start();
73
+
74
+ //非同期で出力の読み取りを開始
75
+ p.BeginOutputReadLine();
76
+
77
+ p.WaitForExit();
78
+ p.Close();
79
+
80
+ }
81
+
82
+ //OutputDataReceivedイベントハンドラ
83
+ //行が出力されるたびに呼び出される
84
+ private void p_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
85
+ {
86
+ //出力された文字列を表示する
87
+ Console.WriteLine(e.Data);
88
+
89
+ // Delegateを作成
90
+ Action act = () =>
91
+ {
92
+ if (string.IsNullOrEmpty(e.Data) == false)
93
+ {
94
+ textbox.AppendText(e.Data);
95
+ }
96
+
97
+ textbox.AppendText(Environment.NewLine);
98
+ };
99
+
100
+ BeginInvoke(act);
101
+ }
102
+ }
103
+ ```
104
+
105
+
106
+ スレッドやデリゲートなんかはイメージを掴むまでが大変です。
107
+ めげずに頑張りましょう。