c#-在执行期间从UI将信息传递给BackgroundWorker [英] c# - Pass information to BackgroundWorker From UI during execution

查看:87
本文介绍了c#-在执行期间从UI将信息传递给BackgroundWorker的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用后台工作程序线程的c#应用程序,并且非常成功地从正在运行的线程中更新了UI.该应用程序涉及网络上的最短路径路由,随着后台工作人员的进行,我在UI上显示网络和最短路径.我想允许用户在应用程序运行时通过使用滑块来减慢显示速度.

I have a c# application that uses a background worker thread, and quite successfully updates the UI from the running thread. 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. I would like to allow the user to slow down the display through use of a slider, while the application is running.

我发现这是一个建议,但是它在vb.net中,我不清楚如何使其在c#中工作.

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#.

如何UIWorker运行时,BackgroundWorker可以从UI线程获取值吗?

我可以将滑块的值传递给背景工作人员,如下所示:

I can pass the value of the slider to the backgroundworker as follows:

//开始异步操作. 延迟= this.trackBar1.Value; backgroundWorker1.RunWorkerAsync(delay);

// Start the asynchronous operation. delay = this.trackBar1.Value; backgroundWorker1.RunWorkerAsync(delay);

并在backgroundworker线程中使用它,但它仅使用初始发送的值.当我在UI上移动滑块时,我不清楚如何从后台工作人员内部获取值.

and use it within the backgroundworker thread, but it only uses the initially-sent value. I am not clear on how to pick up the value from inside the backgroundworker when I move the slider on the UI.

我以前使用过多个线程和委托,但是如果可以利用后台工作程序,那么我会选择它为简单起见.

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

5/10/2012

感谢大家的回应.我仍然有问题,很可能是因为我如何安排事物.网络路由的重型计算是在TransportationDelayModel类中完成的. BackgroundWorker_DoWork创建此类的实例,然后将其启动.延迟在TransportationDelayModel中处理.

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. BackgroundWorker_DoWork creates an instance of this class, and then kicks it off. The delay is handled in TransportationDelayModel.

代码框架如下:

在用户界面中:

 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构造函数为:

The TransportationDelayModel constructor is:

 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.

so I have the tdmWorker, which allows me to pass information back to the UI.

在TransportationDelayModel的内部计算中,我睡了一段延迟时间

In the internal calculations in TransportationDelayModel, I sleep for the delay period

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

所以问题似乎出在如何将更新的滑块值从UI传递回在后台工作程序中执行的对象.我尝试了多种组合,经过反复尝试,无济于事,或者什么也没有发生,或者我收到一条消息,通知我不允许访问其他线程上发生的事情.我意识到,如果我正在DoWork事件处理程序中完成所有工作,那么我应该能够按照您的建议去做,但是这样做太复杂了.

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. 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.

再次感谢您的建议和帮助.

Again, thank you for your suggestions and help.

2012年6月2日

我已经通过两种方法解决了这个问题,但是我有一些疑问.根据我对R. Harvey的评论,我构建了一个简单的应用程序.它由带有运行按钮,滑块和富文本框的表单组成.运行按钮将启动一个后台工作线程,该线程实例化一个完成所有工作的类"Model"的对象(我的TransportationModel的简化替代). Model类仅将100行写入文本框,将每行中的点数增加1,并根据滑块的设置在每行之间以及行尾的滑块值之间有一个延迟,例如这个:

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. 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). 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:

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

我的第一个解决方案涉及创建Globals类,以保存滑块的值:

My first solution involves the creation of a Globals class, to hold the value of the slider:

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.

第二种方法基于R. Harvey的建议,它使用委托和调用.

The second approach, based on suggestions by R. Harvey, makes use of delegates and invoke.

我为代表创建一个类:

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

在表单中,我创建:

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

    } 

并且Model类现在具有成员m_CheckTrackBarValue

and the Model class now has a member 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(对象发送者,EventArgs e) { 如果(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;
        }
    }

最后,在模型中,在传递的表单上调用Invoke方法以获取跟踪栏的值. 公共无效运行(BackgroundWorker worker,DoWorkEventArgs e) {

Finally, in the Model, the Invoke method is called on the passed form to get the value of the trackbar. 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);

     }
 }

这也可以.在将成员变量设为静态之前,我一直收到错误消息,例如 公共静态MyDelegates.DelegateCheckTrackBarValue m_CheckTrackBarValue = null;

This works as well. I kept getting an error until I made the member variable static, e.g. public static MyDelegates.DelegateCheckTrackBarValue m_CheckTrackBarValue=null;

有关此解决方案的问题:与以前的版本相比,该解决方案是否有优势?我在实施此方法时是否使事情变得太复杂了?为什么m_CheckTrackBarValue必须是静态的.

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.

对于本次编辑的长度我深表歉意,但我认为问题和解决方案可能会让其他人感兴趣.

I apologize for the length of this edit, but I thought that the problem and solutions might be of interest to others.

推荐答案

您必须将TrackBar对象传递给BackgroundWorker,而不是delay.设置后,delay不会更改.

You have to pass the TrackBar object to the BackgroundWorker, not delay. delay doesn't change once you set it.

要简化所需的Invoke(),可以使用辅助方法,例如

To simplify the needed Invoke(), you can use a helper method, such as this one:

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

这篇关于c#-在执行期间从UI将信息传递给BackgroundWorker的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆