簡體   English   中英

跨線程操作-調用的函數調用另一個函數C#

[英]Cross Thread Operation - Invoked function calls another function C#

我有一個使用許多線程的程序,當其中一個線程找到答案(我認為上下文並不重要)時,它將宣布它,然后我創建的第一個線程使用Invoke在用戶控件類中調用一個函數。 我檢查了-如果更改此函數中的任何屬性,則不會得到跨線程操作。 但是此函數啟動一個計時器(System.Timers.Timer)->,因此調用了“ Elapsed”事件的功能。 在其中,我試圖更改屬性,這會導致跨線程操作。 我究竟做錯了什么? 是否有可能讓被調用的函數調用另一個函數然后在其中更改屬性?

順便說一句,使用委托調用函數是否錯誤? 我的意思是,將委托作為我需要的類的屬性,然后使用delegAttributeName.Invoke(parameters)-而不是this.Invoke(new Delegate(),parameters);

這是代碼的一部分:

那就是我調用該函數的地方:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace Nim_Assignment_3
{

public delegate void drawDeleg(Color c, int amount, int rowNumber);

public partial class Nim : Form
{
    private event drawDeleg myDrawDeleg;

    private void CheckXor()
    {
      if (this.foundToPaint)
            {
                this.myDrawDeleg.Invoke(this.currentTurnColor, this.amountToPaint, this.rowToPaint);
                this.drawWait.WaitOne();
                this.foundToPaint = false;
                if (this.currentTurnColor == Color.Blue)
                    this.currentTurnColor = Color.Red;
                else
                    this.currentTurnColor = Color.Blue;
            }

    }

  // the invoked function:
  private void callFillPencils(Color c, int amount, int rowNumber)
  {
          this.rows[rowNumber].fillPencils(c, amount);
  }
 }
}

這是被調用函數正在調用的函數-以及它所調用的函數(計時器經過的事件函數):( fillPencils-Form類(Nim)中被調用函數正在調用的函數):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Timers;

namespace Nim_Assignment_3
{
public partial class PencilsUC : UserControl
{
    private PictureBox[] pencils;
    public static Image grayPencil = new Bitmap("GrayPen.bmp"), bluePencil = new    Bitmap("BluePen.bmp"), redPencil = new Bitmap("RedPen.bmp");
    private int amountOfPencils, amountOfPencilsLeft, currIndex, currAmount;
    private System.Timers.Timer timer;
    private Color currColor;
    public event FinishedDrawing drawFinishedDeleg;

    public PencilsUC()
    {
        // intializing things in the constructor...

        this.timer = new System.Timers.Timer();
        this.timer.Interval = 100;
        this.timer.Elapsed += new ElapsedEventHandler(timer_Tick);
    }

    public void timer_Tick(object sender, EventArgs e)
    {
        // THE THING THAT MAKES THE CROSS THREAD-OPERATION: THE LINE INSIDE THE "if"
        if (this.currColor == Color.Blue)
            pencils[currIndex--].Image = bluePencil;
        else
            pencils[currIndex--].Image = redPencil;

        this.currAmount--;

        if (this.currAmount == 0)
        {
            this.timer.Stop();
            if (this.drawFinishedDeleg != null)
                this.drawFinishedDeleg.Invoke(this, new EventArgs());
        }
    }

    public void fillPencils(Color c, int amount)
    {
        MessageBox.Show("Hello");
        this.currColor = c;
        this.currAmount = amount;
        this.timer.Start();
    }
}

}

(在TIMER_TICK函數內部發生交叉線程操作)

我最初使用Windows窗體計時器,但是由於某種原因,它沒有到達滴答事件功能(調用了timer.Start(),但是我在滴答功能中放入了一個消息框,但它沒有到達滴答功能,所以我進行了更改它-我看到一些答案說效果更好)

我希望獲得一些幫助,對於冗長的帖子,我感到抱歉,我只是想盡可能地清楚...

在此先多謝! :)

使用Windows.Forms.Timer而不是System.Timers.Timer (您需要更改一些屬性/事件的名稱,即用Tick代替Elapsed ,但這很簡單。)

與系統計時器在線程池線程中執行事件的系統計時器不同,表單名稱空間中的計時器將Tick事件編組到UI線程中。

如果您真的更喜歡使用系統的計時器,則可以設置SynchronizingObject使其將事件編組到UI線程:

timer.SynchronizingObject = this;

請注意,UserControl是可同步對象。

您需要.invoke進入主線程以更改任何控件。

Image image;
if (this.currColor == Color.Blue)
    image = bluePencil;
else
    image = redPencil;

this.Invoke(new MethodInvoker(() => pencils[currIndex--].Image = image));

=>是lambda的語法(在其他語言中稱為匿名方法)。 將其視為單行函數。

() => pencils[currIndex--].Image = image

是相同的:

void SetImage(Image image, ref int currIndex) {
    pencils[currIndex--].Image = image;
}

MethodInvoker提供了一個簡單的委托,該委托用於調用帶有無效參數列表的方法

您已經編寫了代碼,最簡單的解決方法是將Timer的SynchronizingObject設置為Form,因此timer將在UI線程上運行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM