回答編集履歴

1

見直しキャンペーン中

2023/07/22 10:02

投稿

TN8001
TN8001

スコア9350

test CHANGED
@@ -1,319 +1,157 @@
1
1
  > あるクラス(Mainとは別)において,ある変数の値によって,ピクチャーボックスに適当な図(簡単な長方形で良い)を表示させたいと考えています.
2
2
 
3
-
4
-
5
3
  「あるクラス(Mainとは別)」ここが肝なのかなと思いました。
6
-
7
4
  具体的な使用イメージがわからないのですが、時間のかかる計算やリアルタイムのデータとかなんでしょうか。
8
5
 
9
-
10
-
11
- `.Net`には変数(正確にはプロパティ)の変更を、監視者に通知する仕組みが既にあります。
6
+ .Netには変数(正確にはプロパティ)の変更を、監視者に通知する仕組みが既にあります。
12
-
13
7
  通知する側が`INotifyPropertyChanged`を実装し、監視側は`PropertyChanged`を購読します。
14
-
15
8
  難しそうに感じますが定型コードなのであまり気にせず、「プロパティが変更されると、イベントが来る」と思っておけば十分です。
16
9
 
17
-
18
-
19
10
  `Form1`と`Form2`の連携も、入門者の方が必ず引っかかるポイントですね。
20
-
21
11
  今回は`Class1`をやり取りすることになります。
22
-
23
12
  文字で説明すると無駄に長くなってしまうので、回答コードを試していただいたほうが早そうです^^;
24
13
 
25
-
26
-
27
- Form1.cs
14
+ ```cs:Form1.cs
28
-
29
- ```C#
30
-
31
15
  using System;
32
-
33
16
  using System.Drawing;
34
-
35
17
  using System.Threading.Tasks;
36
-
37
18
  using System.Windows.Forms;
38
19
 
20
+ namespace Questions281063
21
+ {
22
+ public partial class Form1 : Form
23
+ {
24
+ private Button button1 = new Button();
25
+ private Button button2 = new Button();
26
+ private Class1 class1 = new Class1();
39
27
 
28
+ public Form1()
29
+ {
30
+ InitializeComponent();
31
+
32
+ button1.Text = "show";
33
+ button1.Click += Button1_Click;
34
+ Controls.Add(button1);
35
+
36
+ button2.Text = "run";
37
+ button2.Location = new Point(100, 0);
38
+ button2.Click += Button2_Click;
39
+ Controls.Add(button2);
40
+ }
41
+
42
+ private void Button1_Click(object sender, EventArgs e)
43
+ {
44
+ // Class1のインスタンスclass1を渡します
45
+ new Form2(class1).Show();
46
+ }
47
+
48
+ private async void Button2_Click(object sender, EventArgs e)
49
+ {
50
+ button2.Enabled = false;
51
+ // 別スレッドでclass1のRunを実行し、非同期で終了を待ちます
52
+ await Task.Run(() => class1.Run());
53
+ button2.Enabled = true;
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ ```cs:Form2.cs
60
+ using System.ComponentModel;
61
+ using System.Drawing;
62
+ using System.Windows.Forms;
40
63
 
41
64
  namespace Questions281063
65
+ {
66
+ public partial class Form2 : Form
67
+ {
68
+ private PictureBox pictureBox1 = new PictureBox();
69
+ private Class1 class1;
42
70
 
43
- {
44
-
45
- public partial class Form1 : Form
71
+ public Form2(Class1 class1)
46
-
47
- {
48
-
49
- private Button button1 = new Button();
50
-
51
- private Button button2 = new Button();
52
-
53
- private Class1 class1 = new Class1();
54
-
55
-
56
-
57
- public Form1()
58
-
59
72
  {
73
+ // Class1のインスタンスを受け取り、class1変数に入れておきます
74
+ this.class1 = class1;
60
75
 
61
76
  InitializeComponent();
62
77
 
78
+ pictureBox1.Dock = DockStyle.Fill;
79
+ pictureBox1.Paint += PictureBox1_Paint;
80
+ Controls.Add(pictureBox1);
63
81
 
64
-
82
+ // 変更通知イベントを購読します
65
- button1.Text = "show";
83
+ class1.PropertyChanged += Class1_PropertyChanged;
66
-
67
- button1.Click += Button1_Click;
84
+ FormClosed += Form2_FormClosed;
68
-
69
- Controls.Add(button1);
70
-
71
-
72
-
73
- button2.Text = "run";
74
-
75
- button2.Location = new Point(100, 0);
76
-
77
- button2.Click += Button2_Click;
78
-
79
- Controls.Add(button2);
80
-
81
85
  }
82
86
 
83
-
84
-
85
- private void Button1_Click(object sender, EventArgs e)
87
+ private void PictureBox1_Paint(object sender, PaintEventArgs e)
86
-
87
88
  {
88
-
89
- // Class1のインスタンスclass1を渡します
89
+ // class1の状態によって何か描きます
90
-
90
+ if(class1.A == 1) e.Graphics.DrawRectangle(Pens.Black, 5, 5, 400, 400);
91
+ if(class1.B == 1) e.Graphics.FillRectangle(Brushes.Blue, 50, 50, 200, 100);
91
- new Form2(class1).Show();
92
+ if(class1.C == 1) e.Graphics.FillEllipse(Brushes.Pink, 200, 300, 50, 50);
92
-
93
93
  }
94
94
 
95
-
96
-
97
- private async void Button2_Click(object sender, EventArgs e)
95
+ private void Class1_PropertyChanged(object sender, PropertyChangedEventArgs e)
98
-
99
96
  {
100
-
101
- button2.Enabled = false;
102
-
103
- // 別スレッドでclass1のRun実行、非同期で終了を待ちます
97
+ // なにか変更されたのpictureBox1を描き直します
104
-
105
- await Task.Run(() => class1.Run());
106
-
107
- button2.Enabled = true;
98
+ pictureBox1.Invalidate();
108
-
109
99
  }
110
100
 
101
+ private void Form2_FormClosed(object sender, FormClosedEventArgs e)
102
+ {
103
+ // 変更通知イベントを購読解除します(忘れるとメモリーリークします)
104
+ class1.PropertyChanged -= Class1_PropertyChanged;
105
+ }
111
106
  }
112
-
113
107
  }
114
-
115
108
  ```
116
109
 
117
-
118
-
119
- Form2.cs
110
+ ```cs:Class1.cs
120
-
121
- ```C#
122
-
123
111
  using System.ComponentModel;
124
-
125
- using System.Drawing;
126
-
127
- using System.Windows.Forms;
112
+ using System.Runtime.CompilerServices;
128
-
129
-
130
113
 
131
114
  namespace Questions281063
132
-
133
115
  {
134
-
135
- public partial class Form2 : Form
116
+ public class Class1 : INotifyPropertyChanged
136
-
137
117
  {
138
-
139
- private PictureBox pictureBox1 = new PictureBox();
140
-
141
- private Class1 class1;
142
-
143
-
144
-
145
- public Form2(Class1 class1)
146
-
147
- {
148
-
149
- // Class1のインスタンスを受け取り、class1変数に入れておきます
150
-
151
- this.class1 = class1;
152
-
153
-
154
-
155
- InitializeComponent();
156
-
157
-
158
-
159
- pictureBox1.Dock = DockStyle.Fill;
160
-
161
- pictureBox1.Paint += PictureBox1_Paint;
162
-
163
- Controls.Add(pictureBox1);
164
-
165
-
166
-
167
- // 変更通知イベントを購読します
168
-
169
- class1.PropertyChanged += Class1_PropertyChanged;
170
-
171
- FormClosed += Form2_FormClosed;
172
-
173
- }
174
-
175
-
176
-
177
- private void PictureBox1_Paint(object sender, PaintEventArgs e)
178
-
179
- {
180
-
181
- // class1の状態によって何か描きます
182
-
183
- if(class1.A == 1) e.Graphics.DrawRectangle(Pens.Black, 5, 5, 400, 400);
184
-
185
- if(class1.B == 1) e.Graphics.FillRectangle(Brushes.Blue, 50, 50, 200, 100);
186
-
187
- if(class1.C == 1) e.Graphics.FillEllipse(Brushes.Pink, 200, 300, 50, 50);
188
-
189
- }
190
-
191
-
192
-
193
- private void Class1_PropertyChanged(object sender, PropertyChangedEventArgs e)
194
-
195
- {
196
-
197
- // なにか変更されたのでpictureBox1を描き直します
198
-
199
- pictureBox1.Invalidate();
200
-
201
- }
202
-
203
-
204
-
205
- private void Form2_FormClosed(object sender, FormClosedEventArgs e)
206
-
207
- {
208
-
209
- // 変更通知イベントを購読解除します(忘れるとメモリーリークします)
210
-
211
- class1.PropertyChanged -= Class1_PropertyChanged;
212
-
213
- }
214
-
215
- }
216
-
217
- }
218
-
219
- ```
220
-
221
-
222
-
223
- Class1.cs
224
-
225
- ```C#
226
-
227
- using System.ComponentModel;
228
-
229
- using System.Runtime.CompilerServices;
230
-
231
-
232
-
233
- namespace Questions281063
234
-
235
- {
236
-
237
- public class Class1 : INotifyPropertyChanged
238
-
239
- {
240
-
241
118
  // ちょっと冗長なのですが、通知する変数はこのようにする必要があります
242
-
243
119
  public int A { get => _A; set => Set(ref _A, value); }
244
-
245
120
  private int _A;
246
121
 
247
-
248
-
249
122
  public int B { get => _B; set => Set(ref _B, value); }
250
-
251
123
  private int _B;
252
124
 
253
-
254
-
255
125
  public int C { get => _C; set => Set(ref _C, value); }
256
-
257
126
  private int _C;
258
127
 
259
128
 
260
-
261
-
262
-
263
129
  public void Run()
264
-
265
130
  {
266
-
267
131
  A = 1; // AをON
268
-
269
132
  System.Threading.Thread.Sleep(1000);
270
-
271
133
  A = 0; // AをOFF
272
-
273
134
  B = 1;
274
-
275
135
  C = 1;
276
-
277
136
  System.Threading.Thread.Sleep(1000);
278
-
279
137
  B = 0;
280
-
281
138
  System.Threading.Thread.Sleep(1000);
282
-
283
139
  C = 0;
284
-
285
140
  }
286
141
 
287
-
288
-
289
142
  // 定型コードなので気にしないで結構です
290
-
291
143
  #region INotifyPropertyChanged
292
-
293
144
  public event PropertyChangedEventHandler PropertyChanged;
294
-
295
145
  protected void Set<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
296
-
297
146
  {
298
-
299
147
  if(Equals(storage, value)) return;
300
-
301
148
  storage = value;
302
-
303
149
  OnPropertyChanged(propertyName);
304
-
305
150
  }
306
-
307
151
  protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
308
-
309
152
  #endregion
310
-
311
153
  }
312
-
313
154
  }
314
-
315
155
  ```
316
156
 
317
-
318
-
319
157
  `Designer.cs`が行数をとるのでコードで`Button`等を作っていますが、もちろんデザイナでやってもらっても結構です。