Keep UI thread responsive when running long task in windows forms

前端 未结 3 809

I am trying to read a large text file into a TextBox and keep the ui responsive when a file is dragged to the textbox.

Not works as expected, the windows forms is fr

3条回答
  •  执笔经年
    2020-12-07 05:43

    If you need to keep the UI responsive, just give it the time to breath.
    Reading one line of text is so fast that you are (a)waiting almost nothing, while updating the UI takes longer. Inserting even a very little delay lets the UI update.

    Using Async/Await (SynchronizationContext is captured by await)

    public Form1()
    {
       InitializeComponent();
       values.DragDrop += new DragEventHandler(this.OnDrop);
       values.DragEnter += new DragEventHandler(this.OnDragEnter);
    }
    
    public async void OnDrop(object sender, DragEventArgs e)
    {
       string dropped = ((string[])e.Data.GetData(DataFormats.FileDrop))[0];
       if (dropped.Contains(".csv") || dropped.Contains(".txt")) {
          try {
             string line = string.Empty;
             using (var reader = new StreamReader(dropped)) {
                while (reader.Peek() >= 0) {
                   line = await reader.ReadLineAsync();
                   values.AppendText(line.Replace(";", " ") + "\r\n");
                   await Task.Delay(10);
                }
             }
          }
          catch (Exception) {
             //Do something here
          }
       }
    }
    
    private void OnDragEnter(object sender, DragEventArgs e)
    {
       e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop, false) 
                ? DragDropEffects.Copy 
                : DragDropEffects.None;
    }
    

    TPL using Task.Factory
    TPL executes Tasks through a TaskScheduler.
    A TaskScheduler may be used to queue tasks to a SynchronizationContext.

    TaskScheduler _Scheduler = TaskScheduler.FromCurrentSynchronizationContext();
    
    //No async here
    public void OnDrop(object sender, DragEventArgs e)
    {
       string dropped = ((string[])e.Data.GetData(DataFormats.FileDrop))[0];
       if (dropped.Contains(".csv") || dropped.Contains(".txt")) {
          Task.Factory.StartNew(() => {
             string line = string.Empty;
             int x = 0;
             try {
                using (var reader = new StreamReader(dropped)) {
                   while (reader.Peek() >= 0) {
                      line += (reader.ReadLine().Replace(";", " ")) + "\r\n";
                      ++x;
                      //Update the UI after reading 20 lines
                      if (x >= 20) {
                         //Update the UI or report progress 
                         Task UpdateUI = Task.Factory.StartNew(() => {
                            try {
                               values.AppendText(line);
                            }
                            catch (Exception) {
                               //An exception is raised if the form is closed
                            }
                         }, CancellationToken.None, TaskCreationOptions.PreferFairness, _Scheduler);
                         UpdateUI.Wait();
                         x = 0;
                      }
                   }
                }
             }
             catch (Exception) {
                //Do something here
             }
          });
       }
    }
    

提交回复
热议问题