在WPF中实时更新进度条

问题描述 投票:0回答:1

我设法在WPF VSTO应用程序中使用下面的代码实时更新进度条,但是,有一个问题,行 object[,] obj = GetOutput(objInput); 抛出一个错误,说它不能访问这个对象,因为它在不同的线程中。当我把这个放在Dispatch.Invoke下,那么我的进度条就不能实时更新。谁能帮帮我?

private BackgroundWorker backgroundWorker1 = new BackgroundWorker();

private object[,] GetOutput(object[,] obj)
{
    object[,] objOutput = null;
    if (rdUpper.IsChecked == true) //--- This UI element is causing the issue
        objOutput = t1.ConvertCase(obj);

    return objOutput;
}

private void btnTest_Click(object sender, RoutedEventArgs e)
{
    t1.OnProgressUpdate += t1_OnProgressUpdate;
    pb.Maximum = 30;
    backgroundWorker1.WorkerReportsProgress = true;
    backgroundWorker1.WorkerSupportsCancellation = true;
    backgroundWorker1.DoWork += backgroundWorker1_DoWork;
    backgroundWorker1.RunWorkerAsync();
}

 private void t1_OnProgressUpdate(int value)
 {
    Dispatcher.Invoke((Action)delegate
    {
       pb.Value = value;
    });
  }

  private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
  {
            try
            {
                Excel.Range SelectedRange = Globals.ThisAddIn.Application.Selection as Excel.Range;

                foreach (Excel.Range rngArea in SelectedRange.Areas)
                {
                    objInput = Common.GetObject(SelectedRange);
                    object[,] obj =  GetOutput(objInput); //-- This throws an error

                  //  rngArea.Value = obj;
                    backgroundWorker1.CancelAsync();
                }

            }
            catch(Exception ex)
            {
                throw;
            }
        }
    }


    class testClass
    {
        public delegate void ProgressUpdate(int value);
        public event ProgressUpdate OnProgressUpdate;
        public object[,] ConvertCase(object[,] objInput)
        {
            object[,] objOutput = (object[,])objInput.Clone();

            for (int row = objInput.GetLowerBound(0); row <= objInput.GetUpperBound(0); row++)
            {
                for (int col = objInput.GetLowerBound(1); col <= objInput.GetUpperBound(1); col++)
                {
                    objOutput[row, col] = objInput[row, col] is null ? null : objInput[row, col].ToString().ToUpper();
                }

                Thread.Sleep(200); // To check and see the real time progress update
                if (OnProgressUpdate != null)
                {        
                    OnProgressUpdate(row);
                }

            }
            return objOutput;
        }
    }
.net wpf vsto
1个回答
0
投票

由于不能在后台线程上访问控件或其他UI元素的属性,所以应该检查是否在 IsChecked 财产是 true 的值,然后再启动后台工作者。

将该值存储在 bool 变量,你传递给 RunWorkerAsync 方法。

private object[,] GetOutput(object[,] obj, bool isChecked)
{
    object[,] objOutput = null;
    if (isChecked)
        objOutput = t1.ConvertCase(obj);

    return objOutput;
}

private void btnTest_Click(object sender, RoutedEventArgs e)
{
    t1.OnProgressUpdate += t1_OnProgressUpdate;
    pb.Maximum = 30;

    bool isChecked = rdUpper.IsChecked == true;

    backgroundWorker1.WorkerReportsProgress = true;
    backgroundWorker1.WorkerSupportsCancellation = true;
    backgroundWorker1.DoWork += backgroundWorker1_DoWork;
    backgroundWorker1.RunWorkerAsync(isChecked);
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    Excel.Range SelectedRange = Globals.ThisAddIn.Application.Selection as Excel.Range;

    foreach (Excel.Range rngArea in SelectedRange.Areas)
    {
        objInput = Common.GetObject(SelectedRange);
        bool isChecked = (bool)e.Argument;
        object[,] obj = GetOutput(objInput, isChecked);

        //  rngArea.Value = obj;
        backgroundWorker1.CancelAsync();
    }
}

1
投票

你使用的是 BackgroundWorker false.您对ProgressUpdate的调用是从后台线程调用的。您对ProgressUpdate的调用是在一个后台线程中调用的。

您必须订阅 ProgressChanged-事件来自 BackgroundWorker. 在这个methode中,你可以在UI-Thread上做一些事情。

请看下面的代码。

private void Button1_Click(object sender, RoutedEventArgs e)
{
    BackgroundWorker backgroundWorker = new BackgroundWorker();
    backgroundWorker.WorkerReportsProgress = true;
    backgroundWorker.WorkerSupportsCancellation = true;
    backgroundWorker.DoWork += BackgroundWorkerOnDoWork;
    backgroundWorker.ProgressChanged += BackgroundWorkerOnProgressChanged;
    backgroundWorker.RunWorkerAsync(t1);
}

private void BackgroundWorkerOnProgressChanged(object sender, ProgressChangedEventArgs e)
{
   // This method will be called if in the DoWork-Method a call to ReportProgress is made. 
   // You can access the provided data with:
   object data = e.UserState;
}

private void BackgroundWorkerOnDoWork(object sender, DoWorkEventArgs e)
{
    testClass t1 = (testClass) e.Argument;

    // Your async-logic here. Everything here will be executed in a Thread
    // If you want to update the UI you have to do the following:
    ((BackgroundWorker)sender).ReportProgress(0, "OBJECT-TO-PASS-TO-THE-UI-THREAD");

}
© www.soinside.com 2019 - 2024. All rights reserved.