WPF实时更新进度条
Updating Progress bar in WPF real time
我设法使用以下代码在 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;
}
}
您使用的是 BackgroundWorker
false。您对 ProgressUpdate 的调用是从后台线程调用的。
您必须订阅 ProgressChanged
-来自 BackgroundWorker
的活动。在这个方法中,你可以在 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");
}
由于您无法在后台线程上访问控件或其他 UI 元素的属性,因此您应该在开始之前检查 IsChecked
属性 是否为 true
后台工作者。
将值存储在传递给 RunWorkerAsync
方法的 bool
变量中:
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();
}
}
我设法使用以下代码在 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;
}
}
您使用的是 BackgroundWorker
false。您对 ProgressUpdate 的调用是从后台线程调用的。
您必须订阅 ProgressChanged
-来自 BackgroundWorker
的活动。在这个方法中,你可以在 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");
}
由于您无法在后台线程上访问控件或其他 UI 元素的属性,因此您应该在开始之前检查 IsChecked
属性 是否为 true
后台工作者。
将值存储在传递给 RunWorkerAsync
方法的 bool
变量中:
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();
}
}