简体   繁体   English

c# - 在执行期间将信息传递给BackgroundWorker

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

I have ac# application that uses a background worker thread, and quite successfully updates the UI from the running thread. 我有一个使用后台工作线程的ac#应用程序,并且非常成功地从正在运行的线程更新UI。 The application involves shortest path routing on a network, and I display the network and the shortest path, on the UI, as the background worker proceeds. 该应用程序涉及网络上的最短路径路由,并在后台工作进行时在UI上显示网络和最短路径。 I would like to allow the user to slow down the display through use of a slider, while the application is running. 我希望允许用户在应用程序运行时通过使用滑块来降低显示速度。

I found this as a suggestion, but it is in vb.net, I am not clear on how to get it to work in c#. 我发现这是一个建议,但它在vb.net中,我不清楚如何让它在c#中工作。

How can the BackgroundWorker get values from the UI thread while it is running? BackgroundWorker如何在UI线程运行时从UI线程获取值?

I can pass the value of the slider to the backgroundworker as follows: 我可以将滑块的值传递给backgroundworker,如下所示:

// Start the asynchronous operation. //启动异步操作。 delay = this.trackBar1.Value; delay = this.trackBar1.Value; backgroundWorker1.RunWorkerAsync(delay); backgroundWorker1.RunWorkerAsync(延迟);

and use it within the backgroundworker thread, but it only uses the initially-sent value. 并在backgroundworker线程中使用它,但它只使用初始发送的值。 I am not clear on how to pick up the value from inside the backgroundworker when I move the slider on the UI. 当我在UI上移动滑块时,我不清楚如何从backgroundworker中获取值。

I have previously used multiple threads and delegates, but if it is possible to utilize the background worker, I would prefer it for its simplicity. 我以前使用过多个线程和委托,但如果可以使用后台工作程序,我更喜欢它的简单性。

5/10/2012 2012/5/10

Thanks to all for your responses. 感谢大家的回复。 I am still having problems, most likely because of how I have structured things. 我仍然遇到问题,很可能是因为我的结构是如何形成的。 The heavy duty calculations for network routing are done in the TransportationDelayModel class. 网络路由的重载计算在TransportationDelayModel类中完成。 BackgroundWorker_DoWork creates an instance of this class, and then kicks it off. BackgroundWorker_DoWork创建此类的实例,然后将其踢出。 The delay is handled in TransportationDelayModel. 延迟在TransportationDelayModel中处理。

The skeleton of code is as follows: 代码框架如下:

In UI: 在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;
        }


    }

The TransportationDelayModel constructor is: 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();
    }

so I have the tdmWorker, which allows me to pass information back to the UI. 所以我有tdmWorker,它允许我将信息传递回UI。

In the internal calculations in TransportationDelayModel, I sleep for the delay period 在TransportationDelayModel的内部计算中,我睡了一段延迟时间

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

so the problem seems to be how to pass an updated slider value from the UI back to the object that is executing in the background worker. 所以问题似乎是如何将更新的滑块值从UI传递回后台工作程序中执行的对象。 I have tried a number of combinations, sort of thrashing around, to no avail, either nothing happens or I get a message about not being allowed to access what is happening on the other thread. 我已经尝试了许多组合,有点颠簸,无济于事,或者没有任何反应或者我得到一条消息,不允许访问其他线程上发生的事情。 I realize that if I were doing all the work in the DoWork event handler, then I should be able to do things as you suggest, but there is too much complexity for that to happen. 我意识到,如果我在DoWork事件处理程序中完成所有工作,那么我应该能够像你建议的那样做事,但是要做到这一点太复杂了。

Again, thank you for your suggestions and help. 再次感谢您的建议和帮助。

6/2/2012 2012年6月2日

I have resolved this problem by two methods, but I have some questions. 我已经通过两种方法解决了这个问题,但我有一些问题。 Per my comment to R. Harvey, I have built a simple application. 根据我对R. Harvey的评论,我构建了一个简单的应用程序。 It consists of a form with a run button, a slider, and a rich text box. 它由带有运行按钮,滑块和富文本框的表单组成。 The run button launches a background worker thread that instantiates an object of class "Model" that does all the work (a simplified surrogate for my TransportationModel). 运行按钮启动后台工作线程,该线程实例化“Model”类的对象,该对象执行所有工作(我的TransportationModel的简化代理)。 The Model class simply writes 100 lines to the text box, incrementing the number of dots in each line by 1, with a delay between each line based on the setting of the slider, and the slider value at the end of the line, something like this: Model类简单地在文本框中写入100行,将每行中的点数增加1,每行之间的延迟基于滑块的设置,以及行尾的滑块值,类似于这个:

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

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

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

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

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

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

The objective of this exercise is to be able to move the slider on the form while the "Model" is running, and get the delay to change (as in above). 本练习的目的是能够在“模型”运行时移动窗体上的滑块,并获得更改的延迟(如上所述)。

My first solution involves the creation of a Globals class, to hold the value of the slider: 我的第一个解决方案是创建一个Globals类,以保存滑块的值:

class Globals
{
    public static int globalDelay;
}

then, in the form, I update this value whenever the trackbar is scrolled: 然后,在表单中,每当滚动轨迹栏时我都会更新此值:

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

and in the Model, I just pick up the value of the global: 在模型中,我只是拿起全局的价值:

 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);

     }
 }
}

This works just fine. 这很好用。 My question: are there any drawbacks to this approach, which seems very simple to implement and quite general. 我的问题是:这种方法有什么缺点,实现起来非常简单,非常普遍。

The second approach, based on suggestions by R. Harvey, makes use of delegates and invoke. 第二种方法基于R. Harvey的建议,利用代表并调用。

I create a class for delegates: 我为代表创建了一个类:

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

in the form, I create: 在表单中,我创建:

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

    } 

and the Model class now has a member m_CheckTrackBarValue 并且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;
}

When the background thread is launched by the run button, the calling form is passed 当运行按钮启动后台线程时,将传递调用表单

private void button1_Click(object sender, EventArgs e) { if (backgroundWorker1.IsBusy != true) { 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;
        }
    }

Finally, in the Model, the Invoke method is called on the passed form to get the value of the trackbar. 最后,在Model中,在传递的表单上调用Invoke方法以获取轨迹栏的值。 public void Run(BackgroundWorker worker, DoWorkEventArgs e) { 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);

     }
 }

This works as well. 这也有效。 I kept getting an error until I made the member variable static, eg public static MyDelegates.DelegateCheckTrackBarValue m_CheckTrackBarValue=null; 我一直收到错误,直到我将成员变量设为静态,例如public static MyDelegates.DelegateCheckTrackBarValue m_CheckTrackBarValue = null;

My questions on this solution: Are there advantages to this solution as regards to the previous version? 我对这个解决方案的疑问:对于以前的版本,此解决方案是否有优势? Am I making things too complicated in the way I have implemented this? 我的实施方式是否使事情过于复杂? Why does m_CheckTrackBarValue need to be static. 为什么m_CheckTrackBarValue需要是静态的。

I apologize for the length of this edit, but I thought that the problem and solutions might be of interest to others. 我为这个编辑的长度道歉,但我认为问题和解决方案可能是其他人感兴趣的。

You have to pass the TrackBar object to the BackgroundWorker , not delay . 您必须将TrackBar对象传递给BackgroundWorker ,而不是delay delay doesn't change once you set it. delay不会改变。

To simplify the needed Invoke() , you can use a helper method, such as this one : 为了简化需要Invoke()您可以使用一个辅助方法,比如这一个

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

I will assume that you are already familiarized with cross-thread invocation to update the UI. 我将假设您已熟悉跨线程调用以更新UI。 So, the solution is very simple: in your worker thread, after each iteration, invoke the UI to get the slider thumb position. 因此,解决方案非常简单:在您的工作线程中,在每次迭代之后,调用UI以获取滑块的拇指位置。

To use a backgroundworker, you add a method to the DoWork property, like this: 要使用后台工作程序,请向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);

In the DoWork method, you need to check the variable where the updated delay is set. DoWork方法中,您需要检查设置更新延迟的变量。

This could be an integer field that is available on the containing Form or UI control, or it could be the TrackBar itself. 这可以是包含的Form或UI控件上可用的整数字段,也可以是TrackBar本身。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM