-2

我是 .NET 的新手。我需要使用 C# winforms 中的异步回调机制完成以下分配。

在表单加载时,我需要从数据库中获取数据并填充到 datagridview 中。检索可能需要很长时间,我想同时使用 UI。我还需要一个回调机制来检查是否填充了 datagridview。我必须使用线程和异步回调机制来实现这一点。

    private CustomerEntities cn = null;

    delegate CustomerEntities DataSourceDelegate();
    delegate void loadGridViewDelegate(CustomerEntities dtCustomers);

    DataSourceDelegate delegate_GetCustomers;

    public CustomerEntities DataSource()
    {
        cn = new CustomerEntities();
        return cn;
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        status.Text = "Loading";
        delegate_GetCustomers = new DataSourceDelegate(DataSource);
        delegate_GetCustomers.BeginInvoke(LoadCustomerCallBack, null);
    }

    private void LoadCustomerCallBack(IAsyncResult ar)
    {
        CustomerEntities dtCutomers;
        dtCutomers = delegate_GetCustomers.EndInvoke(ar);
        loadGridView(dtCutomers);
    }

    private void loadGridView(CustomerEntities dtCutomers)
    {
        if (dataGridView.InvokeRequired)
        {
            loadGridViewDelegate del = new loadGridViewDelegate(loadGridView);
            dataGridView.Invoke(del, new CustomerEntities[] { dtCutomers });
        }
        else
        {
            dataGridView.DataSource = dtCutomers.customerDetails;
        }
    }

datagridview 正在正确填充,但是当我在函数检索数据时尝试访问它时 UI 被阻止。

4

2 回答 2

0

您需要在主线程上执行任何修改 WinForm 控件的代码。在回调中使用这种类型的模式:

private void CallbackHandler (object sender, EventArgs e)
 {
     if (InvokeRequired)
     {
         Invoke((MethodInvoker)delegate { CallbackHandler (sender, e); });
         return;
     }

     // If you get here, you are running on the main thread.
 }

编辑:至于实际的异步“获取数据”,您的数据库库很可能有一个接受回调作为其参数之一的函数。这将为您处理其他所有事情。

要手动处理线程,只需创建一个任务:

Task.Factory.StartNew ( () =>
{
    FunctionThatTakesALongTime();
    CallbackHandler();
}
于 2013-08-23T06:01:16.820 回答
0

像这样:

myWindow.BeginInvoke(new My_Main.ProductDelegate(myWindow.PopulateGrid), new object[] { row });

但是,如果您的代码在后台线程上运行,您应该只使用 Invoke / BeginInvoke。

如果您的 UpdateProducts 方法在 UI 线程上运行,则不需要 BeginInvoke;您可以简单地正常调用该方法,如下所示:

myWindow.PopulateGrid(row);

如果确实调用了 BeginInvoke,则需要通过在循环内移动行的声明来在每次迭代中创建一个单独的数组实例。

于 2013-08-23T06:05:36.307 回答