不使用async阻止UI并等待

时间:2017-12-11 09:11:10

标签: c# wpf asynchronous async-await parallel.foreach

我的要求是,需要使用async和await来呈现与数据绑定的所有框架元素。

尝试以下可能性:

  
      
  1. 如果我使用的是asyncmethod().result,它会阻止用户界面和它   将等待很长时间才能完成。

  2.   
  3. 如果我使用await关键字 controlstoconfigure foreach(第二个       一个)将在 parallel.foreach()

  4. 完成之前被击中   

那么请您建议我渲染元素,在完成并行foreach 完成之后调用第2个

代码段:

1)Renderingwidget - 此方法用于获取与数据绑定的集合中的框架元素。

2)FetchData - 此方法用于从服务器获取特定框架元素的数据。

3)GetTablefromserver - 此方法用于根据查询获取数据。

    public async void RenderingWidget()
    {
        ConcurrentDictionary<string, EngineChangedEventArgs> controlsToConfigure = new ConcurrentDictionary<string, EngineChangedEventArgs>();
        foreach (var engines in MainWindow.ViewModel.RelationalDataManagerList.Values)
        {
            Dictionary<string, FrameworkElement> controlcollection = CurrentDashboardReport.WidgetCollection;
            Parallel.ForEach(controlcollection, async item =>
             {
                 try
                 {
                     try
                     {
                         controlsToConfigure.TryAdd(item.Key, await FetchDataInParallel(MainWindow.ViewModel.RelationalDashboardReportList[engines.DataSourceName].Reports, item.Key,));
                     }
                     catch (Exception ex)
                     {
                         ExceptionLog.WriteExceptionLog(ex, null);
                         throw new ParallelException(ex, item.Key);
                     }
                 }
                 catch (ParallelException ex)
                 {
                     exceptions.Enqueue(ex);
                     ExceptionLog.WriteExceptionLog(ex, GeneratedQueryText);
                 }
             });
            if (exceptions.Count > 0)
            {
                foreach (var nonRenderedControls in exceptions)
                {
                    controlsToConfigure.TryAdd(nonRenderedControls.ReportName, await FetchDataInParallel(CurrentDashboardReport.Reports, nonRenderedControls.ReportName));
                }
            }
        }
        foreach (var control in controlsToConfigure)
        {
            (CurrentDashboardReport.WidgetCollection[control.Key] as DashboardDataControl).CurrentDashboardReport.OnActiveColumnsChanged(control.Value);                   
        }
    }

    public async Task<EngineChangedEventArgs> FetchDataInParallel(RelationalReportCollection reports, string myReport)
    {
        var dataTable = await GetTableFromServer(reports.Query);
        eventArgs = new EngineChangedEventArgs
        {
            ItemsSource = dataTable
        };
        return eventArgs;
    }

    public async Task<DataTable> GetTableFromServer(string query)
    {
        var resultTable = new DataTable
        {
            Locale = CultureInfo.InvariantCulture
        };
        SqlConnection sqlConnection = new SqlConnection(connectionString);
        SqlCommand command = new SqlCommand(query, sqlConnection)
        SqlDataReader dataReader = null;
        try
        {
            if (sqlConnection.State != ConnectionState.Open)
            {
                sqlConnection.Open();
            }
            dataReader =await command.ExecuteReaderAsync();
            resultTable.Load(dataReader);
            return resultTable;
        }
        finally
        {
            if (dataReader != null)
            {
                dataReader.Dispose();
            }
            command.Dispose();
            return resultTable;
        }
    }

1 个答案:

答案 0 :(得分:2)

当您在Parallel.ForEach调用期间释放线程时,

asyncawait / async的效果不佳。有关详细信息,请参阅以下问题:Nesting await in Parallel.ForEach

您可以在线程池线程上调用Parallel.ForEach,然后使用Task.WhenAll方法等待所有任务完成之后继续:

public async void RenderingWidget()
{
    ConcurrentDictionary<string, EngineChangedEventArgs> controlsToConfigure = new ConcurrentDictionary<string, EngineChangedEventArgs>();

    List<Task> tasks = new List<Task>();

    foreach (var engines in MainWindow.ViewModel.RelationalDataManagerList.Values)
    {
        Dictionary<string, FrameworkElement> controlcollection = CurrentDashboardReport.WidgetCollection;
        tasks.Add(Task.Run(() =>
        {
            Parallel.ForEach(controlcollection, item =>
            {
                try
                {
                    try
                    {
                        controlsToConfigure.TryAdd(item.Key, FetchDataInParallel(MainWindow.ViewModel.RelationalDashboardReportList[engines.DataSourceName].Reports, item.Key).Result);
                    }
                    catch (Exception ex)
                    {
                        ExceptionLog.WriteExceptionLog(ex, null);
                        throw new ParallelException(ex, item.Key);
                    }
                }
                catch (ParallelException ex)
                {
                    exceptions.Enqueue(ex);
                    ExceptionLog.WriteExceptionLog(ex, GeneratedQueryText);
                }
            });
            if (exceptions.Count > 0)
            {
                foreach (var nonRenderedControls in exceptions)
                {
                    controlsToConfigure.TryAdd(nonRenderedControls.ReportName, FetchDataInParallel(CurrentDashboardReport.Reports, nonRenderedControls.ReportName).Result);
                }
            }
        }));
    }

    await Task.WhenAll(tasks);

    foreach (var control in controlsToConfigure)
    {
        (CurrentDashboardReport.WidgetCollection[control.Key] as DashboardDataControl).CurrentDashboardReport.OnActiveColumnsChanged(control.Value);
    }
}

public async Task<EngineChangedEventArgs> FetchDataInParallel(RelationalReportCollection reports, string myReport)
{
    var dataTable = await GetTableFromServer(reports.Query).ConfigureAwait(false);
    return new EngineChangedEventArgs
    {
        ItemsSource = dataTable
    };
}