C# WinForms应用程序w/BackgroundWorker&;类对象事件

C# WinForms应用程序w/BackgroundWorker&;类对象事件,c#,winforms,backgroundworker,C#,Winforms,Backgroundworker,我正在开发一个WinForms应用程序,它可以进行大量的文件处理。此处理在多个类对象中完成,这些类对象具有发布不同类型消息的“事件”。一种是正在进行的工作的“状态”,另一种是记录问题或所做更改的“输出” 我添加了一个BackgroundWorker流程,工作正常,但我看到的唯一通知是ProgressPercentage。如果我订阅并引发任何类事件,我会得到一个“跨线程操作…”,这是可以理解的。为了让winforms应用程序和非交互式进程也可以使用这些组件,实现这一点的最佳方法是什么 以下是我的嫁

我正在开发一个WinForms应用程序,它可以进行大量的文件处理。此处理在多个类对象中完成,这些类对象具有发布不同类型消息的“事件”。一种是正在进行的工作的“状态”,另一种是记录问题或所做更改的“输出”

我添加了一个BackgroundWorker流程,工作正常,但我看到的唯一通知是ProgressPercentage。如果我订阅并引发任何类事件,我会得到一个“跨线程操作…”,这是可以理解的。为了让winforms应用程序和非交互式进程也可以使用这些组件,实现这一点的最佳方法是什么

以下是我的嫁妆现在的样子,但这些事件导致了“交叉线”:

因此,根据PMF的评论,我得出以下结论:

void search_RaiseUpdateOutputEvent(object sender, UpdateEventArgs e)
{
    if (InvokeRequired)
    {
         this.Invoke( (MethodInvoker)delegate{ txtOutput.Text += e.Update; });
    }

}

void search_RaiseUpdateSearchEvent(object sender, UpdateEventArgs e)
{
    if (InvokeRequired)
    {
         this.Invoke((MethodInvoker)delegate { txtSearching.Text = e.Update; });
    }

}
但也要看到并理解Hans Passant对结构问题的担忧,以及我的架构存在缺陷,仍然需要额外的工作

谢谢

dbl

您需要从后台工作线程调用()任何用户界面事件。或者在表单代码中调用实际的更新(后面的解决方案可能是更好的方法,因为它将UI逻辑保留在应用程序的UI部分)

这将类似于以下内容(对于侦听状态更改的事件处理程序):


BackgroundWorker.ReportProgress()有一个带有两个参数的重载。第二个可以是你想要的任何东西。像代表一样:

    public event EventHandler Foo;

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
        //...
        backgroundWorker1.ReportProgress(0, new Action(() => {
            var handler = Foo;
            if (handler != null) handler(this, EventArgs.Empty);
        }));
        //...
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) {
        if (e.UserState != null) ((Action)e.UserState)();
        else this.progressBar1.Value = e.ProgressPercentage;   // optional
    }

我添加了一些代码以使其更加清晰,但我不知道如何传递这样的委托以捕获适当的事件,但我承认委托不是我的强套件。这与“捕获”事件无关,只与引发事件有关。然后我仍然不明白这有何帮助。这些事件发生在一个完全不同于DoWork的类中。我在最初的问题中添加了一些代码。这个答案基于这样的假设:您希望从后台工作程序引发事件,并修复事件处理程序因异常而爆炸的错误。这需要在UI线程而不是工作线程上引发事件。我展示的代码实现了这一点。试试看。好的,那么我需要一些帮助来建立连接。“事件”发生在单独的代码空间(类)中,并在那里引发。我不能把它移到嫁妆法。如果有某种方式,那么使用委托订阅该事件,我看不到你给出的代码。如果我理解这是在DoWork方法中调用的对象上,它不知道文本控件,我将保持这种方式。如果我误解了,也许我在问题中添加的代码对我们双方都有帮助。请参阅上面的答案。这将是
backgroundWorker1\u ProgressChanged
的实现。
void search_RaiseUpdateOutputEvent(object sender, UpdateEventArgs e)
{
    if (InvokeRequired)
    {
         this.Invoke( (MethodInvoker)delegate{ txtOutput.Text += e.Update; });
    }

}

void search_RaiseUpdateSearchEvent(object sender, UpdateEventArgs e)
{
    if (InvokeRequired)
    {
         this.Invoke((MethodInvoker)delegate { txtSearching.Text = e.Update; });
    }

}
public void OnStatusUpdated(Status newStatus)
{
     if (InvokeRequired)
     {
         Invoke(delegate
            {
                statusControl.Text = newStatus.ToString(); // Or something like it.
            });
     }
}
    public event EventHandler Foo;

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) {
        //...
        backgroundWorker1.ReportProgress(0, new Action(() => {
            var handler = Foo;
            if (handler != null) handler(this, EventArgs.Empty);
        }));
        //...
    }

    private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) {
        if (e.UserState != null) ((Action)e.UserState)();
        else this.progressBar1.Value = e.ProgressPercentage;   // optional
    }