C# 如何在WPF关闭事件中使用DerralManager getDeleral()?
Wpf 我试图延迟窗口关闭,直到使用 StephenCleary的异步/等待库 事件处理程序委托和事件参数定义:C# 如何在WPF关闭事件中使用DerralManager getDeleral()?,c#,wpf,events,async-await,C#,Wpf,Events,Async Await,Wpf 我试图延迟窗口关闭,直到使用 StephenCleary的异步/等待库 事件处理程序委托和事件参数定义: public delegate void CancelEventHandlerAsync(object sender, CancelEventArgsAsync e); public class CancelEventArgsAsync : CancelEventArgs { private readonly DeferralManager _deferrals = new
public delegate void CancelEventHandlerAsync(object sender, CancelEventArgsAsync e);
public class CancelEventArgsAsync : CancelEventArgs
{
private readonly DeferralManager _deferrals = new DeferralManager();
public IDisposable GetDeferral()
{
return this._deferrals.GetDeferral();
}
public Task WaitForDefferalsAsync()
{
return this._deferrals.SignalAndWaitAsync();
}
}
然后在NewWindowDialog.xaml的代码隐藏中,我重写了OnClosing事件:
public NewWindowDialog()
{
InitializeComponent();
}
protected override async void OnClosing(System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
base.OnClosing(e);
await LaunchAsync();
}
private async Task LaunchAsync()
{
var vm =(NewProgressNoteViewModel)DataContext;
var cancelEventArgs = new CancelEventArgsAsync();
using (var deferral = cancelEventArgs.GetDeferral())
{
// a very long procedure!
await vm.WritingLayer.CompletionAsync();
}
}
显然,这是失败的,因为e.Cancel=true是在等待之前执行的。那么,在任务完成时(在WPF中),正确使用getDeleral()延迟窗口关闭,我缺少什么呢
短暂性脑缺血发作
编辑:在大家的帮助下,我正在使用这个。然而,有没有人有一个关于窗口关闭延迟模式的好例子
谢谢大家
private bool _handleClose = true;
protected override async void OnClosing(System.ComponentModel.CancelEventArgs e)
{
using (new BusyCursor())
{
if (_handleClose)
{
_handleClose = false;
IsEnabled = false;
e.Cancel = true;
var vm = (NewProgressNoteViewModel)DataContext;
await vm.WritingLayer.SaveAsync();
e.Cancel = false;
base.OnClosing(e);
}
}
}
你不需要延期。只需将
CancelEventArgs.Cancel
属性设置为true
,等待长时间运行的操作,然后关闭。您可以使用标志来避免重复执行同一操作:
private bool _handleClose = true;
protected override async void OnClosing(System.ComponentModel.CancelEventArgs e)
{
if (_handleClose)
{
e.Cancel = true;
await Task.Delay(5000);// a very long procedure!
_handleClose = false;
Close();
}
}
我认为在
窗口中显示模式“请稍候…”消息是一种更为用户友好的方法。关闭任务完成后消失的事件处理程序。这样,在安全关闭应用程序之前,控制流不会离开关闭处理程序
下面是一个完整的WPF示例,说明了如何实现这一点。为简洁起见,将跳过错误处理。这里还有一个类似的问题
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace WpfApp
{
public partial class MainWindow : Window
{
Task _longRunningTask;
private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (_longRunningTask?.IsCompleted != false)
{
return;
}
var canClose = false;
var dialog = new Window
{
Owner = this,
Width = 320,
Height = 200,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Content = new TextBox {
Text = "Please wait... ",
HorizontalContentAlignment = HorizontalAlignment.Center,
VerticalContentAlignment = VerticalAlignment.Center
},
WindowStyle = WindowStyle.None
};
dialog.Closing += (_, args) =>
{
args.Cancel = !canClose;
};
dialog.Loaded += async (_, args) =>
{
await WaitForDefferalsAsync();
canClose = true;
dialog.Close();
};
dialog.ShowDialog();
}
Task WaitForDefferalsAsync()
{
return _longRunningTask;
}
public MainWindow()
{
InitializeComponent();
this.Closing += MainWindow_Closing;
_longRunningTask = Task.Delay(5000);
}
}
}
我也得出了这个结论。但是,如果你知道任何延迟模式的话,我仍然对一些如何使用延迟模式的例子感兴趣。(谷歌在这方面似乎很欠缺)。谢谢。我只想为我补充一下,将Close()改为e.Cancel=false;基数(e);我同意,不过为了简单起见,我用了一个忙碌的人。谢谢。:)@AlanWayne,您可能仍然希望在显示忙碌光标时禁用UI,以防止用户在其挂起时单击:)是。请看我在问题底部确定的代码。很快就很明显你是对的;当关闭按钮被反复按下时,奇怪和不好的事情发生了。谢谢。我认为您不应该在wait
之后调用base.onclose(e)
(以及在此之前设置e.Cancel=false
),因为这样做不符合顺序。太明白我的意思了,看看吧。您在wait
之后的继续操作将在完全不同的堆栈帧和另一个消息循环迭代中调用。@Nosertion没有考虑到这一点……但它似乎工作正常?!(我真的不喜欢用Close()在同一个onclose方法上强制重新进入):)请注意,在当前版本的代码中,当用户单击windows标题中的Close或点击Alt-F4时,仍然无法防止重新进入。设置IsEnabled=false不能阻止这种情况发生。在这种情况下,vm.WritingLayer.SaveAsync()
将被调用两次或两次以上,这可能会给您带来任何副作用,如果有的话:)