4

私は得続けます

Cross-thread operation not valid: Control 'keyholderTxt' accessed from a thread other than the thread it was created on.

プロジェクトのさまざまなフォームのさまざまなコントロールについて、私はそれをグーグルで検索し、さまざまなスレッドからのものにアクセスする方法について多くの応答を見つけましたが、私が知る限り、私は自分のプロジェクトで他のスレッドを使用しておらず、コード内の何百もの可能な場所を変更すると、管理が困難になります。

関係のないように見えるさまざまなコードを追加したためだけに、これは決して起こりませんでした。以下にエラーが発生する場所のサンプルを含めますが、ソリューション全体で非常に多くの場所でエラーが発生しています。

keyholderTxt.Text = "Keyholders Currently In:\r\n \r\n Nibley 1: + keyholders";

または、これはより良い例です。フォームの読み込みからエラーまでに発生するすべてを確認できます。

      private void Identification_Load(object sender, System.EventArgs e)
    {
        _Timer.Interval = 1000;
        _Timer.Tick += new EventHandler(_Timer_Tick);
        _Timer.Start();

        txtIdentify.Text = string.Empty;
        rightIndex = null;

        SendMessage(Action.SendMessage, "Place your finger on the reader.");

        if (!_sender.OpenReader())
        {
            this.Close();
        }

        if (!_sender.StartCaptureAsync(this.OnCaptured))
        {
            this.Close();
        }
    }

    void _Timer_Tick(object sender, EventArgs e)
    {
        this.theTime.Text = DateTime.Now.ToString();
    }

    private void OnCaptured(CaptureResult captureResult)
    {
       txtIdentify.Clear();
       //other stuff after the cross thread error
    }

datareaders を閉じないと、この種のエラーが発生する可能性はありますか?

Windows フォーム アプリケーションを使用しています。

4

4 に答える 4

7

犯人はこれだと思います:

if (!_sender.StartCaptureAsync(this.OnCaptured))

使用している API はわかりませんが、名前からコールバック メソッド ( OnCaptured) は UI スレッドではなく、ワーカー スレッドで呼び出されていると思います。そのため、Invoke を使用して UI スレッドでアクションを実行する必要があります。

private void OnCaptured(CaptureResult captureResult)
{
   if (InvokeRequired)
   {
       Invoke(new System.Action(() => OnCaptured(captureResult)));
       return;
   }

   txtIdentify.Clear();
   // ...
}
于 2013-08-28T12:05:08.683 に答える
3

よし、これをスクラッチ。System.Windows.Forms.Timer以下のコメントで言及されているように、既に UI スレッドで実行されているものを使用しているようです。を使っていると思っていましたSystem.Timers.Timer

間違った答え

タイマー コールバックがスレッドプール スレッドで実行されています。SynchronizingObjectを設定することで、UI スレッドで実行できます。

    _Timer.Interval = 1000;
    _Timer.Tick += new EventHandler(_Timer_Tick);
    _Timer.SynchronizingObject = this;
    _Timer.Start();
于 2013-08-28T12:03:37.530 に答える
1

VSでスレッドパネルを確認しましたか?

于 2013-08-28T11:59:35.077 に答える
1

_Timer( )からのコールバックがバックvoid _Timer_Tick(object sender, EventArgs e)グラウンド スレッドで発生しています。System.Windows.Forms.Timerコールバックを UI スレッドに配置する場合は、 (Windows フォームを使用していると仮定して) を使用してください。

コメンテーターが示唆したように。デバッガーのスレッド ウィンドウをチェックして、例外が発生しているスレッドを確認します。

または、Windowsフォームの場合、これを試してください

void _Timer_Tick(object sender, EventArgs e)
{
    this.BeginInvoke(new Action(() => this.theTime.Text = DateTime.Now.ToString()));
}

そしてWPFの場合、これを試してください

void _Timer_Tick(object sender, EventArgs e)
{
    this.Dispatcher.BeginInvoke(new Action(() => this.theTime.Text = DateTime.Now.ToString()));
}

thisがコントロールまたはウィンドウではなく、WPF を使用している場合

void _Timer_Tick(object sender, EventArgs e)
{
    System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => this.theTime.Text = DateTime.Now.ToString()));
}
于 2013-08-28T11:59:35.203 に答える