Control.InvokeとControl.BeginInvoke
5806 ワード
問題の導入
の下に簡単なdemoがあります.コードを見ると効果の例がわかります.winformのプログラムを新規作成し、次のコードを書きました.using System;
using System.Windows.Forms;
namespace MyExampleList
{
public partial class ControlInvokeExample : Form
{
public ControlInvokeExample()
{
InitializeComponent();
}
private void btnSayHello_Click(object sender, EventArgs e)
{
txtHello.Text = " C# ";
}
}
}
実行効果は以下の通りです:[caption id="attachment_1150"align="alignnone"width="364"]表示テキスト[/caption]では、この簡単なdemoを改造します.プログラミングでマルチスレッドを使用するのはよくありますが、ボタンをクリックするときに別のスレッドを有効にし、textboxの値を操作して変化させます.コードは以下の通りです.
using System;
using System.Threading;
using System.Windows.Forms;
namespace MyExampleList
{
public partial class ControlInvokeExample : Form
{
public ControlInvokeExample()
{
InitializeComponent();
}
private void btnSayHello_Click(object sender, EventArgs e)
{
Thread th=new Thread(new ThreadStart(StartMethord));
th.Start();
}
private void StartMethord()
{
txtHello.Text = " C# ";
}
}
}
は理論的には上のコードで実行できるはずですが、実際にはエラーが報告されます.具体的なエラーは下図のようになります:[caption id="attachment_152"align="alignnone"width="860"]スレッドインタラクションエラー[/caption]
エラー解釈:上記のエラーは、txtHelloというコントロールがthで作成されていないため、thスレッドが直接アクセスできないため、エラーを報告したことを意味します.
では、thスレッドでもUIのtxtHelloというtextboxの値を変えるにはどうすればいいのでしょうか.私たちはControlを通ります.InvokeまたはControl.BeginInvokeが実現します.
Control.InvokeとControl.BeginInvoke
Control.Invoke:このコントロールのベースウィンドウハンドルを持つスレッド上で指定した委任を実行します.Control.BeginInvoke:コントロールを作成するベースハンドルがあるスレッド上で、指定した委任を非同期で実行します.上記の説明に従って、上記のエラーコードを修正し、Invoke方式でthスレッド変更txtHelloの内容を実現します.具体的なコードは以下の通りです.私は次のような実現方法をA)と呼んでいます.
using System;
using System.Threading;
using System.Windows.Forms;
namespace MyExampleList
{
public partial class ControlInvokeExample : Form
{
public ControlInvokeExample()
{
InitializeComponent();
}
delegate void InvokeDelegate();
private void btnSayHello_Click(object sender, EventArgs e)
{
Thread th=new Thread(new ThreadStart(StartMethord));
th.Start();
}
private void StartMethord()
{
txtHello.Invoke(new InvokeDelegate(ChangeTextBox));
}
private void ChangeTextBox()
{
txtHello.Text = " C# ";
}
}
}
thスレッドがtxtHelloの内容を変更することをBeginInvoke方式で実現し、具体的なコードは以下の通りである.私は次のような実現方法をB)と呼んでいます.
using System;
using System.Threading;
using System.Windows.Forms;
namespace MyExampleList
{
public partial class ControlInvokeExample : Form
{
public ControlInvokeExample()
{
InitializeComponent();
}
delegate void InvokeDelegate();
private void btnSayHello_Click(object sender, EventArgs e)
{
Thread th=new Thread(new ThreadStart(StartMethord));
th.Start();
}
private void StartMethord()
{
txtHello.BeginInvoke(new InvokeDelegate(ChangeTextBox));
}
private void ChangeTextBox()
{
txtHello.Text = " C# ";
}
}
}
AとBの2つの実現方式を比較してみると、コード上の違いは、AがtxtHelloを使用していることだけだ.InvokeとB方式はtxtHelloを使った.BeginInvoke、つまり彼らの違いはまたInvokeとBeginInvokeに帰して、1つは同期で、1つは非同期で、つまりA方式の時はInvokeの実行結果を待って、B方式の時は直接実行してBeginInvokeの実行結果を待たない.本例のdemoでは方式AとBで実現する効果は同じであるが,原理が異なり,それだけである.次は新しいdemoを書き直して、この2つの方法の違いを見せてみましょう.変更されたインスタンスコードは次のとおりです.using System;
using System.Threading;
using System.Windows.Forms;
namespace MyExampleList
{
public partial class ControlInvokeExample : Form
{
public ControlInvokeExample()
{
InitializeComponent();
}
delegate void InvokeDelegate();
private void btnSayHello_Click(object sender, EventArgs e)
{
Thread th=new Thread(new ThreadStart(StartMethord));
th.Start();
}
private void StartMethord()
{
DateTime dt1 = DateTime.Now;
txtHello.Invoke(new InvokeDelegate(ChangeTextBox));// ChangeTextBox , str
// txtHello.BeginInvoke(new InvokeDelegate(ChangeTextBox));// ChangeTextBox , str
string str= (DateTime.Now - dt1).TotalMilliseconds.ToString();
}
private void ChangeTextBox()
{
Thread.Sleep(3000);
txtHello.Text = " C# "+DateTime.Now.ToString();
}
}
}
実行後の結果は、[caption id="attachment_1154"align="alignnone"width="630"]の2つの図である.invoke結果[/caption][caption id="attachment_155"align="alignnone"width="584"]
BeginInvokeの結果[/caption]は明らかに差があるでしょう.