C#でシリアル通信アプリをつくっており、受信した直後や、タイマー割り込みの
中でGUIを操作しているのですが、GUIにアクセスするたびにDelegateだとか
Invokeだとか書いて、メソッドを作らないとダメで非常に面倒で読みにくいです。
GUIを操作するメソッド一つにして、その中で全てのGUIを操作するようにして
引数で制御するようにしてみましたが、それを呼び出すたびに操作しないGUIに
対しても引数を全部設定しなければならず手間で見にくいです。
これはどうにもならないものなのでしょうか?
ソースコードは金澤ソフト設計さんのを流用しているので勝手に張るのもよくない
のでそちらを見てください。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答2件
0
ベストアンサー
Control.CheckForIllegalCrossThreadCalls プロパティを False にすると、呼び出しスレッドのチェックを行わなくなります。
「Control.CheckForIllegalCrossThreadCalls プロパティ」
https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.forms.control.checkforillegalcrossthreadcalls?view=netframework-4.8
大抵の操作は、ウインドウズメッセージを介して行われるため、これで充分かと思います。
.NET Framework の場合
透過プロキシを使うことによって、public メソッドや public プロパティ等、全ての操作を Invoke を介して行うことが出来ます。
csharp
1using System; 2using System.Reflection; 3using System.Runtime.Remoting.Messaging; 4using System.Runtime.Remoting.Proxies; 5using System.Windows.Forms; 6 7public static class ControlUtil 8{ 9 public static T CreateProxy<T>(T target) where T : Control { 10 var proxy = new ControlProxy(target); 11 return (T)proxy.GetTransparentProxy(); 12 } 13 14 private class ControlProxy: RealProxy 15 { 16 Control _Instance; 17 18 public ControlProxy(Control target) 19 : base(target.GetType()) { 20 _Instance = target; 21 } 22 23 public sealed override IMessage Invoke(IMessage msg) { 24 try { 25 IMethodMessage mm = msg as IMethodMessage; 26 object[] args = mm.Args; 27 MethodInfo method = (MethodInfo)mm.MethodBase; 28 object ret = Invoke(method, args); 29 return new ReturnMessage( 30 ret, args, args.Length, mm.LogicalCallContext, (IMethodCallMessage)msg); 31 32 } catch (Exception ex) { 33 if (ex.InnerException != null) 34 return new ReturnMessage(ex.InnerException, (IMethodCallMessage)msg); 35 return new ReturnMessage(ex, (IMethodCallMessage)msg); 36 } 37 } 38 39 public object Invoke(MethodInfo mi, object[] args) { 40 if (_Instance.InvokeRequired) { 41 Func<MethodInfo, object[], object> d = Invoke; 42 return _Instance.Invoke(d, mi, args); 43 } else { 44 var result = mi.Invoke(_Instance, args); 45 var parameters = mi.GetParameters(); 46 for (int i = 0; i < parameters.Length; i++) { 47 var p = parameters[i]; 48 if (p.ParameterType.IsByRef && args[i] is Control control) { 49 var proxy = new ControlProxy(control); 50 args[i] = proxy.GetTransparentProxy(); 51 } 52 } 53 return result; 54 } 55 } 56 } 57}
使い方
csharp
1using System; 2using System.Threading; 3using System.Threading.Tasks; 4using System.Windows.Forms; 5 6public partial class Form1 : Form 7{ 8 public Form1() { 9 InitializeComponent(); 10 } 11 12 private void button1_Click(object sender, EventArgs e) { 13 Task.Run(OtherTask); 14 } 15 16 private void OtherTask() { 17 Form1 form1 = ControlUtil.CreateProxy(this); 18 for (int i = 0; i <= 10; i++) { 19 Thread.Sleep(200); 20 form1.label1.Text = i.ToString(); // label1 は public でないとダメ 21 } 22 } 23}
.NET Core 系の場合
RealProxy は使えなくなりました。
代わりに DispatchProxy クラスが提供されていますが、残念ながらインターフェイスを介してしか使えないので RealProxy ほど使い勝手は良くないようです。
https://learn.microsoft.com/ja-jp/dotnet/api/system.reflection.dispatchproxy?view=net-7.0
投稿2023/08/25 14:57
編集2023/08/28 04:43総合スコア2721
0
GUIアプリでシリアル通信を実用的に実装しようと思ったら、そのDelegateだとかInvokeだとかってのは必須となります。
食わず嫌いせずに、そこらへんがんばって学習しましょう
投稿2023/08/25 07:44
総合スコア88163
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。