私はこの質問が以前に尋ねられたことを知っていますが、私は次の方法を探しています:
ここまでが私ですが、Windowsフォームの参照を削除したいと思います。何か案は?
public delegate void SafeInvokeDelegate(System.Action action);
public class SafeInvoke
{
private readonly System.Windows.Forms.Control _threadControl;
public SafeInvoke()
{
_threadControl = new System.Windows.Forms.Control();
}
public void Invoke(System.Action action)
{
if (_threadControl.InvokeRequired)
_threadControl.Invoke(new SafeInvokeDelegate(Invoke), new object[] {action});
else if (action != null) action();
}
}
上記のクラスは次のように使用できます。
SafeInvoke _safeInvoker = new SafeInvoke();
void SafeClearItems()
{
_safeInvoker.Invoke(delegate
{
listView1.Items.Clear();
});
}
SafeInvokeクラスのSystem.Windows.Forms.Controlを削除して、同じ機能を維持するにはどうすればよいですか?
拡張メソッドとラムダを使用して、コードをよりクリーンにすることもできます。
using System.ComponentModel;
public static class ISynchronizeInvokeExtensions
{
public static void InvokeEx<T>(this T @this, Action<T> action) where T : ISynchronizeInvoke
{
if (@this.InvokeRequired)
{
@this.Invoke(action, new object[] { @this });
}
else
{
action(@this);
}
}
}
そのため、ISynchronizeInvokeでInvokeEx
を使用して、実装クラスのプロパティとフィールドにアクセスできるようになりました。
this.InvokeEx(f => f.listView1.Items.Clear());
ISynchronizeInvoke
の代わりに Control
を使用します。これは、Control
がInvoke/BeginInvoke/EndInvoke/InvokeRequired
を使用して実装するインターフェースです。
別の方法は SynchronizationContext.Current
を使用することです-これはBackgroundWorker
が使用するものであると私は信じています。
現在、呼び出すのは簡単です。
例えば。 Label(lblVal)を呼び出してtxtValの値を取得したいとします。
lblVal.Invoke((MethodInvoker)delegate{lblVal.Text = txtVal.Text;});
...それはそれと同じくらい簡単です:D
ここはVB.netにあり、Samuelの回答と非常によく似ています。サブルーチンまたは関数が必要かどうか、およびパラメーターがあるかどうかに応じて、4つのオーバーロードがあります。さらに多くのパラメーターにオーバーロードを追加するのは簡単です。 VB.Netはタイプを推測できます。
Module ISynchronizeInvokeExtensions
Public Delegate Function GenericLambdaFunctionWithParam(Of InputType, OutputType)(ByVal input As InputType) As OutputType
Private Delegate Function InvokeLambdaFunctionCallback(Of InputType, OutputType)(ByVal f As GenericLambdaFunctionWithParam(Of InputType, OutputType), ByVal input As InputType, ByVal c As System.ComponentModel.ISynchronizeInvoke) As OutputType
Public Function InvokeEx(Of InputType, OutputType)(ByVal f As GenericLambdaFunctionWithParam(Of InputType, OutputType), ByVal input As InputType, ByVal c As System.ComponentModel.ISynchronizeInvoke) As OutputType
If c.InvokeRequired Then
Dim d As New InvokeLambdaFunctionCallback(Of InputType, OutputType)(AddressOf InvokeEx)
Return DirectCast(c.Invoke(d, New Object() {f, input, c}), OutputType)
Else
Return f(input)
End If
End Function
Public Delegate Sub GenericLambdaSubWithParam(Of InputType)(ByVal input As InputType)
Public Sub InvokeEx(Of InputType)(ByVal s As GenericLambdaSubWithParam(Of InputType), ByVal input As InputType, ByVal c As System.ComponentModel.ISynchronizeInvoke)
InvokeEx(Of InputType, Object)(Function(i As InputType) As Object
s(i)
Return Nothing
End Function, input, c)
End Sub
Public Delegate Sub GenericLambdaSub()
Public Sub InvokeEx(ByVal s As GenericLambdaSub, ByVal c As System.ComponentModel.ISynchronizeInvoke)
InvokeEx(Of Object, Object)(Function(i As Object) As Object
s()
Return Nothing
End Function, Nothing, c)
End Sub
Public Delegate Function GenericLambdaFunction(Of OutputType)() As OutputType
Public Function InvokeEx(Of OutputType)(ByVal f As GenericLambdaFunction(Of OutputType), ByVal c As System.ComponentModel.ISynchronizeInvoke) As OutputType
Return InvokeEx(Of Object, OutputType)(Function(i As Object) f(), Nothing, c)
End Function
End Module
使用法(これをバックグラウンドワーカーで実行する):
InvokeEx(Sub(x As String) Me.Text = x, "foo", Me) 'set form title to foo
InvokeEx(AddressOf MsgBox, Me.Text, Me)
InvokeEx(Sub() Me.Text &= "!", "foo", Me) 'append "!" to form title
InvokeEx(AddressOf MsgBox, Me.Text, Me)
Dim s As String = InvokeEx(Function() Me.Text, Me) & "bar" 'get form title to backgorundworker thread
InvokeEx(AddressOf MsgBox, s, Me) 'display the string from backgroundworker thread
ここにVB私が使用するSamuelの回答と同等のコードがあります。実際には2つの拡張機能があることに注意してください。ただし、なぜそこにあるのかわからないことを認めなければなりません。C#バージョンを何年も前にコピーしました(多分このサイトから)そしてそれは両方の拡張機能を持っていましたが、なぜか私は完全に理解していません。私はそれをコピーし、それをどのように使用するかを理解しました、そしてこれらの「内部」で起こっているすべてを半分理解しました複雑な機能。
#Const System_ComponentModel = True
#Const System_Drawing = False
Option Compare Binary
Option Explicit On
Option Strict On
Imports System.Collections
Imports System.Runtime.CompilerServices ' for Extension() attribute
Imports System.Text
#If System_ComponentModel Then
Imports System.ComponentModel
#End If
#If System_Drawing Then
Imports System.Drawing
#End If
Public Module MyExtensions
' other #Region blocks are removed. i use many in my Extensions
' module/class. the below code is only the 2 relevant extension
' for this 'SafeInvoke' functionality. but i use other regions
' such as "String extensions" and "Numeric extensions". i use
' the above System_ComponentModel and System_Drawing compiler
' directives to include or exclude blocks of code that i want
' to either include or exclude in a project, which allows me to
' easily compare my code in one project with the same file in
' other projects to syncronise new changes across projects.
' you can scrap pretty much all the code above,
' but i'm giving it here so you see it in the full context.
#Region "ISynchronizeInvoke extensions"
#If System_ComponentModel Then
<Extension()>
Public Function SafeInvoke(Of T As ISynchronizeInvoke, TResult)(isi As T, callFunction As Func(Of T, TResult)) As TResult
If (isi.InvokeRequired) Then
Dim result As IAsyncResult = isi.BeginInvoke(callFunction, New Object() {isi})
Dim endresult As Object = isi.EndInvoke(result)
Return DirectCast(endresult, TResult)
Else
Return callFunction(isi)
End If
End Function
''' <summary>
''' This can be used in VB with:
''' txtMyTextBox.SafeInvoke(Sub(d) d.Text = "This is my new Text value.")
''' or:
''' txtMyTextBox.SafeInvoke(Sub(d) d.Text = myTextStringVariable)
''' </summary>
''' <typeparam name="T"></typeparam>
''' <param name="isi"></param>
''' <param name="callFunction"></param>
''' <remarks></remarks>
<Extension()>
Public Sub SafeInvoke(Of T As ISynchronizeInvoke)(isi As T, callFunction As Action(Of T))
If isi.InvokeRequired Then
isi.BeginInvoke(callFunction, New Object() {isi})
Else
callFunction(isi)
End If
End Sub
#End If
#End Region
' other #Region blocks are removed from here too.
End Module
C#のバージョンは次のとおりです。
#define System_ComponentModel
#undef System_Drawing
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
#if System_ComponentModel
using System.ComponentModel;
#endif
#if System_Drawing
using System.Drawing;
#endif
namespace MyCompany.Extensions
{
static partial class MyExtensions
{
// other #Region blocks are removed. i use many in my Extensions
// module/class. the below code is only the 2 relevant extension
// for this 'SafeInvoke' functionality. but i use other regions
// such as "String extensions" and "Numeric extensions". i use
// the above System_ComponentModel and System_Drawing compiler
// directives to include or exclude blocks of code that i want
// to either include or exclude in a project, which allows me to
// easily compare my code in one project with the same file in
// other projects to syncronise new changes across projects.
// you can scrap pretty much all the code above,
// but i'm giving it here so you see it in the full context.
#region ISynchronizeInvoke extensions
#if System_ComponentModel
public static TResult SafeInvoke<T, TResult>(this T isi, Func<T, TResult> callFunction) where T : ISynchronizeInvoke
{
if (isi.InvokeRequired)
{
IAsyncResult result = isi.BeginInvoke(callFunction, new object[] { isi });
object endResult = isi.EndInvoke(result); return (TResult)endResult;
}
else
return callFunction(isi);
}
/// <summary>
/// This can be used in C# with:
/// txtMyTextBox.SafeInvoke(d => d.Text = "This is my new Text value.");
/// or:
/// txtMyTextBox.SafeInvoke(d => d.Text = myTextStringVariable);
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="isi"></param>
/// <param name="callFunction"></param>
public static void SafeInvoke<T>(this T isi, Action<T> callFunction) where T : ISynchronizeInvoke
{
if (isi.InvokeRequired) isi.BeginInvoke(callFunction, new object[] { isi });
else
callFunction(isi);
}
#endif
#endregion
// other #Region blocks are removed from here too.
} // static class MyExtensions
} // namespace
幸せなコーディング!