簡體   English   中英

c# - 在執行期間將信息傳遞給BackgroundWorker

[英]c# - Pass information to BackgroundWorker From UI during execution

我有一個使用后台工作線程的ac#應用程序,並且非常成功地從正在運行的線程更新UI。 該應用程序涉及網絡上的最短路徑路由,並在后台工作進行時在UI上顯示網絡和最短路徑。 我希望允許用戶在應用程序運行時通過使用滑塊來降低顯示速度。

我發現這是一個建議,但它在vb.net中,我不清楚如何讓它在c#中工作。

BackgroundWorker如何在UI線程運行時從UI線程獲取值?

我可以將滑塊的值傳遞給backgroundworker,如下所示:

//啟動異步操作。 delay = this.trackBar1.Value; backgroundWorker1.RunWorkerAsync(延遲);

並在backgroundworker線程中使用它,但它只使用初始發送的值。 當我在UI上移動滑塊時,我不清楚如何從backgroundworker中獲取值。

我以前使用過多個線程和委托,但如果可以使用后台工作程序,我更喜歡它的簡單性。

2012/5/10

感謝大家的回復。 我仍然遇到問題,很可能是因為我的結構是如何形成的。 網絡路由的重載計算在TransportationDelayModel類中完成。 BackgroundWorker_DoWork創建此類的實例,然后將其踢出。 延遲在TransportationDelayModel中處理。

代碼框架如下:

在UI中:

 private void runToolStripMenuItem1_Click(object sender, EventArgs e)
    {
        if (sqliteFileName.Equals("Not Set"))
        {
            MessageBox.Show("Database Name Not Set");
            this.chooseDatabaseToolStripMenuItem_Click(sender, e);

        }

        if (backgroundWorker1.IsBusy != true)
        {
            // Start the asynchronous operation.
            delay = this.trackBar1.Value;
            // pass the initial value of delay
            backgroundWorker1.RunWorkerAsync(delay);
            // preclude multiple runs
            runToolStripMenuItem1.Enabled = false;
            toolStripButton2.Enabled = false;
        }

    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        BackgroundWorker worker = sender as BackgroundWorker;

        if (!backgroundWorkerLaunched)
        {
            // instantiate the object that does all the heavy work
            TransportationDelayModel TDM = new TransportationDelayModel(worker, e);               
            // kick it off
            TDM.Run(sqliteFileName, worker, e);
            backgroundWorkerLaunched = true;
        }


    }

TransportationDelayModel構造函數是:

 public TransportationDelayModel(BackgroundWorker worker, DoWorkEventArgs e)
    {
        listCentroids = new List<RoadNode>();
        listCentroidIDs = new List<int>();
        listNodes = new List<RoadNode>();
        listNodeIDs = new List<int>();
        listRoadLink = new List<RoadLink>();
        roadGraph = new AdjacencyGraph<int, RoadLink>(true); // note parallel edges allowed
        tdmWorker = worker;
        tdmEvent = e;
        networkForm = new NetworkForm();
    }

所以我有tdmWorker,它允許我將信息傳遞回UI。

在TransportationDelayModel的內部計算中,我睡了一段延遲時間

  if (delay2 > 0)
                                    {
                                        tdmWorker.ReportProgress(-12, zzz);
                                        System.Threading.Thread.Sleep(delay2);
                                    }

所以問題似乎是如何將更新的滑塊值從UI傳遞回后台工作程序中執行的對象。 我已經嘗試了許多組合,有點顛簸,無濟於事,或者沒有任何反應或者我得到一條消息,不允許訪問其他線程上發生的事情。 我意識到,如果我在DoWork事件處理程序中完成所有工作,那么我應該能夠像你建議的那樣做事,但是要做到這一點太復雜了。

再次感謝您的建議和幫助。

2012年6月2日

我已經通過兩種方法解決了這個問題,但我有一些問題。 根據我對R. Harvey的評論,我構建了一個簡單的應用程序。 它由帶有運行按鈕,滑塊和富文本框的表單組成。 運行按鈕啟動后台工作線程,該線程實例化“Model”類的對象,該對象執行所有工作(我的TransportationModel的簡化代理)。 Model類簡單地在文本框中寫入100行,將每行中的點數增加1,每行之間的延遲基於滑塊的設置,以及行尾的滑塊值,類似於這個:

.................... 58

..................... 58

...................... 58

....................... 51

........................ 44

......................... 44

本練習的目的是能夠在“模型”運行時移動窗體上的滑塊,並獲得更改的延遲(如上所述)。

我的第一個解決方案是創建一個Globals類,以保存滑塊的值:

class Globals
{
    public static int globalDelay;
}

然后,在表單中,每當滾動軌跡欄時我都會更新此值:

private void trackBar1_Scroll(object sender, EventArgs e)
    {
        Globals.globalDelay = this.trackBar1.Value;
    } 

在模型中,我只是拿起全局的價值:

 public void Run(BackgroundWorker worker, DoWorkEventArgs e)
 {

     for (int i = 1; i < 100; i++)
     {
         delay = Globals.globalDelay; // revise delay based on static global set on UI
         System.Threading.Thread.Sleep(delay);
         worker.ReportProgress(i);
         string reportString = ".";
         for (int k = 0; k < i; k++)
         {
             reportString += ".";
         }
         reportString += delay.ToString();
         worker.ReportProgress(-1, reportString);

     }
 }
}

這很好用。 我的問題是:這種方法有什么缺點,實現起來非常簡單,非常普遍。

第二種方法基於R. Harvey的建議,利用代表並調用。

我為代表創建了一個類:

 public class MyDelegates
{
    public delegate int DelegateCheckTrackBarValue(); // create the delegate here
}

在表單中,我創建:

  public int CheckTrackBarValue()
    {
        return this.trackBar1.Value;

    } 

並且Model類現在有一個成員m_CheckTrackBarValue

 public class Model 
{

#region Members

Form1 passedForm;
public static MyDelegates.DelegateCheckTrackBarValue m_CheckTrackBarValue=null;      
#endregion Members

#region Constructor
public Model(BackgroundWorker worker, DoWorkEventArgs e, Form1 form)
{
    passedForm = form;
}

當運行按鈕啟動后台線程時,將傳遞調用表單

private void button1_Click(object sender,EventArgs e){if(backgroundWorker1.IsBusy!= true){

            backgroundWorker1.RunWorkerAsync();

        }
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {

        BackgroundWorker worker = sender as BackgroundWorker;

        if (!backgroundWorkerLaunched)
        {
            // instantiate the object that does all the heavy work
            Model myModel= new Model(worker, e, this);

            Model.m_CheckTrackBarValue = new MyDelegates.DelegateCheckTrackBarValue(this.CheckTrackBarValue);

            // kick it off
            myModel.Run(worker, e);
            backgroundWorkerLaunched = true;
        }
    }

最后,在Model中,在傳遞的表單上調用Invoke方法以獲取軌跡欄的值。 public void Run(BackgroundWorker worker,DoWorkEventArgs e){

     for (int i = 1; i < 100; i++)
     {
         int delay = (int)passedForm.Invoke(m_CheckTrackBarValue,null); // invoke the method, note need the cast here
         System.Threading.Thread.Sleep(delay);
         worker.ReportProgress(i);
         string reportString = ".";
         for (int k = 0; k < i; k++)
         {
             reportString += ".";
         }
         reportString += delay.ToString();
         worker.ReportProgress(-1, reportString);

     }
 }

這也有效。 我一直收到錯誤,直到我將成員變量設為靜態,例如public static MyDelegates.DelegateCheckTrackBarValue m_CheckTrackBarValue = null;

我對這個解決方案的疑問:對於以前的版本,此解決方案是否有優勢? 我的實施方式是否使事情過於復雜? 為什么m_CheckTrackBarValue需要是靜態的。

我為這個編輯的長度道歉,但我認為問題和解決方案可能是其他人感興趣的。

您必須將TrackBar對象傳遞給BackgroundWorker ,而不是delay delay不會改變。

為了簡化需要Invoke()您可以使用一個輔助方法,比如這一個

Async.UI(delegate { textBox1.Text = "This is way easier!"; }, textBox1, true);

我將假設您已熟悉跨線程調用以更新UI。 因此,解決方案非常簡單:在您的工作線程中,在每次迭代之后,調用UI以獲取滑塊的拇指位置。

要使用后台工作程序,請向DoWork屬性添加方法,如下所示:

this.backgroundWorker1.WorkerSupportsCancellation = true;
this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);

DoWork方法中,您需要檢查設置更新延遲的變量。

這可以是包含的Form或UI控件上可用的整數字段,也可以是TrackBar本身。

暫無
暫無

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

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