Kun*_*esh 310 c# wpf multithreading backgroundworker
我的代码如下
public CountryStandards()
{
InitializeComponent();
try
{
FillPageControls();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Country Standards", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// Fills the page controls.
/// </summary>
private void FillPageControls()
{
popUpProgressBar.IsOpen = true;
lblProgress.Content = "Loading. Please wait...";
progress.IsIndeterminate = true;
worker = new BackgroundWorker();
worker.DoWork += new System.ComponentModel.DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(worker_ProgressChanged);
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
GetGridData(null, 0); // filling grid
}
private void worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
{
progress.Value = e.ProgressPercentage;
}
private void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
worker = null;
popUpProgressBar.IsOpen = false;
//filling Region dropdown
Standards.UDMCountryStandards objUDMCountryStandards = new Standards.UDMCountryStandards();
objUDMCountryStandards.Operation = "SELECT_REGION";
DataSet dsRegionStandards = objStandardsBusinessLayer.GetCountryStandards(objUDMCountryStandards);
if (!StandardsDefault.IsNullOrEmptyDataTable(dsRegionStandards, 0))
StandardsDefault.FillComboBox(cmbRegion, dsRegionStandards.Tables[0], "Region", "RegionId");
//filling Currency dropdown
objUDMCountryStandards = new Standards.UDMCountryStandards();
objUDMCountryStandards.Operation = "SELECT_CURRENCY";
DataSet dsCurrencyStandards = objStandardsBusinessLayer.GetCountryStandards(objUDMCountryStandards);
if (!StandardsDefault.IsNullOrEmptyDataTable(dsCurrencyStandards, 0))
StandardsDefault.FillComboBox(cmbCurrency, dsCurrencyStandards.Tables[0], "CurrencyName", "CurrencyId");
if (Users.UserRole != "Admin")
btnSave.IsEnabled = false;
}
/// <summary>
/// Gets the grid data.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="pageIndex">Index of the page.( used in case of paging) </pamam>
private void GetGridData(object sender, int pageIndex)
{
Standards.UDMCountryStandards objUDMCountryStandards = new Standards.UDMCountryStandards();
objUDMCountryStandards.Operation = "SELECT";
objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null;
DataSet dsCountryStandards = objStandardsBusinessLayer.GetCountryStandards(objUDMCountryStandards);
if (!StandardsDefault.IsNullOrEmptyDataTable(dsCountryStandards, 0) && (chkbxMarketsSearch.IsChecked == true || chkbxBudgetsSearch.IsChecked == true || chkbxProgramsSearch.IsChecked == true))
{
DataTable objDataTable = StandardsDefault.FilterDatatableForModules(dsCountryStandards.Tables[0], "Country", chkbxMarketsSearch, chkbxBudgetsSearch, chkbxProgramsSearch);
dgCountryList.ItemsSource = objDataTable.DefaultView;
}
else
{
MessageBox.Show("No Records Found", "Country Standards", MessageBoxButton.OK, MessageBoxImage.Information);
btnClear_Click(null, null);
}
}
Run Code Online (Sandbox Code Playgroud)
objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null;
获取网格数据的步骤会引发异常
调用线程无法访问此对象,因为另一个线程拥有它.
这有什么不对?
Can*_*ide 638
这是人们入门的常见问题.每当您从主线程以外的线程更新UI元素时,您需要使用:
this.Dispatcher.Invoke(() =>
{
...// your code here.
});
Run Code Online (Sandbox Code Playgroud)
您还可以使用control.Dispatcher.CheckAccess()
检查当前线程是否拥有该控件.如果它拥有它,您的代码看起来很正常.否则,请使用上述模式.
小智 48
另一个很好的用途Dispatcher.Invoke
是在执行其他任务的函数中立即更新UI:
// Force WPF to render UI changes immediately with this magic line of code...
Dispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle);
Run Code Online (Sandbox Code Playgroud)
我用它将按钮文本更新为" Processing ... "并在发出WebClient
请求时禁用它.
dot*_*NET 38
要增加2美分,即使您通过代码调用,也会发生异常System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke()
.
问题的关键是,你必须调用Invoke()
的Dispatcher
的的,你要访问的控制,在某些情况下可能不一样System.Windows.Threading.Dispatcher.CurrentDispatcher
.所以相反,你应该使用YourControl.Dispatcher.Invoke()
安全.在我意识到这一点之前,我正在敲打我的头几个小时.
juF*_*uFo 31
如果有人试图BitmapSource
在WPF和线程中使用并且有相同的消息:ImageSource
在传递Freeze()
一个线程参数之前先调用方法.
Bas*_*ANI 24
这发生在我身上,因为我试图access UI
组成another thread insted of UI thread
像这样
private void button_Click(object sender, RoutedEventArgs e)
{
new Thread(SyncProcces).Start();
}
private void SyncProcces()
{
string val1 = null, val2 = null;
//here is the problem
val1 = textBox1.Text;//access UI in another thread
val2 = textBox2.Text;//access UI in another thread
localStore = new LocalStore(val1);
remoteStore = new RemoteStore(val2);
}
Run Code Online (Sandbox Code Playgroud)
要解决这个问题,请将任何ui调用包含在Candide上面提到的答案中
private void SyncProcces()
{
string val1 = null, val2 = null;
this.Dispatcher.Invoke((Action)(() =>
{//this refer to form in WPF application
val1 = textBox.Text;
val2 = textBox_Copy.Text;
}));
localStore = new LocalStore(val1);
remoteStore = new RemoteStore(val2 );
}
Run Code Online (Sandbox Code Playgroud)
Sar*_*rah 14
由于某种原因,Candide的答案没有建立.不过,这很有帮助,因为它让我找到了这个,它完美地工作:
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
{
//your code here...
}));
Run Code Online (Sandbox Code Playgroud)
小智 13
您需要更新到UI,所以使用
Dispatcher.BeginInvoke(new Action(() => {GetGridData(null, 0)}));
Run Code Online (Sandbox Code Playgroud)
这对我有用。
new Thread(() =>
{
Thread.CurrentThread.IsBackground = false;
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate {
//Your Code here.
}, null);
}).Start();
Run Code Online (Sandbox Code Playgroud)
我还发现System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke()
并不总是目标控制的调度程序,正如 dotNet 在他的回答中所写的那样。我无法访问控件自己的调度程序,因此我使用了它Application.Current.Dispatcher
,它解决了问题。
正如这里提到的,Dispatcher.Invoke
可能会冻结 UI。应Dispatcher.BeginInvoke
改为使用。
这是一个方便的扩展类,用于简化检查和调用调度程序调用。
示例用法:(从 WPF 窗口调用)
this Dispatcher.InvokeIfRequired(new Action(() =>
{
logTextbox.AppendText(message);
logTextbox.ScrollToEnd();
}));
Run Code Online (Sandbox Code Playgroud)
扩展类:
using System;
using System.Windows.Threading;
namespace WpfUtility
{
public static class DispatcherExtension
{
public static void InvokeIfRequired(this Dispatcher dispatcher, Action action)
{
if (dispatcher == null)
{
return;
}
if (!dispatcher.CheckAccess())
{
dispatcher.BeginInvoke(action, DispatcherPriority.ContextIdle);
return;
}
action();
}
}
}
Run Code Online (Sandbox Code Playgroud)