gpt4 book ai didi

c# - 在 FormClosing 事件中等待异步函数

转载 作者:IT王子 更新时间:2023-10-29 04:13:02 27 4
gpt4 key购买 nike

我遇到了一个问题,我无法等待 FormClosing 事件中的异步函数,该函数将确定表单关闭是否应该继续。我创建了一个简单的示例,如果您关闭而不保存(很像记事本或 Microsoft Word),它会提示您保存未保存的更改。我遇到的问题是,当我等待异步保存函数时,它会在保存函数完成之前继续关闭表单,然后在完成后返回关闭函数并尝试继续。我唯一的解决方案是在调用 SaveAsync 之前取消关闭事件,然后如果保存成功它将调用 form.Close() 函数。我希望有一种更简洁的方法来处理这种情况。

要复制该场景,请创建一个带有文本框 (txtValue)、复选框 (cbFail) 和按钮 (btnSave) 的表单。这是表单的代码。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TestZ
{
public partial class Form1 : Form
{

string cleanValue = "";

public Form1()
{
InitializeComponent();
}

public bool HasChanges()
{
return (txtValue.Text != cleanValue);
}

public void ResetChangeState()
{
cleanValue = txtValue.Text;
}

private async void btnSave_Click(object sender, EventArgs e)
{
//Save without immediate concern of the result
await SaveAsync();
}

private async Task<bool> SaveAsync()
{
this.Cursor = Cursors.WaitCursor;
btnSave.Enabled = false;
txtValue.Enabled = false;
cbFail.Enabled = false;

Task<bool> work = Task<bool>.Factory.StartNew(() =>
{
//Work to do on a background thread
System.Threading.Thread.Sleep(3000); //Pretend to work hard.

if (cbFail.Checked)
{
MessageBox.Show("Save Failed.");
return false;
}
else
{
//The value is saved into the database, mark current form state as "clean"
MessageBox.Show("Save Succeeded.");
ResetChangeState();
return true;
}
});

bool retval = await work;

btnSave.Enabled = true;
txtValue.Enabled = true;
cbFail.Enabled = true;
this.Cursor = Cursors.Default;

return retval;
}


private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (HasChanges())
{
DialogResult result = MessageBox.Show("There are unsaved changes. Do you want to save before closing?", "Unsaved Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
if (result == System.Windows.Forms.DialogResult.Yes)
{
//This is how I want to handle it - But it closes the form while it should be waiting for the Save() to complete.
//bool SaveSuccessful = await Save();
//if (!SaveSuccessful)
//{
// e.Cancel = true;
//}

//This is how I have to handle it:
e.Cancel = true;
bool SaveSuccessful = await SaveAsync();
if (SaveSuccessful)
{
this.Close();
}
}
else if (result == System.Windows.Forms.DialogResult.Cancel)
{
e.Cancel = true;
}

//If they hit "No", just close the form.
}
}

}
}

Edit 05/23/2013

Its understandable that people would ask me why I would be trying to do this. The data classes in our libraries will often have Save, Load, New, Delete functions that are designed to be run asynchronously (See SaveAsync as an example). I do not actually care that much about running the function asynchronously in the FormClosing Event specifically. But if the user wants to save before closing the form, I need it to wait and see if the save succeds or not. If the save fails, then I want it to cancel the form closing event. I'm just looking for the cleanest way to handle this.

最佳答案

在我看来,最好的答案是取消表单的关闭。总是。取消它,随心所欲地显示您的对话框,并在用户完成该对话框后,以编程方式关闭表单。

这是我的做法:

async void Window_Closing(object sender, CancelEventArgs args)
{
var w = (Window)sender;
var h = (ObjectViewModelHost)w.Content;
var v = h.ViewModel;

if (v != null &&
v.IsDirty)
{
args.Cancel = true;
w.IsEnabled = false;

// caller returns and window stays open
await Task.Yield();

var c = await interaction.ConfirmAsync(
"Close",
"You have unsaved changes in this window. If you exit they will be discarded.",
w);
if (c)
w.Close();

// doesn't matter if it's closed
w.IsEnabled = true;
}
}

请务必注意对 await Task.Yield() 的调用。如果被调用的异步方法总是异步执行,则没有必要。但是,如果该方法有任何同步路径(即 null 检查和返回等),Window_Closing 事件将永远不会完成执行并且对 w.Close() 的调用将抛出异常.

关于c# - 在 FormClosing 事件中等待异步函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16656523/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com