У меня возникла проблема, когда я не могу ждать асинхронной функции внутри события FormClosing, которая будет определять, следует ли продолжать закрывать форму. Я создал простой пример, который предлагает вам сохранить несохраненные изменения, если вы закрываете без сохранения (так же, как с помощью блокнота или слова Microsoft). Проблема, с которой я столкнулся, заключается в том, что когда я жду функции асинхронного сохранения, она продолжает закрывать форму до завершения функции сохранения, затем она возвращается к закрывающей функции, когда она выполняется, и пытается продолжить. Мое единственное решение - отменить закрывающее событие перед вызовом SaveAsync, тогда, если сохранение будет успешным, оно вызовет функцию form.Close(). Я надеюсь, что есть более чистый способ справиться с этой ситуацией.Ожидание Асинхронная функция внутри события FormClosing
Чтобы воспроизвести сценарий, создайте форму с текстовым полем (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.
}
}
}
}
Редактировать 05/23/2013
Ее понятно, что люди спрашивают меня, почему я пытался бы сделать это. Классы данных в наших библиотеках часто имеют функцию Save, Load, New, Delete, которые предназначены для асинхронного запуска. (см. Пример SaveAsync). На самом деле мне неинтересно о , выполняющем функцию асинхронно в событии FormClosing. Но если пользователь хочет сохранить перед закрытием формы, мне нужно, чтобы он подождал, и посмотрим, сохранилось ли спасение или нет. Если сбой не удался, я хочу, чтобы он отменил событие закрытия формы. Я просто ищу самый чистый способ до справиться с этим.
Использование ждать в случае, выстреливает миллисекунды перед тем ваша программа завершается не будет хорошо работать. Тебе придется держать его в живых. –
Я думаю, что тот факт, что вы до сих пор не получили ответа, похоже, указывает на то, что то, что вы сейчас делаете, вероятно, является лучшим методом или, по крайней мере, достаточно хорошим. Это выглядит не очень красиво, но о единственной проблеме, о которой я могу думать, заключается в том, что кто-то может нажать кнопку «Закрыть» и выбрать «сохранить», пока она сохраняет данные изменения; вам нужно будет справиться с этим, и гарантировать, что сохранение только когда-либо называется один раз, когда это происходит. – Servy
Вы можете быть правы, может быть, нет лучшего способа. Что касается того, чтобы пользователь не нажал кнопку сохранения во время сохранения, в моем реальном приложении я занимаюсь этим. Хорошо, что нужно следить, хотя при сохранении формы реагирования. – Hagelt18