【问题标题】:Cause Object to Respond to Button Click使对象响应按钮单击
【发布时间】:2014-02-20 22:34:43
【问题描述】:

我正在寻找一种方法来获取具有正在运行的进程的对象以响应 Windows 窗体按钮单击。此实用程序中的所有内容都发生在一个“主”Windows 应用程序表单上。

该过程正在浏览文件夹中的一堆文件,我想在表单上放置一个“暂停”按钮。

我可以创建一个全局变量,通过按钮更改其状态,并让对象在其过程中检查变量的状态。

但我想编写更好的软件,我怀疑有一种方法可以使用委托、事件或某种形式的侦听器设计模式,或者...,可以更优雅地做到这一点。

想法?

【问题讨论】:

  • 你可以查看线程

标签: c# oop


【解决方案1】:

处理此问题的最佳方法是将长时间运行的进程置于后台线程上。这可以通过BackgroundWorker 完成,并且是我在 Windows 应用程序中的选择。为什么?因为当通过它报告进度时(例如更改按钮的状态),它会自动处理线程切换到 UI 线程。

这是一个如何工作的例子。假设您有一个 BackgroundWorker 的私有类字段:

private BackgroundWorker _worker = new BackgroundWorker();

在构造函数中我们需要设置一些东西:

_worker.WorkerReportsProgress = true;

_worker.DoWork += DoWork;
_worker.ProgressChanged += ProgressChanged;
_worker.RunWorkerCompleted += RunWorkerCompleted;

好的,现在设置处理程序:

private void DoWork(object sender, DoWorkEventArgs e)
{
    // do the work here
}

private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    // e.UserState is a value that you can pass anything to
    // like a string for a status label

    // e.ProgressPercentage is an integer that you specify letting
    // this event know what step the process is at - this is well
    // used for a progress bar
}

private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // e.Result is a value that you can pass anything to
    // like a reference to an object with the finished product
    // or whatever makes sense in your case
}

最后,要运行后台进程,只需这样做:

_worker.RunWorkerAsync();

并报告进度,在 DoWork 处理程序中,执行以下操作:

// NOTE: make sure to pass AT LEAST a value of 1 for the percentage
// or the event handler will NEVER fire. Further, someValue can be anything
// an instance of an object with data or just a string, or nothing for that
// matter - it's up to you
_worker.ReportProgress(1, someValue);

【讨论】:

    【解决方案2】:

    听起来您的思路是正确的 - 您的后台任务是否被 BackgroundWorker 调用/调用? - 这是保持 GUI 响应并在循环中暂停的方式。在您的后台工作人员中等待 Pause event wait handle(在用户单击暂停按钮之前或如果用户单击暂停按钮,它将永远不会被“设置”)。

    像这样创建事件:

    KeepWorking = new EventWaitHandle(true, EventResetMode.ManualReset);
    

    在工人中这样做:

    while (KeepWorking.WaitOne())
    {
        ...
    }
    

    为您的暂停按钮设置和取消设置事件:

    KeepWorking.Reset(); // To pause it
    KeepWorking.Set(); // To unpause it
    

    【讨论】:

    • 我有一个指向源文件夹的类。该类有一个“开始”方法,该方法调用一个循环,一次获取一个文件。在课堂上,活动只是程序性的。我双击一个文本框以显示文件夹浏览器对话框。然后有一个开始按钮,它实例化完成工作的类,将源文件夹作为构造函数的参数提供给它。我将研究这种后台工作人员的调用方式。但是,在转换为这种方式后,我仍在寻找优雅的信号量方法来响应“暂停”按钮。
    • 我相信EventWaitHandle 是您正在寻找的优雅方式!它的工作原理很像信号量,因为它是一个为线程间等待而设计的可等待对象。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-13
    • 2021-08-11
    • 1970-01-01
    相关资源
    最近更新 更多