質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Q&A

解決済

2回答

826閲覧

DelegateだとかInvokeだとかそんなんしたくない・・・

milkypai

総合スコア8

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

0グッド

0クリップ

投稿2023/08/25 07:29

C#でシリアル通信アプリをつくっており、受信した直後や、タイマー割り込みの
中でGUIを操作しているのですが、GUIにアクセスするたびにDelegateだとか
Invokeだとか書いて、メソッドを作らないとダメで非常に面倒で読みにくいです。

GUIを操作するメソッド一つにして、その中で全てのGUIを操作するようにして
引数で制御するようにしてみましたが、それを呼び出すたびに操作しないGUIに
対しても引数を全部設定しなければならず手間で見にくいです。

これはどうにもならないものなのでしょうか?

ソースコードは金澤ソフト設計さんのを流用しているので勝手に張るのもよくない
のでそちらを見てください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2023/08/25 07:42

どこを見ればいいんでしょうか
guest

回答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
KOZ6.0

総合スコア2721

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

milkypai

2023/08/28 00:42

非常に使い勝手がよくなりました。 こんな方法があるなんて、驚きました。 本当にありがとうございました。
KOZ6.0

2023/08/28 02:44

すみません、透過プロキシ作成のコーディングミスってました。 メソッド実行時、ByRef でコントロールを 返す場合は、透過プロキシを返すようにしなければいけません。 これにより、CheckForIllegalCrossThreadCalls = false にする必要はなくなります。
guest

0

GUIアプリでシリアル通信を実用的に実装しようと思ったら、そのDelegateだとかInvokeだとかってのは必須となります。
食わず嫌いせずに、そこらへんがんばって学習しましょう

投稿2023/08/25 07:44

y_waiwai

総合スコア88163

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

milkypai

2023/08/25 07:47

学習とかじゃなく、質問に書いてある通り書く工数を減らしたい、読みやすくしたいんですね
y_waiwai

2023/08/25 07:55

そのキーワードを使いたくないってだけなら、ラムダ式なんかを使えば、ある程度それは実現できます まあそれで工数が減るとか読みやすくなるかってのはちと疑問なところではありますが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問