当前位置: 首页 > 编程语言 > C#

WPFModeProgressWindow分享

时间:2023-04-10 17:45:00 C#

WPFModeProgressWindow很抱歉,这个问题已经回答了这么多次,但我似乎找不到适合我的答案。我想创建一个模态窗口,在我的应用程序执行长时间运行的任务时显示各种进度消息。这些任务在单独的线程上运行,我可以在流程的不同阶段更新进度窗口上的文本。跨线程通信一切正常。问题是我不能让窗口只停留在其他应用程序窗口(不是计算机上的每个应用程序)的顶部,阻止与父窗口的交互,并且仍然允许工作继续。到目前为止,这是我尝试过的方法:首先,我的启动窗口是一个自定义类,它扩展了Window类并具有更新消息框的方法。我很早就创建了splash类的一个新实例,并根据需要显示/隐藏它。在最简单的情况下,我实例化窗口并在其上调用.Show()://从我的辅助线程内部this._splash.Dispatcher.Invoke(newAction(()=>this._splash.Show());//Dothings//updatesplashtext//Domorethings//完成后关闭splashthis._splash.Dispatcher.Invoke(newAction(()=>this._splash.Hide());这将是正确的窗口显示并继续运行我的代码来处理初始化任务,但它允许我单击父窗口并将其置于最前面。接下来我尝试禁用主窗口并稍后重新启用它:Application.Current.Dispatcher。Invoke(newAction(()=>this.MainWindow.IsEnabled=false));//显示启动画面、执行操作等Application.Current.Dispatcher.Invoke(newAction(()=>this.MainWindow.IsEnabled=true));这会禁用窗口中的所有元素,但我仍然可以单击主窗口并将其置于启动画面前,这不是我想要的。接下来,我尝试使用启动窗口中最顶层的属性。这使它保持在所有内容的前面,并且随着设置主窗口IsEnabled属性,我可以阻止交互,但这会使启动画面出现在所有内容之上,包括其他应用程序。我也不想要那个。我只希望它成为此应用程序中最顶层的窗口。然后我找到了一篇关于使用.ShowDialog()而不是.Show()的帖子。我试过了,它正确显示了对话框,不允许我单击父窗口,但是调用.ShowDialog()会使程序挂起,等待您关闭对话框,然后它将继续运行代码。这显然不是我想要的。我想我可以在不同的线程上调用ShowDialog(),这样线程会挂起,但执行工作的线程不会……这是推荐的方法吗?我还考虑过完全不使用窗口的可能性,而是在页面上其他内容的前面放置一个全尺寸的窗口元素。这有效,除非我打开了其他窗口并且我希望能够在这些窗口打开时使用启动画面。如果我使用一个窗口元素,我将不得不在每个窗口上重新创建它,并且我将无法在我的自定义启动类中使用我方便的UpdateSplashText方法。所以这让我想到了这个问题。处理这个问题的正确方法是什么?感谢您抽出宝贵的时间,对于这么长的问题深表歉意,但细节很重要:)ShowDialog为您提供了大部分您想要的UI行为,您是正确的。它的问题在于,只要您调用它,它就会阻止执行。您怎么可能在显示表单后运行一些代码,但在显示之前定义它应该是什么?那是你的问题。您可以在splash类中完成所有工作,但由于紧密耦合,这是非常糟糕的做法。您可以做的是利用Window的Loaded事件来定义应该在窗口显示之后运行但在显示之前的位置运行的代码。publicstaticvoidDoWorkWithModal(Action>work){SplashWindowsplash=newSplashWindow();splash.Loaded+=(_,args)=>{BackgroundWorkerworker=newBackgroundWorker();Progressprogress=newProgress(data=>splash.Text=data);工人。DoWork+=(s,workerArgs)=>工作(进度);工人。RunWorkerCompleted+=(s,workerArgs)=>启动。关闭();工人。RunWorkerAsync();};溅。显示对话框();请注意,此方法旨在封装此处的样板代码,以便您可以传入任何接受进度指示器的工作方法,并且它将在后台线程中执行该工作,同时显示用于人工指示进度的通用启动画面。然后可以这样调用:publicvoidFoo(){DoWorkWithModal(progress=>{Thread.Sleep(5000);//真正工作的占位符;progress.Report("FinishedFirstTask");Thread.Sleep(5000);//真正工作的占位符;progress.Report("FinishedSecondTask");Thread.Sleep(5000);//真正工作的占位符;progress.Report("FinishedThirdTask");});您可以使用Window上的Visibility属性在启动画面运行时隐藏整个窗口。XAML代码window.Visibility=System.Windows.Visibility.Hidden;//showsplash//做工作//endsplashwindow.Visibility=System.Windows.Visibility.Visible;您可以让进度窗口的构造函数接受一个任务,然后确保窗口在OnLoaded事件上调用OnLoaded。然后从父窗体使用ShowDialog,这将导致一个进度窗口来启动任务。请注意,您还可以在构造函数中调用task.Start,或者在调用ShowDialog之前在父窗体的任何位置调用。哪个对你最有意义。另一种选择是在主窗口的状态栏中使用进度条并摆脱弹出窗口。如今,此选项似乎变得越来越普遍。@Servy接受的答案对我帮助很大!我想用异步和MVVM方法分享我的版本。它还包括一个小的延迟以避免操作过快的“窗口闪烁”。对话方法:publicstaticasyncvoidShowModal(Func,Task>workAsync,stringtitle=null,TimeSpan?waitTimeDialogShow=null){if(!waitTimeDialogShow.HasValue){waitTimeDialogShow=TimeSpan.FromMilliseconds(300);}varprogressWindow=newProgressWindow();progressWindow.Owner=Application.Current.MainWindow;varviewModel=progressWindow.DataContext作为ProgressWindowViewModel;进度progress=newProgress(text=>viewModel.Text=text);if(!string.IsNullOrEmpty(title)){viewModel.Title=title;}varworkingTask=workAsync(进度);progressWindow.Loaded+=async(s,e)=>{awaitworkingTask;progressWindow.Close();};awaitTask.Delay((int)waitTimeDialogShow.Value.TotalMilliseconds);如果(!workingTask.IsCompleted&&!workingTask.IsFaulted){progressWindow.ShowDialog();}}使用方法:ShowModal(asyncprogress=>{awaitTask.Delay(5000);//Task1progress.Report("Finishedfirsttask");awaitTask.Delay(5000);//Task2progress.Report("完成第二个任务");});再次感谢@Servy,为我节省了很多时间,我找到了一种通过在单独的线程上调用ShowDialog()来执行此操作的方法。我在对话框类中创建了自己的ShowMe()和HideMe()方法来处理工作。我还捕获了Closing事件以防止关闭对话框,以便我可以重用它。这是我的启动画面类的代码:以上是C#学习教程:WPF模式进度窗的全部内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注——publicpartialclassStartupSplash:Window{privateThread_showHideThread;publicStartupSplash(){InitializeComponent();this.Closing+=OnCloseDialog;}publicstringMessage{get{returnthis.lb_progress.Content.ToString();}set{if(Application.Current.Dispatcher.Thread==System.Threading.Thread.CurrentThread)this.lb_progress.Content=value;否则this.lb_progress.Dispatcher.Invoke(newAction(()=>this.lb_progress.Content=value));}}publicvoidShowMe(){_showHideThread=newThread(newParameterizedThreadStart(doShowHideDialog));_showHideThread.Start(true);}publicvoidHideMe(){//_showHideThread.Start(false);this.doShowHideDialog(false);}privatevoiddoShowHideDialog(objectparam){boolshow=(bool)param;如果(显示){如果(Application.Current.Dispatcher.Thread==System.Threading.Thread.CurrentThread)this.ShowDialog();否则申请ion.Current.Dispatcher.Invoke(新动作(()=>this.ShowDialog()));}else{if(Application.Current.Dispatcher.Thread==System.Threading.Thread.CurrentThread)this.Close();否则Application.Current.Dispatcher.Invoke(newAction(()=>this.Close()));}}privatevoidOnCloseDialog(objectsender,CancelEventArgse){e.Cancel=true;这个。隐藏();}}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如有转载请注明出处: