C〓〓の中でスレッドをまたいでコントロールの問題の解決案にアクセスします。
第二の方法は、コンパイラがスレッドをまたぐアクセスをチェックすることを禁止することであり、アクセスを実現することができますが、エラーが発生しても、Control.CchockForIllalCross ThreadCalls=falseを保証することができません。
最近、私はプロジェクトをしていますが、スレッドをまたいでページコントロールにアクセスしたいということに出会いました。しかし、エラーが発生しました。他のスレッドでコントロールを作成するスレッドのコントロールの値を変更することはできません。その後、匿名エージェントを採用しました。結果は簡単に解決しました。解決過程は以下の通りです。まずフォーム上で、listbox、lableを作成します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace AccessControl
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread newthread = new Thread(new ThreadStart(BackgroundProcess));
newthread.Start();
}
/// <summary>
///
/// </summary>
private delegate void CrossThreadOperationControl();
private void BackgroundProcess()
{
//
CrossThreadOperationControl CrossDelete = delegate()
{
int i = 1;
while (i<5)
{
//
listBox1.Items.Add("Item " + i.ToString());
i++;
}
label1.Text = " lable!";
listBox1.Items.Add(label1.Text);
} ;
listBox1.Invoke(CrossDelete);
}
}
}
この小さい技巧があなたの学習と仕事に対して役に立つことができることを望んで、もしもっと良い方法があるならば、スレッドをまたいでコントロールにアクセスする問題を解決しにきて、みんなをも取り出して分かち合います。C〓〓がスレッドをまたいでコントロールにアクセスしている時にエラーが発生しました。MethodInvokerを使って解決できます。
元のコード:
private void btnOK_Click(object sender, EventArgs e)
{
tslInfo.Text = " ...";
Thread td = new Thread(new ThreadStart(run));
td.Start();
}
/// <summary>
///
/// </summary>
private void run()
{
this.tslInfo.Text = " ";
}
修正後:
private void btnOK_Click(object sender, EventArgs e)
{
tslInfo.Text = " ...";
Thread td = new Thread(new ThreadStart(threadRun));
td.Start();
}
/// <summary>
///
/// </summary>
private void run()
{
this.tslInfo.Text = " ";
}
/// <summary>
///
/// </summary>
private void threadRun()
{
MethodInvoker In = new MethodInvoker(run);
this.BeginInvoke(In);
}
私達はwindformアプリケーションをする時、多くの場合、マルチスレッド制御インターフェース上のコントロール情報を使用する問題に遭遇します。しかし、私たちは伝統的な方法でこの問題をすることはできません。詳しく紹介します。まず伝統的な方法を見ます。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(ThreadFuntion);
thread.IsBackground = true;
thread.Start();
}
private void ThreadFuntion()
{
while (true)
{
this.textBox1.Text = DateTime.Now.ToString();
Thread.Sleep(1000);
}
}
}
このコードを実行すると、システムが投げた異常が見られます。Cross-thread operation not valid:Control'text Box 1'accessed from a thread other thand the thread it was created on.これは.net 2.0以降にセキュリティ機構を強化し、windformの中でスレッドコントロールに直接アクセスすることができないからです。この問題をどう解決しますか?いくつかの案を提供します。最初の案はForm 1でございます。Load()メソッドにコードを追加します。
private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;
Thread thread = new Thread(ThreadFuntion);
thread.IsBackground = true;
thread.Start();
}
にこのコードを追加したら、プログラムが正常に実行されます。このコードは、このクラスではスレッドをまたぐ呼び出しが合法的かどうかを確認しません。(これを追加していないと運行に異常がないので、システムとデフォルトはチェックしない方式を採用しています。)しかし、この方法は好ましくない。私たちはCheckForIllelgalCross ThreadCallsという属性の定義を見ると、それはstaticであることが分かります。つまり、プロジェクトのどこでこの値を修正しても、彼は大局で働きます。また、このようなクロススレッドアクセスに異常があるかどうかは、通常チェックします。プロジェクトの中で他の人がこの属性を修正したら、私達の案は失敗します。私達は別の案を採用します。次に2つ目のシナリオを見ると、delegateとinvokeを使って他のスレッドからコントロール情報を制御します。ネット上では多くの人がこのような制御方式を書いていますが、私はこのような書き込みをたくさん見ました。表示上は問題がないと思いますが、実際にはこの問題を解決していません。まずネット上の不完全な方法を見に来ました。
この方法を使うと、スレッドをまたいでのアクセスの異常がなくなります。しかし、新しい問題が現れました。界面は応答しませんでした。なぜこの問題が発生したのかというと、私たちは新しく開かれたスレッドを無限に循環させるだけで、理論的にはメインスレッドに影響を与えないはずです。実際にはそうではないです。このような方法は、この新しく開かれたスレッドをメインコントロールスレッドに「注入」することに相当します。これはメインスレッドの制御をとりました。このスレッドが戻らない限り、メインラインは永遠に応答しません。新しく開かれたスレッドの中で無限ループを使わなくても、戻せるようにします。このような方式のマルチスレッドの使用も本来の意味を失った。
今回はオススメの解決策を見てみましょう。
上記のコードを実行すると、問題が解決されたことが分かります。非同期を待つことによって、メインスレッドの制御を常に保持しないようにします。これにより、マルチスレッドによるWindows formマルチスレッドコントロールの制御が完了します。
深山さんが提出した問題について、最近より優れた解決策を見つけました。delegateの非同期呼び出しを利用して、見てください。
public partial class Form1 : Form
{
private delegate void FlushClient();//
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(CrossThreadFlush);
thread.IsBackground=true;
thread.Start();
}
private void CrossThreadFlush()
{
//
FlushClient fc = new FlushClient(ThreadFuntion);
this.BeginInvoke(fc);//
}
private void ThreadFuntion()
{
while (true)
{
this.textBox1.Text = DateTime.Now.ToString();
Thread.Sleep(1000);
}
}
}
この方法は直接に簡略化できます。