如何从后台工作人员的外部类调用的方法调用表单上的方法?

发布于 2024-08-02 07:02:15 字数 699 浏览 5 评论 0原文

如何从后台工作人员的外部类调用的方法调用表单上的方法?我相信代表们在某种程度上是这个问题的答案,但在花时间阅读之后,我仍然对这个问题感到困惑。

这是在 Visual Studio 2008 中,backgroundWorker 从表单运行并调用 ExternalClass.Method。该表单位于命名空间 ProgramName 中,ExternalClass 使用 ProgramName。当我在 windows.form 文件的 namespace ProgramName 中声明 public delegate MyDelegate 时,我可以创建一个MyDelegate 的实例并在我的表单的方法中调用它(但这对我没有帮助),但是如果我尝试创建 MyDelegate 的实例并从我的外部类的方法我无法访问 windows.form 的方法,即使它是公共的。

谢谢

,是的,我想从 ExternalClass.Method 传回进度报告(整数百分比,字符串状态)。您能多解释一下 CSharpAtl (或任何人)吗?

How can I call a method on a form from a method called from an external class from a backgroundWorker? I believe that delegates are somehow the answer to this question, but after spending time reading, I still am confused by this problem.

This is in Visual Studio 2008, the backgroundWorker is run from the form and calls ExternalClass.Method. The form is in namespace ProgramName and the ExternalClass is using ProgramName. When i declare public delegate MyDelegate in the namespace ProgramName in the file of my windows.form I can create an instance of MyDelegate and call it in a method of my form (but this does not help me), but if I try to create an instance of MyDelegate and call it from a method of my external class I cannot access the method of the windows.form, even though it is public.

thanks

yes, I want to pass progress reports (int percent, string status) back from ExternalClass.Method. Can you explain a bit more about that CSharpAtl (or anyone)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

动次打次papapa 2024-08-09 07:02:15

主要要认识到的是,这里实际上有两个级别的同步:Form 和BackgroundWorker 之间,以及BackgroundWorker 和ExternalClass 对象之间。

该表单正在异步调用在另一个线程中运行的 BackgroundWorker.DoWork()。对表单的任何更新都应通过 Form.Invoke() (它在表单线程中触发任意委托)进行,或者更好的是通过 BackgroundWorker.ProgressChanged 事件(它会在表单线程中触发特定事件)。

因此,您想要做的是将状态更新从ExternalClass 方法代理回BackgroundWorker,后者又将它们推送到Form。我过去这样做的一种方法是使用回调委托:

public delegate void ProgressCallback(double percentCompleted, string status);

并让我昂贵的工作方法将回调作为参数:

public void ExpensiveMethod(ProgressCallback callback) {
    while(doingThings) {
        if(callback != null) callback(percentDone, statusString);
    }
}

然后在您的BackgroundWorker类中,定义一个与您的回调委托匹配的方法,并让它调用< code>BackgroundWorker.ReportProgress() 触发 BackgroundWorker.ProgressChanged 事件,该事件又可以更新表单的状态。

更新:这与 Henk Holterman 在他的新编辑中建议的解决方案基本相同。

The main thing to realize is that you actually have two levels of synchronization going on here: between the Form and the BackgroundWorker, and between the BackgroundWorker and the ExternalClass object.

The Form is asynchronously invoking BackgroundWorker.DoWork(), which is running in another thread. Any updates to the Form should come through Form.Invoke() (which fires an arbitrary delegate in the Form's thread) or, better yet, through the BackgroundWorker.ProgressChanged event (which fires a specific event in the Form's thread).

So what you want to do is proxy the status updates from the ExternalClass method back to the BackgroundWorker, which will in turn push them on to the Form. One way I've done this in the past is to use a callback delegate:

public delegate void ProgressCallback(double percentCompleted, string status);

And have my expensive worker method take the callback as an argument:

public void ExpensiveMethod(ProgressCallback callback) {
    while(doingThings) {
        if(callback != null) callback(percentDone, statusString);
    }
}

Then in your BackgroundWorker class, define a method that matches your callback delegate, and have it call BackgroundWorker.ReportProgress() to trigger the BackgroundWorker.ProgressChanged event, which can in turn update your Form's state.

Update: this is basically the same as the solution Henk Holterman suggested in his new edit.

落墨 2024-08-09 07:02:15

请注意,您的问题(afaik)不仅仅是关于背景,而是关于如何打破类之间的循环引用。这是一个有标准解决方案的标准问题。

您可以像任何对象一样传递委托(指表单方法),也可以传递给后台工作人员。 Bgw 可以将其传递给外部方法。委托包括对对象(在本例中为表单)的引用。

请注意,由于您位于另一个线程上,因此您需要在委托内使用 Control.Invoke,或使用 Bgw ReportProgress 事件。

public partial class Form1 : Form
{
    private void ReportProgresshandler(int percent, string state)
    {
        backgroundWorker1.ReportProgress(percent);  // also does the Invoke
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        var ex = new ExampleClass();
        ex.Dowork(ReportProgresshandler);    
    }
}

和类似的东西

class ExampleClass
{
    delegate void ReportDelegate(int percent, string status);

    public void Dowork(ReportDelegate report)
    {
        report(0, "starting");
    }

}

Note that your question (afaik) is not just about the backgroundwiorker but just as much about how to break a circular reference between classes. This is a standard problem with a standard solution.

You can pass a delegate (referring to a Form-method) around just as any object so also to a Backgroundworker. And the Bgw can pass it to the external method. A delegate includes a reference to the object (in this case the Form).

Note that since you are on another thread you will need to use Control.Invoke inside the delegate, or use the Bgw ReportProgress event.

public partial class Form1 : Form
{
    private void ReportProgresshandler(int percent, string state)
    {
        backgroundWorker1.ReportProgress(percent);  // also does the Invoke
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        var ex = new ExampleClass();
        ex.Dowork(ReportProgresshandler);    
    }
}

and something like

class ExampleClass
{
    delegate void ReportDelegate(int percent, string status);

    public void Dowork(ReportDelegate report)
    {
        report(0, "starting");
    }

}
世界如花海般美丽 2024-08-09 07:02:15

我不知道出了什么问题。您也可以使用委托,但不需要委托。

using System.Windows.Forms;
using System.ComponentModel;

public partial class ExampleForm : Form
{

    public ExampleForm()
    {
        InitializeComponent();

        var worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(doWork);
        worker.RunWorkerAsync(this);
    }

    void doWork(object sender, DoWorkEventArgs e)
    {
        ExampleForm f = e.Argument as ExampleForm;
        f.Hello();
    }

    private void Hello()
    {

    }

}

I'm not sure what the trouble is. And also you can use a delegate, but don't need one.

using System.Windows.Forms;
using System.ComponentModel;

public partial class ExampleForm : Form
{

    public ExampleForm()
    {
        InitializeComponent();

        var worker = new BackgroundWorker();
        worker.DoWork += new DoWorkEventHandler(doWork);
        worker.RunWorkerAsync(this);
    }

    void doWork(object sender, DoWorkEventArgs e)
    {
        ExampleForm f = e.Argument as ExampleForm;
        f.Hello();
    }

    private void Hello()
    {

    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文