等效于异步上下文中WPF DataGrid的DataGridRowEditEndingEventArgs.Cancel

时间:2015-02-15 01:20:17

标签: c# wpf asynchronous datagrid

我有一个 DataGrid ,我在 RowEditEnding 上设置了一个事件处理程序来执行数据更新并使用 DataGridRowEditEndingEventArgs.Cancel 来保持如果更新因任何原因失败,则用户在同一行上。在同步上下文中,这很好。但是,我正在重构async / await模式的数据更新,并希望保留相同的用户交互 - 也就是说,用户无法在一行中保留未保存的更改 - 更改必须成功更新或用户必须明确取消编辑。我还希望尽量减少到数据存储的往返 - 只对 RowEditEnding 或同等事件进行更新。

问题在于使用async / await模式,尝试更新的结果仅在 RowEditEnding 方法返回后确定,因此我无法使用 DataGridRowEditEndingEventArgs.Cancel < / strong>了。我似乎需要确保选中编辑的行并处于编辑模式,但调用 BeginEdit(),即无参数重载不会重新激活编辑模式( RowEditEnding 如果我跳出行,则不会被触发)。

如何强制数据网格回到 RowEditEnding 事件范围之外的编辑状态?

同步方式(工作正常):

public class MyData
{
    // Properties, etc...


    public void Save()
    {
        // Synchronously saves to database, throws exception on error
    }
}


void MyGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
    if (e.EditAction == DataGridEditAction.Commit)
    {
        var item = (MyData)e.Row.Item;
        try
        {
            item.Save();
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);

            e.Cancel = true;
        }
    }
}

async / await方式......根据需要不起作用:

public class MyData
{
    // Properties, etc...


    public Task Save()
    {
        // Asynchronously saves to database, throws exception on error
    }
}


async void MyGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
    if (e.EditAction == DataGridEditAction.Commit)
    {
        var item = (MyData)e.Row.Item;
        try
        {
            await item.Save();
        }
        catch (Exception ex)
        {
            // We get here on an exception thrown from Save
            MessageBox.Show(ex.Message);

            e.Cancel = true; // <== pointless, we're not in the execution scope of the event handler any more

            MyGrid.SelectedItem = item; // We reselect the offending item
            MyGrid.BeginEdit(); // Has no apparent effect
        }
    }
}

1 个答案:

答案 0 :(得分:0)

找到一个解决方法,不确定它是否符合&#34;最佳&#34;做法:

public class MyData
{
    // Properties, etc...


    public Task Save()
    {
        // Asynchronously saves to database, throws exception on error
    }
}


void MyGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
    if (e.EditAction == DataGridEditAction.Commit)
    {
        var item = (MyData)e.Row.Item;
        try
        {
            // Force the awaitable task to complete synchronously
            // Have to use Task.Run to keep the awaited task from deadlocking
            var task = Task.Run(async () => { await item.Save(); });
            task.Wait();
        }
        catch (Exception ex)
        {
            // We get here on an exception thrown from Save
            MessageBox.Show(ex.Message);

            e.Cancel = true; // <== Can do this just as before
        }
    }
}