在wpf应用程序中 - 按钮点击后UI被冻结 - 然后如何在大量数据处理时显示忙指示符?
我已尝试过后台工作程序,但它抛出了以下异常。
"调用线程"在消息中不是你的UI线程......
示例代码:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle);
BackgroundWorker worker = sender as BackgroundWorker;
this.busyIndicator.Visibility = Visibility.Visible;
busyIndicator.IsBusy = true;
for (int k = 1; (k <= 10); k++)
{
if ((worker.CancellationPending == true))
{
e.Cancel = true;
break;
}
else
{
int intAutomationID = 0;
int intAutomation_SS_ID = 0;
int intAS_ID = 0;
string strProcedureName = "";
//busyIndicator.Visibility = Visibility.Visible;
try
{
// Insert entry into AUTOMATION_PROCESS table.
intAutomationID = Pkg_TargetsIdentifiers.InsertAutomationProcess(Convert.ToInt32(cmbIdentifier.SelectedValue),
Convert.ToInt32(cmbSourceData.SelectedValue), "InProgress", 0, "Insert");
if (intAutomationID > 0)
{
for (int i = 0; i <= dgvProcessLists.Items.Count - 1; i++)
{
int j = 3;
strProcedureName = "";
strProcedureName = (dgvProcessLists.Items[i] as DataRowView).Row.ItemArray[j].ToString();
if (!string.IsNullOrEmpty(strProcedureName))
{
//AS_ID
// InitializeMouseHandlersForVisual(dgvProcessLists);
intAS_ID = Convert.ToInt32((dgvProcessLists.Items[i] as DataRowView).Row.ItemArray[0].ToString());
intAutomation_SS_ID = Pkg_TargetsIdentifiers.InsertAutomationStepsStatus(intAS_ID, intAutomationID,
"Inprogress", 0, "Insert");
bool boolStatus = Pkg_TargetsIdentifiers.CallActionProcess(strProcedureName, intAutomationID);
if (boolStatus == true)
{
//var selectedRow = DataProcessing.Class1.GetSelectedRow(this.dgvProcessLists);
//var columnCell = DataProcessing.Class1.GetRow(this.dgvProcessLists,0);
intAutomation_SS_ID = Pkg_TargetsIdentifiers.InsertAutomationStepsStatus(intAS_ID, intAutomationID,
"Completed", intAutomation_SS_ID, "Update");
intAS_ID = 0;
strProcedureName = "";
DataRowView row = (dgvProcessLists.Items[i] as DataRowView);
if (row != null)
{
if (row.DataView.Table.Columns.Contains("Status"))
{
Type type = row["Status"].GetType();
string status = row["Status"] == System.DBNull.Value ? null : (string)row["Status"];
if (boolStatus == true)
{
Uri uri = new Uri("pack://application:,,,/Images/green.jpg");
BitmapImage source = new BitmapImage(uri);
}
if (boolStatus == false)
{
Uri uri = new Uri("pack://application:,,,/Images/red.jpg");
BitmapImage source = new BitmapImage(uri);
}
}
}
continue;
}
else
{
break;
}
}
}
intAutomationID = Pkg_TargetsIdentifiers.InsertAutomationProcess(Convert.ToInt32(cmbIdentifier.SelectedValue),
Convert.ToInt32(cmbSourceData.SelectedValue), "Completed", intAutomationID, "Update");
}
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress((k * 10));
}
catch (Exception ex)
{
throw ex;
}
finally
{ }
}
}
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle);
if ((e.Cancelled == true))
{
this.busyIndicator.Visibility = Visibility.Hidden;
busyIndicator.IsBusy = false;
}
else if (!(e.Error == null))
{
this.busyIndicator.Visibility = Visibility.Hidden;
busyIndicator.IsBusy = false;
}
else
{
this.busyIndicator.Visibility = Visibility.Hidden;
busyIndicator.IsBusy = false;
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.busyIndicator.Visibility = Visibility.Visible;
busyIndicator.IsBusy = true;
}
/// <summary>
/// btnStartProcess_Click
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnStartProcess_Click(object sender, RoutedEventArgs e)
{
try
{
if (bw.IsBusy != true)
{
bw.RunWorkerAsync();
}
//worker.RunWorkerAsync();
// //};
// //worker.RunWorkerCompleted += (o, ea) =>
// //{
// // busyIndicator.Visibility = Visibility.Hidden;
// // busyIndicator.IsBusy = false;
// //};
// //worker.RunWorkerAsync();
// //};
// //worker.RunWorkerAsync();
//bw.RunWorkerCompleted += (o, ea) =>
//{
// busyIndicator.IsBusy = false;
// busyIndicator.Visibility = Visibility.Hidden;
//};
//busyIndicator.IsBusy = true;
//busyIndicator.Visibility = Visibility.Visible;
//bw.RunWorkerAsync();
}
catch (Exception ex)
{
throw ex;
}
}
请做必要的..
谢谢和问候, Vijay Babu
答案 0 :(得分:1)
首先,您需要让BackgroundWorker
代码正常运行。为此,我建议您查看我对How to correctly implement a BackgroundWorker with ProgressBar updates?问题的回答,该问题提供了一个清晰,简洁的代码示例。
我现在假设您已正确设置BackgroundWorker
,因此我们可以继续显示忙碌指示符。首先,您需要了解错误的原因:
我们不能从UI线程之外的任何其他线程调用任何UI对象上的任何函数
考虑到这一点,这意味着我们无法从后台线程设置任何忙指标的Visiblity
。因此,最简单的解决方法是在开始Visibility.Visible
之前将其设置为BackgroundWorker
:
busyIndicator.Visibility = Visibility.Visible;
busyIndicator.IsBusy = true;
backgroundWorker.RunWorkerAsync();
我们可以从MSDN上的ooo页面看到:
您必须小心不要操纵
DoWork
事件处理程序中的任何用户界面对象。而是通过ProgressChanged
和RunWorkerCompleted
事件与用户界面进行通信。
这基本上意味着我们可以在UI线程上处理这些事件,因此我们可以从这些事件处理程序访问我们的UI元素。因此,当您的长时间运行过程完成时,将调用RunWorkerCompleted
事件。如果您处理此事件,则可以在相关事件处理程序中隐藏繁忙指示符:
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
busyIndicator.Visibility = Visibility.Hidden;
busyIndicator.IsBusy = false;
}
当它在UI线程上运行时,不需要调用Dispatcher.Invoke
,并且值得注意的是,您对此方法的调用不执行任何操作,因为您没有提供任何委托方法来运行它: / p>
Dispatcher.Invoke(new Action(() => { /*No action*/ }), DispatcherPriority.ContextIdle);
答案 1 :(得分:-1)
试试这个:
Dispatcher.Invoke(() => { busyIndicator.Visibility = Visibility.Visible; });
答案 2 :(得分:-1)
{
System.Threading.ThreadStart start = delegate()
{
CallAutomationProcess();
//done doing work, send result to the UI thread
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
new Action(changest));
};
this.busyIndicator.IsBusy = true;
this.busyIndicator.Visibility = Visibility.Visible;
new System.Threading.Thread(start).Start();