I have looked around at several questions relating dynamic UIs but I still don't understand what I'm missing. In addition, I've followed tutorials on how to use tasks but my understanding is still limited. Here is what I would like to achieve:

My app is doing some work behind the scene but I would like my UI to be responsive. I've tried the following (see code) but the UI doesn't start updating until the dispatcher is invoked. I would like the UI status to be:

  1. Creating... -- as soon as the the CreatePivotTableButton is clicked
  2. Establishing Connection... -- before calling the provider.GetReportData method
  3. Connection Successful or Connection failure depending on the result
  4. Done.

     <!-- language: lang-cs -->
     private void CreatePivotTableButton(object sender, RoutedEventArgs e)
    {
    
        this.StatusToBeDisplayed.Content = "Creating...";
        this.DescriptionLabel.IsEnabled = false;
        this.TextBlockBorder.IsEnabled = true; 
    
        List<CombinedData> items = (List<CombinedData>)CustomerComboBox.ItemsSource;
        List<int> selectedItems = new List<int>();
        foreach (CombinedData item in items)
        {
            if (item.IsSelected)
            {
                selectedItems.Add(item.ReferenceId);
            }
        }
    
        PCTProvider provider = new PCTProvider();
        ExportToExcel export = new ExportToExcel();
    
        ExcelAutomation excelAutomation = new ExcelAutomation();
    
        this.ResultTextBlock.Text = "Establishing Connection";
        DataTable generateReportDataTable = provider.GetReportData(selectedItems);
        Excel.Workbook workbook = export.ExportDataTableToExcel(generateReportDataTable);
        Task updateTask = Task.Factory.StartNew(() =>
        {
            Dispatcher.Invoke(new Action(() => excelAutomation.CreatePivotTable(workbook)));
        }).ContinueWith(result =>
        {
            Dispatcher.Invoke(new Action(() => this.StatusToBeDisplayed.Content = "Done!"));
            Dispatcher.Invoke(new Action(() => OriginalStatus()));
        }, TaskScheduler.FromCurrentSynchronizationContext());
    
    }
    

I highly appreciate your time and help.

有帮助吗?

解决方案

I don't think you need the ContinueWith and/or possibly the TaskScheduler By doing the work in a Task you allow the UI thread to be responsive to the message pump. You might want to move more of the work of your CreatePivotTableButton into the Task.

Try this instead:

private void CreatePivotTableButton(object sender, RoutedEventArgs e)
{

    this.StatusToBeDisplayed.Content = "Creating...";
    this.DescriptionLabel.IsEnabled = false;
    this.TextBlockBorder.IsEnabled = true; 
    // move the rest of the code into your Task to perform the work off the UI thread
    Task updateTask = Task.Factory.StartNew(() =>
    {
        List<CombinedData> items = (List<CombinedData>)CustomerComboBox.ItemsSource;
        List<int> selectedItems = new List<int>();
        foreach (CombinedData item in items)
        {
            if (item.IsSelected)
            {
                selectedItems.Add(item.ReferenceId);
            }
        }

        PCTProvider provider = new PCTProvider();
        ExportToExcel export = new ExportToExcel();

        ExcelAutomation excelAutomation = new ExcelAutomation();

        Dispatcher.Invoke(new Action(() => this.ResultTextBlock.Text = "Establishing Connection"));
        DataTable generateReportDataTable = provider.GetReportData(selectedItems);
        Excel.Workbook workbook = export.ExportDataTableToExcel(generateReportDataTable);

        excelAutomation.CreatePivotTable(workbook);
        Dispatcher.Invoke(new Action(() => this.StatusToBeDisplayed.Content = "Done!"));
        Dispatcher.Invoke(new Action(() => OriginalStatus()));
    });
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top