等待的FormClosing事件里面异步功能 [英] Awaiting Asynchronous function inside FormClosing Event

查看:194
本文介绍了等待的FormClosing事件里面异步功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个问题,我不能等待的FormClosing事件,这将决定形式密切是否应该继续的内部异步函数。我创建了一个简单的例子,提示您,如果您关闭不保存(用记事本或Microsoft Word很像)来保存未保存的更改。我遇到的问题是,当我在等待着异步保存功能,进入关闭表单保存功能完成之前,那么它回来的关闭功能,当它完成,并试图继续。我唯一​​的解决办法是在调用SaveAsync之前取消closing事件,那么如果保存成功,将调用form.Close()函数。我希望有处理这种情况的一个更清洁的方式。

要复制的场景中,创建一个文本框(txtValue),一个复选框(cbFail),和一个按钮(btnSave)的形式。这里是code的形式。

 使用系统;
使用System.Collections.Generic;
使用System.ComponentModel;
使用System.Data这;
使用System.Drawing中;
使用System.Linq的;
使用System.Text;
使用System.Threading.Tasks;
使用System.Windows.Forms的;命名空间TestZ
{
公共部分Form1类:表格
{    字符串cleanValue =;    公共Form1中()
    {
        的InitializeComponent();
    }    公共BOOL HasChanges()
    {
        返回(txtValue.Text = cleanValue!);
    }    公共无效ResetChangeState()
    {
        cleanValue = txtValue.Text;
    }    私人异步无效btnSave_Click(对象发件人,EventArgs的发送)
    {
        //保存没有结果杀到
        等待SaveAsync();
    }    私人异步任务<布尔> SaveAsync()
    {
        this.Cursor = Cursors.WaitCursor;
        btnSave.Enabled = FALSE;
        txtValue.Enabled = FALSE;
        cbFail.Enabled = FALSE;        任务<布尔>工作任务=<布尔> .Factory.StartNew(()=>
        {
            //工作做在后台线程
            System.Threading.Thread.Sleep(3000); // pretend努力。            如果(cbFail.Checked)
            {
                的MessageBox.show(保存失败。);
                返回false;
            }
            其他
            {
                //该值将被保存到数据库中,标记当前的形式状态干净
                MessageBox.Show(保存成功);
                ResetChangeState();
                返回true;
            }
        });        布尔RETVAL =等待工作;        btnSave.Enabled = TRUE;
        txtValue.Enabled = TRUE;
        cbFail.Enabled = TRUE;
        this.Cursor = Cursors.Default;        返回RETVAL;
    }
    私人异步无效Form1_FormClosing(对象发件人,FormClosingEventArgs E)
    {
        如果(HasChanges())
        {
            DialogResult的结果= MessageBox.Show(有未保存的更改您要在关闭之前保存?,未保存的更改,MessageBoxButtons.YesNoCancel,MessageBoxIcon.Question);
            如果(结果== System.Windows.Forms.DialogResult.Yes)
            {
                //这是我要如何处理它 - 但它关闭形式,而应等待保存()来完成。
                //布尔SaveSuccessful =等待保存();
                //如果(!SaveSuccessful)
                // {
                // e.Cancel = TRUE;
                //}                //这是我怎么也得处理:
                e.Cancel =真;
                布尔SaveSuccessful =等待SaveAsync();
                如果(SaveSuccessful)
                {
                    this.Close();
                }
            }
            否则,如果(结果== System.Windows.Forms.DialogResult.Cancel)
            {
                e.Cancel =真;
            }            //如果他们打否,只需关闭形式。
        }
    }}
}


  

修改2013年5月23日


  
  

其可以理解的人会问我,为什么我会努力
  做这个。在我们的库中的数据类往往有保存,
  负载,新建,删除被设计成异步运行的功能
  (见SaveAsync作为例子)。其实我并不很在乎
  在事件的FormClosing异步运行功能专。但是,如果
  用户想要关闭窗体之前保存,我需要等待,
  看是否保存succeds与否。如果保存失败,那么我希望它
  取消形式closing事件。我只是在寻找最干净的方式
  处理这个问题。



解决方案

最好的答案,在我看来,是从关闭取消表格。总是。取消它,但是你想显示你的对话框,一旦用户使用该对话框完成,编程关闭窗体。

下面是我做的:

 异步无效WINDOW_CLOSING(对象发件人,发送CancelEventArgs参数)
{
    变种W =(窗口)发送;
    VAR H =(ObjectViewModelHost)w.Content;
    变种V = h.ViewModel;    如果(V = NULL&放大器;!&安培;
        v.IsDirty)
    {
        args.Cancel =真;
        w.IsEnabled = FALSE;        //调用者的回报和窗口保持打开状态
        等待Task.Yield();        变种C =等待interaction.ConfirmAsync(
            关,
            你必须在这个窗口中未保存的更改。如果退出,他们将被丢弃。
            w)的;
        如果(C)
            w.Close();        如果它关闭//没关系
        w.IsEnabled = TRUE;
    }
}

I'm having a problem where I cannot await an asynchronous function inside of the FormClosing event which will determine whether the form close should continue. I have created a simple example that prompts you to save unsaved changes if you close without saving (much like with notepad or microsoft word). The problem I ran into is that when I await the asynchronous Save function, it proceeds to close the form before the save function has completed, then it comes back to the closing function when it is done and tries to continue. My only solution is to cancel the closing event before calling SaveAsync, then if the save is successful it will call the form.Close() function. I'm hoping there is a cleaner way of handling this situation.

To replicate the scenario, create a form with a text box (txtValue), a checkbox (cbFail), and a button (btnSave). Here is the code for the form.

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.

解决方案

The best answer, in my opinion, is to cancel the Form from closing. Always. Cancel it, display your dialog however you want, and once the user is done with the dialog, programatically close the Form.

Here's what I do:

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;
    }
}

这篇关于等待的FormClosing事件里面异步功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆