【问题标题】:Update/populate DataGrid with data asynchronously使用数据异步更新/填充 DataGrid
【发布时间】:2019-01-28 19:34:06
【问题描述】:

我已经检查了一些主题和谷歌,但找不到合适的解决方案。 我想让 WPF 应用程序使用 RestApi 使用 TextBox(项目名称)将项目信息下载到 DataGrid(项目列)。

代码正确且有效,但异步更新 DataGrid 存在问题。

DataTable dt;
public DataTable Dt { get => dt; set { dt = value; dataGridItems.DataContext = Dt.DefaultView; } }

private async void ButtonSearch_Click(object sender, RoutedEventArgs e)
{
    //buttonSearch.IsEnabled = false;
    rest = new RestClass(ClientId, ClientSecret);

    Task T = Task.Run(() => SearchItem(rest, textBoxProductName.Text));

    T.ContinueWith((t) =>
       {
           dataGridItems.DataContext = Dt.DefaultView;
           //buttonSearch.IsEnabled = true;
       }, TaskScheduler.FromCurrentSynchronizationContext());

上面有小改动的代码 (dataGridItems.DataBinding) 在 WinForms 中运行没有任何问题,但我无法让它在 WPF 应用程序中运行。

private void SearchItem(RestClass Rest, string ItemName)
{
    try
    {
        var x = Rest.GetTokenJ().Result;
        ItemsOffersWPF.Rootobject searchResponse = Rest.requestSearchItem(ItemName);
        GetItemsCollection(searchResponse);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    //dataGridItems.DataContext = Dt.DefaultView;
}

我尝试过 Invoke、InvokeAsync,但它使 UI 不负责任,这是我想要避免的。

【问题讨论】:

  • 猜猜,那个 SearchItem() 方法会冻结你的 UI。您所要做的就是在后台任务中调用它。当它准备好时,即在代码中的 ContinueWith 中 - 调用 Dispatcher.Invoke() 并进行您想要做的更改。如果要更新 Control,请确保您获得的 Dispatcher 实例。
  • 另一种猜测:您的ButtonSearch_Click 包含async 关键字,因此您可能在Task.Run(() =>...); 之前缺少await
  • 在 Task.Run 之前尝试等待,但它给出了 UI 正在从另一个线程更新的错误

标签: c# wpf asynchronous async-await wpfdatagrid


【解决方案1】:

你应该使用 await 而不是 T.ContinueWith

    await Task.Run(() => SearchItem(rest, textBoxProductName.Text));
    dataGridItems.DataContext = Dt.DefaultView;

“等待”之后的任何内容都将在任务完成运行后立即执行。

【讨论】:

  • 它给出了关于从其他线程更改 UI 元素的错误,但冻结 await Task.Run(() => dataGridItems.Dispatcher.InvokeAsync(() => { SearchItem(rest, textBoxProductName.Text) ; buttonSearch.IsEnabled = true; }));
  • SearchItem(...) 中或等待之后的任何内容都不允许操作 UiElements 的属性,因为 WPF 不允许从后台线程更改 UiElements 的属性(如果您确实需要,如果不想阻塞 UI)。您必须在此处使用绑定。
  • 他应该关注绑定和 MVVM 但不,您不必使用绑定。将字符串传递到任务中,其余的都作为参数。添加一个包含 rest 和搜索字符串作为属性的类,这样您就拥有一个对象,或者如果您特别想要内联代码,可以捕获它们。您还可以将 searchitem 设为一项任务并从中返回数据表。
  • @Tim Rooney 好的,我明白你的意思。我将 DataTable 绑定到在 SearchItem 内更新的网格。如何正确使用绑定?我尝试 ro 删除所有 UI 更改但仍然错误
【解决方案2】:

好的,谢谢你,我终于找到了解决方案。它并不完美,但效果很好。 问题在于更新 GetItemsCollection 方法中的 DataTable(Dt 属性)并在 await SearchItem 函数中使用 textBoxProductName.Text。

// its useless now
//DataTable Dt { get => dt; set { dt = value; dataGridAllegro.DataContext = Dt.DefaultView; } } 
private async void ButtonSearch_Click(object sender, RoutedEventArgs e)
{
   buttonSearch.IsEnabled = false;
   var productName = textBoxProductName.Text; // get Text value before using Task!
   await Task.Run(() => SearchItem(productName));
   dataGridItems.ItemsSource = dt.DefaultView;
   buttonSearch.IsEnabled = true;
}     

private async void SearchItem(string ProductName)
{
   try
   {
      var x = rest.GetTokenJ().Result;
      ItemsOffersWPF.Rootobject searchResponse = rest.requestSearchItem(ProductName);
      GetItemsCollection(searchResponse); // inside update dt not property DataTable Dt { get => dt; set { dt = value; dataGridAllegro.DataContext = Dt.DefaultView; } }
   // = exception using another thread UI
   }
   catch(Exception ex)
   {
      MessageBox.Show(ex.Message);
   }  
}

【讨论】:

    猜你喜欢
    • 2013-05-01
    • 2018-10-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多