在BackgroundWorker中调用ShowDialog
我有一个WinForms应用程序,我的后台工作人员在其中执行同步任务,添加新文件,删除旧文件等。
在我的后台工作者代码中,我想向用户显示一个自定义表单,告诉他将删除什么以及如果他继续将添加什么,使用YES / NO按钮获取他的反馈。
我想知道在后台工作者的doWork方法中做这样的事情是否可行? 如果没有,我该怎么办?
请指教..
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { MyForm f = new MyForm(); f.FilesToAddDelete(..); DialogResult result = f.ShowDialog(); if(No...) return; else //keep working... }
如果您尝试这样做,您将自己看到它将无法工作,因为BackgroundWorker
线程不是STA (它来自托管线程池 )。
问题的实质是你不能从工作线程¹显示用户界面,所以你必须解决它。 您应该将引用传递给应用程序的UI元素(主窗体将是一个不错的选择),然后使用Invoke
将用户交互请求编组到UI线程。 一个准确的例子:
class MainForm { // all other members here public bool AskForConfirmation() { var confirmationForm = new ConfirmationForm(); return confirmationForm.ShowDialog() == DialogResult.Yes; } }
后台工作人员会这样做:
// I assume that mainForm has been passed somehow to BackgroundWorker var result = (bool)mainForm.Invoke(mainForm.AskForConfirmation); if (result) { ... }
¹从技术上讲,您无法从不是STA的线程显示用户界面。 如果您自己创建一个工作线程,您可以选择将其设为STA,但如果它来自线程池则没有这种可能性。
我通常创建一个在UI线程上执行委托的方法:
private void DoOnUIThread(MethodInvoker d) { if (this.InvokeRequired) { this.Invoke(d); } else { d(); } }
有了这个,您可以将代码更改为:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { DialogResult result = DialogResult.No; DoOnUIThread(delegate() { MyForm f = new MyForm(); f.FilesToAddDelete(..); result = f.ShowDialog(); }); if(No...) return; else //keep working... }
IMO回答说你应该启动一个线程来处理这个被误导。 你需要的是将窗口跳回主调度程序线程。
在WPF中
public ShellViewModel( [NotNull] IWindowManager windows, [NotNull] IWindsorContainer container) { if (windows == null) throw new ArgumentNullException("windows"); if (container == null) throw new ArgumentNullException("container"); _windows = windows; _container = container; UIDispatcher = Dispatcher.CurrentDispatcher; // not for WinForms } public Dispatcher UIDispatcher { get; private set; }
然后,当某个事件发生在另一个线程上时(在这种情况下是线程池线程):
public void Consume(ImageFound message) { var model = _container.Resolve(); model.ForImage(message); UIDispatcher.BeginInvoke(new Action(() => _windows.ShowWindow(model))); }
WinForms等价
不要将UIDispatcher设置为任何东西,那么你可以拥有:
public void Consume(ImageFound message) { var model = _container.Resolve(); model.ForImage(message); this.Invoke( () => _windows.ShowWindow(model) ); }
为WPF干掉它:
伙计,这么多代码……
public interface ThreadedViewModel : IConsumer { /// /// Gets the UI-thread dispatcher /// Dispatcher UIDispatcher { get; } } public static class ThreadedViewModelEx { public static void BeginInvoke([NotNull] this ThreadedViewModel viewModel, [NotNull] Action action) { if (viewModel == null) throw new ArgumentNullException("viewModel"); if (action == null) throw new ArgumentNullException("action"); if (viewModel.UIDispatcher.CheckAccess()) action(); else viewModel.UIDispatcher.BeginInvoke(action); } }
并在视图模型中:
public void Consume(ImageFound message) { var model = _container.Resolve(); model.ForImage(message); this.BeginInvoke(() => _windows.ShowWindow(model)); }
希望能帮助到你。
您应该在运行backgroundworker之前调出对话框。 在progresschanged事件中,您可以更新对话框。
上述就是C#学习教程:在BackgroundWorker中调用ShowDialog分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1008012.html