Kode saya seperti di bawah ini
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);
}
}
Langkah objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null;
dalam mendapatkan data grid melempar pengecualian
Utas panggilan tidak dapat mengakses objek ini karena utas yang berbeda memilikinya.
Ada apa di sini?
c#
wpf
multithreading
backgroundworker
Kuntady Nithesh
sumber
sumber
Jawaban:
Ini adalah masalah umum dengan orang yang memulai. Setiap kali Anda memperbarui elemen UI Anda dari utas selain utas utama, Anda perlu menggunakan:
Anda juga dapat menggunakan
control.Dispatcher.CheckAccess()
untuk memeriksa apakah utas saat ini memiliki kontrol. Jika memang memilikinya, kode Anda terlihat seperti biasa. Jika tidak, gunakan pola di atas.sumber
Application.Current.Dispatcher.Invoke(MyMethod, DispatcherPriority.ContextIdle);
untuk mendapatkan dispatcher jika tidak pada utas UI sesuai jawaban inithis.Dispatcher.Invoke
.... sebaliknya ...myControl.Dispatcher.Invoke
:) Saya harus mengembalikan objek kembali jadi saya lakukanmyControlDispatcher.Invoke<object>(() => myControl.DataContext)
;Penggunaan lain yang baik
Dispatcher.Invoke
adalah untuk segera memperbarui UI dalam fungsi yang melakukan tugas-tugas lain:Saya menggunakan ini untuk memperbarui teks tombol ke " Memproses ... " dan menonaktifkannya saat membuat
WebClient
permintaan.sumber
Untuk menambahkan 2 sen saya, pengecualian dapat terjadi bahkan jika Anda memanggil kode Anda
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke()
.Intinya adalah bahwa Anda harus menelepon
Invoke()
dariDispatcher
satu kontrol yang Anda coba akses , yang dalam beberapa kasus mungkin tidak samaSystem.Windows.Threading.Dispatcher.CurrentDispatcher
. Jadi, alih-alih, Anda harus menggunakannyaYourControl.Dispatcher.Invoke()
agar aman. Saya membenturkan kepala selama beberapa jam sebelum saya menyadari hal ini.Memperbarui
Untuk pembaca masa depan, sepertinya ini telah berubah di versi .NET (4.0 dan di atas) yang lebih baru. Sekarang Anda tidak perlu lagi khawatir tentang operator yang tepat ketika memperbarui properti dukungan UI di VM Anda. Mesin WPF akan marshal panggilan lintas-thread pada utas UI yang benar. Lihat lebih detail di sini . Terima kasih kepada @aaronburro untuk info dan tautannya. Anda mungkin juga ingin membaca percakapan kami di bawah ini dalam komentar.
sumber
Dispatcher
. Dalam kasus-kasus tersebut (yang memang jarang), meneleponControl.Dispatcher
adalah pendekatan yang aman. Untuk referensi Anda dapat melihat artikel ini serta pos SO ini (terutama jawaban Squidward).Jika Anda mengalami masalah ini dan Kontrol UI dibuat pada utas pekerja terpisah saat bekerja dengan
BitmapSource
atauImageSource
di WPF, panggilFreeze()
metode terlebih dahulu sebelum meneruskanBitmapSource
atauImageSource
sebagai parameter ke metode apa pun. PenggunaanApplication.Current.Dispatcher.Invoke()
tidak berfungsi dalam kasus seperti itusumber
ini terjadi pada saya karena saya mencoba
access UI
komponen dalamanother thread insted of UI thread
seperti ini
untuk mengatasi masalah ini, bungkus semua panggilan ui di dalam apa yang disebutkan Candide di atas dalam jawabannya
sumber
Untuk beberapa alasan jawaban Candide tidak membangun. Namun, itu sangat membantu, karena itu menuntun saya untuk menemukan ini, yang bekerja dengan sempurna:
sumber
System.Windows.Threading.Dispatcher.CurrentDispatcher
adalah dispatcher untuk utas saat ini . Itu berarti jika Anda berada di utas latar, ia tidak akan menjadi pengirim utas UI. Untuk mengakses dispatcher utas UI, gunakanSystem.Windows.Application.Current.Dispatcher
.Anda perlu Perbarui ke UI, Jadi gunakan
sumber
Ini bekerja untuk saya.
sumber
Saya juga menemukan bahwa
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke()
tidak selalu operator target control, seperti yang ditulis dotNet dalam jawabannya. Saya tidak memiliki akses ke operator kontrol sendiri, jadi saya menggunakanApplication.Current.Dispatcher
dan itu memecahkan masalah.sumber
Masalahnya adalah bahwa Anda menelepon
GetGridData
dari utas latar belakang. Metode ini mengakses beberapa kontrol WPF yang terikat pada utas utama. Upaya apa pun untuk mengaksesnya dari utas latar belakang akan menyebabkan kesalahan ini.Untuk kembali ke utas yang benar, Anda harus menggunakan
SynchronizationContext.Current.Post
. Namun dalam kasus khusus ini sepertinya sebagian besar pekerjaan yang Anda lakukan berbasis UI. Oleh karena itu Anda akan membuat utas latar hanya untuk segera kembali ke utas UI dan melakukan beberapa pekerjaan. Anda perlu sedikit memperbaiki kode Anda sehingga dapat melakukan pekerjaan mahal pada utas latar belakang dan kemudian memposting data baru ke utas UI setelahnyasumber
Seperti disebutkan di sini ,
Dispatcher.Invoke
bisa membekukan UI. Harus menggunakanDispatcher.BeginInvoke
saja.Berikut ini adalah kelas ekstensi yang berguna untuk menyederhanakan pemeriksaan dan panggilan permintaan dispatcher.
Contoh penggunaan: (panggilan dari jendela WPF)
Kelas ekstensi:
sumber
Juga, solusi lain adalah memastikan kontrol Anda dibuat di utas UI, bukan oleh utas pekerja latar belakang misalnya.
sumber
Saya terus mendapatkan kesalahan ketika saya menambahkan combobox cascading ke aplikasi WPF saya, dan menyelesaikan kesalahan dengan menggunakan API ini:
Untuk perinciannya, silakan lihat https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Windows.Data.BindingOperations.EnableCollectionSynchronization);k(TargetFrameworkMoniker-.NETFramework, Vers % 3Dv4.7); k (DevLang-csharp) & rd = true
sumber