回答編集履歴

1

Invoke,BeginInvokeについて追記

2015/07/18 01:51

投稿

wakuwaku
wakuwaku

スコア386

test CHANGED
@@ -9,3 +9,207 @@
9
9
  ざっと見た感じp_OutputDataReceivedはprivateで問題なさそうですが、
10
10
 
11
11
  staticにしてある理由があれば追記してください。
12
+
13
+
14
+
15
+ 追記
16
+
17
+
18
+
19
+ 今回はFormアプリなのでDispatcherクラスではなく、ContorolクラスのInvoke,BeginInvokeを使用します。
20
+
21
+ 間違った情報失礼しました。
22
+
23
+
24
+
25
+
26
+
27
+ まず、C#がマルチスレッドで動作することはご存知と思います。[マルチスレッド](http://ufcpp.net/study/csharp/sp_thread.html)
28
+
29
+ Formアプリでは、アプリを起動すると必ずUIスレッドというものがただ1つだけ起動します。
30
+
31
+ UIスレッドは、ユーザからの入力(TextBoxへの入力やButtonクリックの処理など)の受付や出力(TextBoxへのTextの設定など)を制御するスレッドです。
32
+
33
+ 逆にいうと、UIスレッド以外からUIの更新をすることはできません。
34
+
35
+
36
+
37
+
38
+
39
+ 今回の場合、画面入出力を制御するUIスレッドとは別のスレッドでDOMコマンドの処理を行うことで、UIがフリーズしないようにしているわけです。
40
+
41
+
42
+
43
+ ただ、
44
+
45
+ p.WaitForExit();
46
+
47
+ とあるように、プロセスが終了するまでUIスレッドをロックしたまま待機していますので、実はフリーズしているんですが。。。
48
+
49
+
50
+
51
+
52
+
53
+ では、どのようにUIスレッドとは別のスレッドからUIの更新を行うかといいますと、
54
+
55
+ ここで、Invoke,BeginInvokeメソッドが登場するわけです。
56
+
57
+
58
+
59
+ 先述した通り、実はUIスレッドはロックされているので、今回はInvoke(同期)は使うことはできません。
60
+
61
+ BeginInvoke(非同期)で説明します。
62
+
63
+
64
+
65
+ BeginInvokeメソッドを理解するうえで、delegate(デリゲート)の理解が必須になってきます。[処理を委譲するdelegate](http://www.atmarkit.co.jp/fdotnet/csharp_abc/csharp_abc_017/csharp_abc01.html)
66
+
67
+ こちらについても、調べてみてください。
68
+
69
+
70
+
71
+ さて、BeginInvokeメソッドの使い方ですが、BeginInvokeメソッドにUIスレッドで実行したい処理のdelegateを引数に渡します。
72
+
73
+ 今回の場合、「textBox.Text = e.Data」をUIスレッド上で実行してもらいたいので、以下のようにします。
74
+
75
+ (目的の動作となるよう、少し処理を変えています。TextBoxをMultiLineにして、十分に大きくしておいてください。dirコマンドの出力結果をTextBoxに出力します。)
76
+
77
+
78
+
79
+
80
+
81
+ ```C#
82
+
83
+ public partial class Form1 : Form
84
+
85
+ {
86
+
87
+ public Form1()
88
+
89
+ {
90
+
91
+ InitializeComponent();
92
+
93
+ }
94
+
95
+
96
+
97
+ private void Form1_Load(object sender, EventArgs e)
98
+
99
+ {
100
+
101
+
102
+
103
+ }
104
+
105
+
106
+
107
+ private void button1_Click(object sender, EventArgs e)
108
+
109
+ {
110
+
111
+ //Processオブジェクトを作成
112
+
113
+ System.Diagnostics.Process p = new System.Diagnostics.Process();
114
+
115
+
116
+
117
+ //出力をストリームに書き込むようにする
118
+
119
+ p.StartInfo.UseShellExecute = false;
120
+
121
+ p.StartInfo.RedirectStandardOutput = true;
122
+
123
+ //OutputDataReceivedイベントハンドラを追加
124
+
125
+ p.OutputDataReceived += p_OutputDataReceived;
126
+
127
+
128
+
129
+ p.StartInfo.FileName =
130
+
131
+ System.Environment.GetEnvironmentVariable("ComSpec");
132
+
133
+ p.StartInfo.RedirectStandardInput = false;
134
+
135
+ p.StartInfo.CreateNoWindow = true;
136
+
137
+ p.StartInfo.Arguments = @"/c dir";
138
+
139
+
140
+
141
+ //起動
142
+
143
+ p.Start();
144
+
145
+
146
+
147
+ //非同期で出力の読み取りを開始
148
+
149
+ p.BeginOutputReadLine();
150
+
151
+
152
+
153
+ p.WaitForExit();
154
+
155
+ p.Close();
156
+
157
+
158
+
159
+ }
160
+
161
+
162
+
163
+ //OutputDataReceivedイベントハンドラ
164
+
165
+ //行が出力されるたびに呼び出される
166
+
167
+ private void p_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
168
+
169
+ {
170
+
171
+ //出力された文字列を表示する
172
+
173
+ Console.WriteLine(e.Data);
174
+
175
+
176
+
177
+ // Delegateを作成
178
+
179
+ Action act = () =>
180
+
181
+ {
182
+
183
+ if (string.IsNullOrEmpty(e.Data) == false)
184
+
185
+ {
186
+
187
+ textbox.AppendText(e.Data);
188
+
189
+ }
190
+
191
+
192
+
193
+ textbox.AppendText(Environment.NewLine);
194
+
195
+ };
196
+
197
+
198
+
199
+ BeginInvoke(act);
200
+
201
+ }
202
+
203
+ }
204
+
205
+ ```
206
+
207
+
208
+
209
+
210
+
211
+ スレッドやデリゲートなんかはイメージを掴むまでが大変です。
212
+
213
+ めげずに頑張りましょう。
214
+
215
+