سؤال

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