C#Backgroundworker:定期更新PictureBox的方法是什么?

Ste*_*hof 2 .net c# multithreading picturebox backgroundworker

我正在使用BackgroundWorker定期检查硬件开关.由于它通过慢速RS485网络连接,我必须延迟下一次状态更新.在开关状态更改时,我想更新OK/nOK图片框.这是在nOK pictureBox上实现的绿色OK图片框.这里没有真正的工作.

为了扩展性,我决定使用Backgroundworker.最后我想要一个隐藏的工人,这个

  1. 全局提供三个交换机的状态和
  2. 更新StatusChange PictureBoxes.

问题描述 启动BackgroundWorker后,它会按预期工作.然而,GUI冻结了.

我尝试了什么?MSDN的BackgroundWorker类注1 表示,该GUI应通过ProgressChanged更新.我尝试通过Worker_Switch.ReportProgress(fakeProgress ++)引发此事件并失败.PictureBox不再更新.

来自设计师的片段

this.Worker_Switch = new System.ComponentModel.BackgroundWorker();
// 
// Worker_Switch
// 
this.Worker_Switch.WorkerSupportsCancellation = true;
this.Worker_Switch.DoWork += new System.ComponentModel.DoWorkEventHandler(this.Worker_Switch_DoWork);
Run Code Online (Sandbox Code Playgroud)

主表格的片段

delegate void SetEventCallback(object sender, DoWorkEventArgs e);   // Threadsafe calls for DoWork

private void btnBackgroundworker_Click(object sender, EventArgs e)
{
    if (!Worker_Switch.IsBusy)
    {
        Worker_Switch.RunWorkerAsync();                              
    }
}

private void Worker_Switch_DoWork(object sender, DoWorkEventArgs e)
{
    // Worker Thread has no permission to change PictureBox "pictureBoxSwitchrightOK"
        // Therefore this method calls itsself in the MainThread, if necessary.
    while (!Worker_Switch.CancellationPending)
    {
      if (this.pictureBoxSwitchrightOK.InvokeRequired)              // Worker Thread
    {
            System.Threading.Thread.Sleep(400);
        SetEventCallback myCall = new SetEventCallback(Worker_Switch_DoWork);
        this.Invoke(myCall, new object[] { sender, e });
    }
    else                                                            // Main Thread
    {
        // Turns OK Picture Box invisible, if nOk State (Switch pushed)
        pictureBoxSwitchrightOK.Visible = SwitchOK("right");  // true: OK (green)
        this.Refresh();

    }
}

private bool SwitchOK(string rightOrLeft)               // select one of the switches
{ (...)}                                    // gets hardware switch status
Run Code Online (Sandbox Code Playgroud)

编辑:特别感谢laszlokiss88(3种可能性)和JMK(为了简化System.Windows.Forms工具箱中的Timer)

Toolbox的这个替代方案也有效:

this.timer_Switch.Enabled = true;
    this.timer_Switch.Interval = 400;
    this.timer_Switch.Tick += new System.EventHandler(this.timer_Switch_Tick);

    private void timer_Switch_Tick(object sender, EventArgs e)
{
    motorSwitchControl.Init();        // globally available Switch status                                               
    SwitchRight = SwitchOK("right");
    SwitchRightOK.Visible = SwitchRight; 

    SwitchLeft = SwitchOK("left");    // globally available Switch status
    SwitchLeftOK.Visible = SwitchLeft;  
    SwitchAllOK = SwitchRight & SwitchLeft;
    this.Refresh();
}
Run Code Online (Sandbox Code Playgroud)

a)是否正确,Sleep()实际上发生在工作线程中? - 没有主线程

b)如果我在DoWork中操作用户界面对象,会出现什么问题?(与MSDN注意相反) - 在主线程中工作?

c)定期更新PictureBox的正确方法是什么?DoWork,ProgressChanged,RunWorkerCompleted ......? - 来自laszlokiss88答案的三种可能性.

las*_*s88 5

您可以通过Dispatcher或Control.Begininvoke(winforms)从DoWork事件更新UI,也可以通过BackgroundWorker的ProgressChanged事件来完成:

    public MainWindow()
    {
        InitializeComponent();

        var bw = new BackgroundWorker();
        bw.WorkerReportsProgress = true;
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);
        bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
        bw.RunWorkerAsync();
    }

    void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        // You are in the main thread
        // Update the UI here
        string data = (string)e.UserState;
    }

    void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        // You are in a worker thread
        (sender as BackgroundWorker).ReportProgress(0, "right");
    }
Run Code Online (Sandbox Code Playgroud)