简体   繁体   English

具有ProgressBar的BackgroundWorker-跨线程操作无效

[英]BackgroundWorker with ProgressBar - Cross-thread operation not valid

I have service call in my form application. 我的表格申请中有服务电话。 When my button has been clicked I am calling my service method. 单击我的按钮后,我将调用我的服务方法。 Here is my code block: 这是我的代码块:

void listBox_SelectedValueChanged(object sender, EventArgs e)
    {
        if (listBox.SelectedItem.Equals("Demo"))
        {
            progressBar1.Visible = true;
            backgroundWorker1.RunWorkerAsync();
        }
    }

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {   
        ObservableCollection<FilterInfo> filterInfos = new ObservableCollection<FilterInfo>();
        FilterInfo myFilterObj = new FilterInfo("SUPERVISOR", userName);
        filterInfos.Add(myFilterObj);
        ObservableCollection<DEMOBec> demos = demoSvc.GetDemoByFilter(filterInfos, false);
        dt = new Converter<DEMOBec>().ConvertDataTable(demos.ToList());
    }

Before calling the service, I make my ProgressBar (Style = Marquee) visible. 在调用该服务之前,我使ProgressBar(样式=选取框)可见。 But I couldn't make it invisible in completed method because of Cross Thread problem. 但是由于跨线程问题,我无法使其在完整的方法中不可见。

When I tried to do something with in UI thread in BGWorker's Completed event, 当我尝试在BGWorker的Completed事件中的UI线程中执行某些操作时,

void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        progressBar1.Visible = false;
    }

I am getting an exception : 我有一个例外:

Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on. 跨线程操作无效:控件“ Form1”从创建该线程的线程之外的线程访问。

How can I handle this problem? 我该如何解决这个问题?

You need to use Invoke() method 您需要使用Invoke()方法

    private delegate void ToDoDelegate();
    void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        Invoke(new ToDoDelegate(() => progressBar1.Visible = false));
    }

more info for Invoke() http://msdn.microsoft.com/de-de/library/System.Windows.Forms.Control.Invoke(v=vs.110).aspx Invoke()的详细信息http://msdn.microsoft.com/de-de/library/System.Windows.Forms.Control.Invoke(v=vs.110).aspx

Here's alittle piece of code that I always love to use, I don't remember where I got it from I put it in my Dropbox a long time ago. 这是我一直喜欢使用的小段代码,我不记得很久以前将其放在Dropbox中的位置。

public static class ControlExtensions
{
    public static TResult InvokeEx<TControl, TResult>(this TControl control,
                                               Func<TControl, TResult> func)
      where TControl : Control
    {
        return control.InvokeRequired
                ? (TResult)control.Invoke(func, control)
                : func(control);
    }

    public static void InvokeEx<TControl>(this TControl control,
                                          Action<TControl> func)
      where TControl : Control
    {
        control.InvokeEx(c => { func(c); return c; });
    }

    public static void InvokeEx<TControl>(this TControl control, Action action)
      where TControl : Control
    {
        control.InvokeEx(c => action());
    }

}

Usage 用法

this.InvokeEx( x => Progressbar1.Visible = false); //Note 'x' could be any variable

This way you won't have to type all that out each time, and it's so simple to use. 这样,您不必每次都键入所有内容,并且使用非常简单。 Just add this right to the end of your form class (after the last bracket closes). 只需将此权利添加到表单类的末尾(在最后一个括号关闭之后)。 You can use this to preform any cross thread operations safely. 您可以使用它来安全地执行任何跨线程操作。

Modify the Visibility of the ProgressBar on the UI thread. 修改UI线程上ProgressBar的可见性。

Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)
                    delegate()
                    {
                        progressBar1.Visible = false;
                    });

I think the exception isn't raised in the RunWorkerCompleted event (as in comments said). 我认为在RunWorkerCompleted事件中不会引发异常(如评论中所述)。 My suggestion is, that the lines you try to access UI cmponents in the DoWork event fires it. 我的建议是,您尝试在DoWork事件中访问UI cmponent的行会触发它。

Try to put the data you need in the DoWork event into DoWorkEventArgs e . 尝试将DoWork事件中所需的数据放入DoWorkEventArgs e Tons of examples how to do it are provided on SO like this discussion . 这样的讨论在SO上提供了大量示例。

When the work has finished, provide the "main UI thread" the modified/new data by using event args, too, like this: 工作完成后,也可以使用事件args向“主UI线程”提供已修改/新的数据,如下所示:

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
    // do some work
    e.Result = ... ; // modified/new data
}

and retrieve it in the following way: 并以以下方式检索它:

void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
    var newData = (CastToWhatever) e.Result;
}

Hope it helps =) 希望对您有帮助=)

EDIT 编辑

Your code in backgroundWorker1_RunWorkerCompleted() is definitly not the source of the exception. 您在backgroundWorker1_RunWorkerCompleted()代码绝对不是异常的来源。 It built a little and simple example to demonstrate my argment: 它构建了一个简单的示例来说明我的观点:

private void button1_Click(object sender, EventArgs e)
{
    backgroundWorker1.RunWorkerAsync(textBox1.Text);
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    var num = Int32.Parse(e.Argument.ToString()) + 1;
    backgroundWorker1.ReportProgress(num);
    e.Result = num;
}

private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = (int)e.ProgressPercentage;
}

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    textBox1.Text = e.Result.ToString();
}

What it does? 它能做什么? On the WinForm there is a TextBox with a number, a ProgressBar and a Button to start a BackGroundWorker . 在WinForm上,有一个带有数字的TextBox ,一个ProgressBar和一个用于启动BackGroundWorkerButton

The worker gets the number from the TextBox (UI thread) , DoWork increases it by 1 and saves it as result (new thread) . worker从TextBox (UI线程)获取该数字, DoWork将其增加1并将其保存为result (新线程) Additionally it reports the increased number to the ProgressBar (cross-thread) . 另外,它将增加的数字报告给ProgressBar (跨线程)

Finally RunWorkerCompleted reads out the result and stores the new value in the TextBox (UI thread) . 最后, RunWorkerCompleted读取结果并将新值存储在TextBox (UI线程)中

So, please re-check your code ;-) 因此,请重新检查您的代码;-)

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

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