My code is as below
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);
}
}
The step objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null; in get grid data throws exception
The calling thread cannot access this object because a different
thread owns it.
What's wrong here?
This is a common problem with people getting started. Whenever you update your UI elements from a thread other than the main thread, you need to use:
this.Dispatcher.Invoke(() =>
{
...// your code here.
});
You can also use control.Dispatcher.CheckAccess() to check whether the current thread owns the control. If it does own it, your code looks as normal. Otherwise, use above pattern.
To add my 2 cents, the exception can occur even if you call your code through System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke(). The point is that you have to call Invoke() of the Dispatcher of the control that you're trying to access, which in some cases may not be the same as System.Windows.Threading.Dispatcher.CurrentDispatcher. So instead you should use YourControl.Dispatcher.Invoke() to be safe. I was banging my head for a couple of hours before I realized this.
Update
For future readers, it looks like this has changed in the newer versions of .NET (4.0 and above). Now you no longer have to worry about the correct dispatcher when updating UI-backing properties in your VM. WPF engine will marshal cross-thread calls on the correct UI thread. See more details here. Thanks to #aaronburro for the info and link. You may also want to read our conversation below in comments.
Update 2
Since this is a popular post now, I thought I'd share my experience that I had in the following years. The behavior seems to be that any property bindings will update correctly in cross-thread calls (no marshalling required; WPF will handle it for you). OTOH command bindings will need to be delegated to the UI dispatcher. I have tested it with both MVVM Light and the relatively new Community Toolkit and it seems to be the case with both the old Framework and the new .NET 5 and 6. AsyncRelayCommand fails to update the UI when invoked from non-UI thread (This happens when CanExecuteChanged is fired from a worker thread which updates, for example, button's Enabled property). The solution of course is to store UI dispatcher somewhere in the global space in your VM upon startup and then use it when updating the UI.
If you encounter this problem and UI Controls were created on a separate worker thread when working with BitmapSource or ImageSource in WPF, call Freeze() method first before passing the BitmapSource or ImageSource as a parameter to any method. Using Application.Current.Dispatcher.Invoke() does not work in such instances
this happened with me because I tried to access UI component in another thread insted of UI thread
like this
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);
}
to solve this problem, wrap any ui call inside what Candide mentioned above in his answer
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 );
}
You need to do it on the UI thread. Use:
Dispatcher.BeginInvoke(new Action(() => {GetGridData(null, 0)}));
For some reason Candide's answer didn't build. It was helpful, though, as it led me to find this, which worked perfectly:
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
{
//your code here...
}));
This works for me.
new Thread(() =>
{
Thread.CurrentThread.IsBackground = false;
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate {
//Your Code here.
}, null);
}).Start();
As mentioned here, Dispatcher.Invoke could freeze the UI. Should use Dispatcher.BeginInvoke instead.
Here is a handy extension class to simplify the checking and calling dispatcher invocation.
Sample usage: (call from WPF window)
this Dispatcher.InvokeIfRequired(new Action(() =>
{
logTextbox.AppendText(message);
logTextbox.ScrollToEnd();
}));
Extension class:
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();
}
}
}
I also found that System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke() is not always dispatcher of target control, just as dotNet wrote in his answer. I didn't had access to control's own dispatcher, so I used Application.Current.Dispatcher and it solved the problem.
The problem is that you are calling GetGridData from a background thread. This method accesses several WPF controls which are bound to the main thread. Any attempt to access them from a background thread will lead to this error.
In order to get back to the correct thread you should use SynchronizationContext.Current.Post. However in this particular case it seems like the majority of the work you are doing is UI based. Hence you would be creating a background thread just to go immediately back to the UI thread and do some work. You need to refactor your code a bit so that it can do the expensive work on the background thread and then post the new data to the UI thread afterwards
There are definitely different ways to do this depending on your needs.
One way I use a UI-updating thread (that's not the main UI thread) is to have the thread start a loop where the entire logical processing loop is invoked onto the UI thread.
Example:
public SomeFunction()
{
bool working = true;
Thread t = new Thread(() =>
{
// Don't put the working bool in here, otherwise it will
// belong to the new thread and not the main UI thread.
while (working)
{
Application.Current.Dispatcher.Invoke(() =>
{
// Put your entire logic code in here.
// All of this code will process on the main UI thread because
// of the Invoke.
// By doing it this way, you don't have to worry about Invoking individual
// elements as they are needed.
});
}
});
}
With this, code executes entirely on main UI thread. This can be a pro for amateur programmers that have difficulty wrapping their heads around cross-threaded operations. However, it can easily become a con with more complex UIs (especially if performing animations). Really, this is only to fake a system of updating the UI and then returning to handle any events that have fired in lieu of efficient cross-threading operations.
Also, another solution is ensuring your controls are created in UI thread, not by a background worker thread for example.
I kept getting the error when I added cascading comboboxes to my WPF application, and resolved the error by using this API:
using System.Windows.Data;
private readonly object _lock = new object();
private CustomObservableCollection<string> _myUiBoundProperty;
public CustomObservableCollection<string> MyUiBoundProperty
{
get { return _myUiBoundProperty; }
set
{
if (value == _myUiBoundProperty) return;
_myUiBoundProperty = value;
NotifyPropertyChanged(nameof(MyUiBoundProperty));
}
}
public MyViewModelCtor(INavigationService navigationService)
{
// Other code...
BindingOperations.EnableCollectionSynchronization(AvailableDefectSubCategories, _lock );
}
For details, please see https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Windows.Data.BindingOperations.EnableCollectionSynchronization);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.7);k(DevLang-csharp)&rd=true
Sometimes it can be the object you created that throws the exception, not the target where I was obviously looking at.
In my code here:
xaml file:
<Grid Margin="0,0,0,0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<TextBlock x:Name="tbScreenLog" VerticalAlignment="Stretch" Background="Black" FontSize="12" Foreground="#FF919191" HorizontalAlignment="Stretch"/>
</Grid>
xaml.cs file:
System.Windows.Documents.Run rnLine = new System.Windows.Documents.Run(Message.Item2 + "\r\n");
rnLine.Foreground = LineAlternate ? Brushes.Green : Brushes.Orange;
Dispatcher.Invoke(()=> {
tbScreenLog.Inlines.Add(rnLine);
});
LineAlternate = !LineAlternate;
I got the exception about accessing an object from a different thread but I was invoking it on the UI thread??
After a while it daunted on me that it was not about the TextBlock object but about the Run object I created before invoking.
Changing the code to this solved my problem:
Dispatcher.Invoke(()=> {
Run rnLine = new Run(Message.Item2 + "\r\n");
rnLine.Foreground = LineAlternate ? Brushes.Green : Brushes.Orange;
tbScreenLog.Inlines.Add(rnLine);
});
LineAlternate = !LineAlternate;
I encountered this error strangely on the second item selected from a WPF Control.
The reason was that I loaded the data into a RX SourceCache, and the loaded elements had ObservableCollections as Navigation Properties wrapped into a CollectionView. The ObservableCollections are connected to the UIThread and the data was loaded by the WorkerThread. As the CollectionView was only populated on displaying the first element, the issue with the different thread only occured on the second item being selected.
Solution would be to move the sublists to the ViewModel as ReadOnlyObservableCollections and filter the full list of the sub element table by the currently selected main element.
Related
My code is as below
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);
}
}
The step objUDMCountryStandards.Country = txtSearchCountry.Text.Trim() != string.Empty ? txtSearchCountry.Text : null; in get grid data throws exception
The calling thread cannot access this object because a different
thread owns it.
What's wrong here?
This is a common problem with people getting started. Whenever you update your UI elements from a thread other than the main thread, you need to use:
this.Dispatcher.Invoke(() =>
{
...// your code here.
});
You can also use control.Dispatcher.CheckAccess() to check whether the current thread owns the control. If it does own it, your code looks as normal. Otherwise, use above pattern.
To add my 2 cents, the exception can occur even if you call your code through System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke(). The point is that you have to call Invoke() of the Dispatcher of the control that you're trying to access, which in some cases may not be the same as System.Windows.Threading.Dispatcher.CurrentDispatcher. So instead you should use YourControl.Dispatcher.Invoke() to be safe. I was banging my head for a couple of hours before I realized this.
Update
For future readers, it looks like this has changed in the newer versions of .NET (4.0 and above). Now you no longer have to worry about the correct dispatcher when updating UI-backing properties in your VM. WPF engine will marshal cross-thread calls on the correct UI thread. See more details here. Thanks to #aaronburro for the info and link. You may also want to read our conversation below in comments.
Update 2
Since this is a popular post now, I thought I'd share my experience that I had in the following years. The behavior seems to be that any property bindings will update correctly in cross-thread calls (no marshalling required; WPF will handle it for you). OTOH command bindings will need to be delegated to the UI dispatcher. I have tested it with both MVVM Light and the relatively new Community Toolkit and it seems to be the case with both the old Framework and the new .NET 5 and 6. AsyncRelayCommand fails to update the UI when invoked from non-UI thread (This happens when CanExecuteChanged is fired from a worker thread which updates, for example, button's Enabled property). The solution of course is to store UI dispatcher somewhere in the global space in your VM upon startup and then use it when updating the UI.
If you encounter this problem and UI Controls were created on a separate worker thread when working with BitmapSource or ImageSource in WPF, call Freeze() method first before passing the BitmapSource or ImageSource as a parameter to any method. Using Application.Current.Dispatcher.Invoke() does not work in such instances
this happened with me because I tried to access UI component in another thread insted of UI thread
like this
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);
}
to solve this problem, wrap any ui call inside what Candide mentioned above in his answer
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 );
}
You need to do it on the UI thread. Use:
Dispatcher.BeginInvoke(new Action(() => {GetGridData(null, 0)}));
For some reason Candide's answer didn't build. It was helpful, though, as it led me to find this, which worked perfectly:
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
{
//your code here...
}));
This works for me.
new Thread(() =>
{
Thread.CurrentThread.IsBackground = false;
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, (SendOrPostCallback)delegate {
//Your Code here.
}, null);
}).Start();
As mentioned here, Dispatcher.Invoke could freeze the UI. Should use Dispatcher.BeginInvoke instead.
Here is a handy extension class to simplify the checking and calling dispatcher invocation.
Sample usage: (call from WPF window)
this Dispatcher.InvokeIfRequired(new Action(() =>
{
logTextbox.AppendText(message);
logTextbox.ScrollToEnd();
}));
Extension class:
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();
}
}
}
I also found that System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke() is not always dispatcher of target control, just as dotNet wrote in his answer. I didn't had access to control's own dispatcher, so I used Application.Current.Dispatcher and it solved the problem.
The problem is that you are calling GetGridData from a background thread. This method accesses several WPF controls which are bound to the main thread. Any attempt to access them from a background thread will lead to this error.
In order to get back to the correct thread you should use SynchronizationContext.Current.Post. However in this particular case it seems like the majority of the work you are doing is UI based. Hence you would be creating a background thread just to go immediately back to the UI thread and do some work. You need to refactor your code a bit so that it can do the expensive work on the background thread and then post the new data to the UI thread afterwards
There are definitely different ways to do this depending on your needs.
One way I use a UI-updating thread (that's not the main UI thread) is to have the thread start a loop where the entire logical processing loop is invoked onto the UI thread.
Example:
public SomeFunction()
{
bool working = true;
Thread t = new Thread(() =>
{
// Don't put the working bool in here, otherwise it will
// belong to the new thread and not the main UI thread.
while (working)
{
Application.Current.Dispatcher.Invoke(() =>
{
// Put your entire logic code in here.
// All of this code will process on the main UI thread because
// of the Invoke.
// By doing it this way, you don't have to worry about Invoking individual
// elements as they are needed.
});
}
});
}
With this, code executes entirely on main UI thread. This can be a pro for amateur programmers that have difficulty wrapping their heads around cross-threaded operations. However, it can easily become a con with more complex UIs (especially if performing animations). Really, this is only to fake a system of updating the UI and then returning to handle any events that have fired in lieu of efficient cross-threading operations.
Also, another solution is ensuring your controls are created in UI thread, not by a background worker thread for example.
I kept getting the error when I added cascading comboboxes to my WPF application, and resolved the error by using this API:
using System.Windows.Data;
private readonly object _lock = new object();
private CustomObservableCollection<string> _myUiBoundProperty;
public CustomObservableCollection<string> MyUiBoundProperty
{
get { return _myUiBoundProperty; }
set
{
if (value == _myUiBoundProperty) return;
_myUiBoundProperty = value;
NotifyPropertyChanged(nameof(MyUiBoundProperty));
}
}
public MyViewModelCtor(INavigationService navigationService)
{
// Other code...
BindingOperations.EnableCollectionSynchronization(AvailableDefectSubCategories, _lock );
}
For details, please see https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Windows.Data.BindingOperations.EnableCollectionSynchronization);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.7);k(DevLang-csharp)&rd=true
Sometimes it can be the object you created that throws the exception, not the target where I was obviously looking at.
In my code here:
xaml file:
<Grid Margin="0,0,0,0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<TextBlock x:Name="tbScreenLog" VerticalAlignment="Stretch" Background="Black" FontSize="12" Foreground="#FF919191" HorizontalAlignment="Stretch"/>
</Grid>
xaml.cs file:
System.Windows.Documents.Run rnLine = new System.Windows.Documents.Run(Message.Item2 + "\r\n");
rnLine.Foreground = LineAlternate ? Brushes.Green : Brushes.Orange;
Dispatcher.Invoke(()=> {
tbScreenLog.Inlines.Add(rnLine);
});
LineAlternate = !LineAlternate;
I got the exception about accessing an object from a different thread but I was invoking it on the UI thread??
After a while it daunted on me that it was not about the TextBlock object but about the Run object I created before invoking.
Changing the code to this solved my problem:
Dispatcher.Invoke(()=> {
Run rnLine = new Run(Message.Item2 + "\r\n");
rnLine.Foreground = LineAlternate ? Brushes.Green : Brushes.Orange;
tbScreenLog.Inlines.Add(rnLine);
});
LineAlternate = !LineAlternate;
I encountered this error strangely on the second item selected from a WPF Control.
The reason was that I loaded the data into a RX SourceCache, and the loaded elements had ObservableCollections as Navigation Properties wrapped into a CollectionView. The ObservableCollections are connected to the UIThread and the data was loaded by the WorkerThread. As the CollectionView was only populated on displaying the first element, the issue with the different thread only occured on the second item being selected.
Solution would be to move the sublists to the ViewModel as ReadOnlyObservableCollections and filter the full list of the sub element table by the currently selected main element.
My small WPF code is giving me this error
The calling thread cannot access this object because a different thread owns it
I know what exactly it is saying but I am unable to understand how can I fix it. I have tried different things but no luck and I admit that I am not good in Task library.
This is what I am trying to achieve.
Load data when WPF form loads - This is ok
On the form user will press the Refresh button to refresh the data from the database.
here is my code
public partial class DocListView : UserControlListBase
{
private ScecoBillDataScope _scecoBillDataScope;
public EntityCollection<ScecoBillEntity> ScecoBills = new EntityCollection<ScecoBillEntity>();
public DocListView()
{
InitializeComponent();
LoadData();
}
private async void LoadData()
{
await Task.Run(() =>
{
_scecoBillDataScope.FetchData();
});
var collectionView = CollectionViewSource.GetDefaultView(_scecoBillDataScope.ScecoBills);
await Dispatcher.BeginInvoke(new ThreadStart(()=> LayoutRoot.DataContext = collectionView));
}
private void BbiRefresh_ItemClick(object sender, DevExpress.Xpf.Bars.ItemClickEventArgs e)
{
_scecoBillDataScope.Reset();
LoadData();
e.Handled = true;
}}
Actually the error is appearing when I click the Refresh button at this line _scecoBillDataScope.FetchData();
Please advice.
Your problem is this line:
await Dispatcher.BeginInvoke(new ThreadStart(()=> LayoutRoot.DataContext = collectionView));
You're just creating a new thread, you have to actually dispatch on the GUI thread:
Application.Current.Dispatcher.Invoke(() =>
{
LayoutRoot.DataContext = collectionView;
});
Since your collection items are data bound to your view, you have to treat them as part of your UI.
Try loading a new collection from within Task.Run, and then copying them over your existing items while on the UI thread. So, the new collection is built on a thread pool thread (Task.Run), and then the data-bound collection items are modified from the UI thread.
It looks like you want to do something in UI Thread.
As You know You can use Dispatcher class.
But There is another way to ask something to UI Thread.
var uiThread = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
{
// I assumed that It returns boolean value
_scecoBillDataScope.FetchData();
}).ContinueWith(x =>
{
// Here you can put the code to work on the UI thread.
if (x.Result)
{
var collectionView = CollectionViewSource.GetDefaultView(_scecoBillDataScope.ScecoBills);
LayoutRoot.DataContext = collectionView;
}
}, uiThread);
I hope it helps.
thank you.
So I currently have this code below, which has a background worker call showdialog(). However, I thought that the UI cannot be updated on a background thread, so how does the dialog display? Does the dialog actually get opened on the UI thread? what happens?
public partial class ProgressDialog : Window
{
BackgroundWorker _worker;
public BackgroundWorker Worker
{
get { return _worker; }
}
public void RunWorkerThread(object argument, Func<object> workHandler)
{
//store reference to callback handler and launch worker thread
workerCallback = workHandler;
_worker.RunWorkerAsync(argument);
//display modal dialog (blocks caller)
//never returns null, but is a nullable boolean to match the dialogresult property
ShowDialog();
}
I have gotten suggestions that I just run the code and check, but how do i check whether the show dialog window was opened on a new thread or on the background thread itself? Not sure how I would check that.
Anyway this was just a post to try to help my understanding of what is actually happening in my code.
Anyway finally understood more of the comments, so I think I understand everything that is going on. Most of my real problems weren't caused by this dialog anyway, they were caused by updating observable collections from a non-ui thread while controls were bound to them.
Technically you are not changing a property on your Main thread just creating a instance of another object.
But it could help if you elaborate a bit more on your method ShowDialog().
I had also problem with calling ShowDialog() from non-UI thread. And my answer is that it depends on the thread which calls the ShowDialog(). If you set the ApartamentState property for this thread before its start then everything will work as called from the UI thread. I have finally ended up with such a code:
private async void button1_Click(object sender, EventArgs e)
{
var foo = new Foo();
// MessageBox.Show(foo.DirPath) - this works as a charm but
// if, it is called from non UI thread needs special handling as below.
await Task.Run(() => MessageBox.Show(foo.DirPath));
}
public class Foo
{
private string dirPath;
public string DirPath
{
get
{
if (dirPath == null)
{
var t = new Thread(() =>
{
using (var dirDialog = new FolderBrowserDialog())
{
if (dirDialog.ShowDialog() == DialogResult.OK)
dirPath = dirDialog.SelectedPath;
}
}
);
t.IsBackground = true;
t.SetApartmentState(ApartmentState.STA);
t.Start();
t.Join();
}
return dirPath;
}
set
{
dirPath = value;
}
}
}
I dont know for sure but i thought that the showDialog doesnt create the object only showing it. So when u say ShowDialog it only tells to show. So it will run on the UI thread instead of the backgroundworker
(dont know for sure)
I am currently writing my first program on C# and I am extremely new to the language (used to only work with C so far). I have done a lot of research, but all answers were too general and I simply couldn't get it t work.
So here my (very common) problem:
I have a WPF application which takes inputs from a few textboxes filled by the user and then uses that to do a lot of calculations with them. They should take around 2-3 minutes, so I would like to update a progress bar and a textblock telling me what the current status is.
Also I need to store the UI inputs from the user and give them to the thread, so I have a third class, which I use to create an object and would like to pass this object to the background thread.
Obviously I would run the calculations in another thread, so the UI doesn't freeze, but I don't know how to update the UI, since all the calculation methods are part of another class.
After a lot of reasearch I think the best method to go with would be using dispatchers and TPL and not a backgroundworker, but honestly I am not sure how they work and after around 20 hours of trial and error with other answers, I decided to ask a question myself.
Here a very simple structure of my program:
public partial class MainWindow : Window
{
public MainWindow()
{
Initialize Component();
}
private void startCalc(object sender, RoutedEventArgs e)
{
inputValues input = new inputValues();
calcClass calculations = new calcClass();
try
{
input.pota = Convert.ToDouble(aVar.Text);
input.potb = Convert.ToDouble(bVar.Text);
input.potc = Convert.ToDouble(cVar.Text);
input.potd = Convert.ToDouble(dVar.Text);
input.potf = Convert.ToDouble(fVar.Text);
input.potA = Convert.ToDouble(AVar.Text);
input.potB = Convert.ToDouble(BVar.Text);
input.initStart = Convert.ToDouble(initStart.Text);
input.initEnd = Convert.ToDouble(initEnd.Text);
input.inita = Convert.ToDouble(inita.Text);
input.initb = Convert.ToDouble(initb.Text);
input.initc = Convert.ToDouble(initb.Text);
}
catch
{
MessageBox.Show("Some input values are not of the expected Type.", "Wrong Input", MessageBoxButton.OK, MessageBoxImage.Error);
}
Thread calcthread = new Thread(new ParameterizedThreadStart(calculations.testMethod);
calcthread.Start(input);
}
public class inputValues
{
public double pota, potb, potc, potd, potf, potA, potB;
public double initStart, initEnd, inita, initb, initc;
}
public class calcClass
{
public void testmethod(inputValues input)
{
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
int i;
//the input object will be used somehow, but that doesn't matter for my problem
for (i = 0; i < 1000; i++)
{
Thread.Sleep(10);
}
}
}
I would be very grateful if someone had a simple explanation how to update the UI from inside the testmethod. Since I am new to C# and object oriented programming, too complicated answers I will very likely not understand, I'll do my best though.
Also if someone has a better idea in general (maybe using backgroundworker or anything else) I am open to see it.
First you need to use Dispatcher.Invoke to change the UI from another thread and to do that from another class, you can use events.
Then you can register to that event(s) in the main class and Dispatch the changes to the UI and in the calculation class you throw the event when you want to notify the UI:
class MainWindow : Window
{
private void startCalc()
{
//your code
CalcClass calc = new CalcClass();
calc.ProgressUpdate += (s, e) => {
Dispatcher.Invoke((Action)delegate() { /* update UI */ });
};
Thread calcthread = new Thread(new ParameterizedThreadStart(calc.testMethod));
calcthread.Start(input);
}
}
class CalcClass
{
public event EventHandler ProgressUpdate;
public void testMethod(object input)
{
//part 1
if(ProgressUpdate != null)
ProgressUpdate(this, new YourEventArgs(status));
//part 2
}
}
UPDATE:
As it seems this is still an often visited question and answer I want to update this answer with how I would do it now (with .NET 4.5) - this is a little longer as I will show some different possibilities:
class MainWindow : Window
{
Task calcTask = null;
void buttonStartCalc_Clicked(object sender, EventArgs e) { StartCalc(); } // #1
async void buttonDoCalc_Clicked(object sender, EventArgs e) // #2
{
await CalcAsync(); // #2
}
void StartCalc()
{
var calc = PrepareCalc();
calcTask = Task.Run(() => calc.TestMethod(input)); // #3
}
Task CalcAsync()
{
var calc = PrepareCalc();
return Task.Run(() => calc.TestMethod(input)); // #4
}
CalcClass PrepareCalc()
{
//your code
var calc = new CalcClass();
calc.ProgressUpdate += (s, e) => Dispatcher.Invoke((Action)delegate()
{
// update UI
});
return calc;
}
}
class CalcClass
{
public event EventHandler<EventArgs<YourStatus>> ProgressUpdate; // #5
public TestMethod(InputValues input)
{
//part 1
ProgressUpdate.Raise(this, status); // #6 - status is of type YourStatus
// alternative version to the extension for C# 6+:
ProgressUpdate?.Invoke(this, new EventArgs<YourStatus>(status));
//part 2
}
}
static class EventExtensions
{
public static void Raise<T>(this EventHandler<EventArgs<T>> theEvent,
object sender, T args)
{
if (theEvent != null)
theEvent(sender, new EventArgs<T>(args));
}
}
#1) How to start the "synchronous" calculations and run them in the background
#2) How to start it "asynchronous" and "await it": Here the calculation is executed and completed before the method returns, but because of the async/await the UI is not blocked (BTW: such event handlers are the only valid usages of async void as the event handler must return void - use async Task in all other cases)
#3) Instead of a new Thread we now use a Task. To later be able to check its (successfull) completion we save it in the global calcTask member. In the background this also starts a new thread and runs the action there, but it is much easier to handle and has some other benefits.
#4) Here we also start the action, but this time we return the task, so the "async event handler" can "await it". We could also create async Task CalcAsync() and then await Task.Run(() => calc.TestMethod(input)).ConfigureAwait(false); (FYI: the ConfigureAwait(false) is to avoid deadlocks, you should read up on this if you use async/await as it would be to much to explain here) which would result in the same workflow, but as the Task.Run is the only "awaitable operation" and is the last one we can simply return the task and save one context switch, which saves some execution time.
#5) Here I now use a "strongly typed generic event" so we can pass and receive our "status object" easily
#6) Here I use the extension defined below, which (aside from ease of use) solve the possible race condition in the old example. There it could have happened that the event got null after the if-check, but before the call if the event handler was removed in another thread at just that moment. This can't happen here, as the extensions gets a "copy" of the event delegate and in the same situation the handler is still registered inside the Raise method.
I am going to throw you a curve ball here. If I have said it once I have said it a hundred times. Marshaling operations like Invoke or BeginInvoke are not always the best methods for updating the UI with worker thread progress.
In this case it usually works better to have the worker thread publish its progress information to a shared data structure that the UI thread then polls at regular intervals. This has several advantages.
It breaks the tight coupling between the UI and worker thread that Invoke imposes.
The UI thread gets to dictate when the UI controls get updated...the way it should be anyway when you really think about it.
There is no risk of overrunning the UI message queue as would be the case if BeginInvoke were used from the worker thread.
The worker thread does not have to wait for a response from the UI thread as would be the case with Invoke.
You get more throughput on both the UI and worker threads.
Invoke and BeginInvoke are expensive operations.
So in your calcClass create a data structure that will hold the progress information.
public class calcClass
{
private double percentComplete = 0;
public double PercentComplete
{
get
{
// Do a thread-safe read here.
return Interlocked.CompareExchange(ref percentComplete, 0, 0);
}
}
public testMethod(object input)
{
int count = 1000;
for (int i = 0; i < count; i++)
{
Thread.Sleep(10);
double newvalue = ((double)i + 1) / (double)count;
Interlocked.Exchange(ref percentComplete, newvalue);
}
}
}
Then in your MainWindow class use a DispatcherTimer to periodically poll the progress information. Configure the DispatcherTimer to raise the Tick event on whatever interval is most appropriate for your situation.
public partial class MainWindow : Window
{
public void YourDispatcherTimer_Tick(object sender, EventArgs args)
{
YourProgressBar.Value = calculation.PercentComplete;
}
}
You're right that you should use the Dispatcher to update controls on the UI thread, and also right that long-running processes should not run on the UI thread. Even if you run the long-running process asynchronously on the UI thread, it can still cause performance issues.
It should be noted that Dispatcher.CurrentDispatcher will return the dispatcher for the current thread, not necessarily the UI thread. I think you can use Application.Current.Dispatcher to get a reference to the UI thread's dispatcher if that's available to you, but if not you'll have to pass the UI dispatcher in to your background thread.
Typically I use the Task Parallel Library for threading operations instead of a BackgroundWorker. I just find it easier to use.
For example,
Task.Factory.StartNew(() =>
SomeObject.RunLongProcess(someDataObject));
where
void RunLongProcess(SomeViewModel someDataObject)
{
for (int i = 0; i <= 1000; i++)
{
Thread.Sleep(10);
// Update every 10 executions
if (i % 10 == 0)
{
// Send message to UI thread
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
(Action)(() => someDataObject.ProgressValue = (i / 1000)));
}
}
}
Everything that interacts with the UI must be called in the UI thread (unless it is a frozen object). To do that, you can use the dispatcher.
var disp = /* Get the UI dispatcher, each WPF object has a dispatcher which you can query*/
disp.BeginInvoke(DispatcherPriority.Normal,
(Action)(() => /*Do your UI Stuff here*/));
I use BeginInvoke here, usually a backgroundworker doesn't need to wait that the UI updates. If you want to wait, you can use Invoke. But you should be careful not to call BeginInvoke to fast to often, this can get really nasty.
By the way, The BackgroundWorker class helps with this kind of taks. It allows Reporting changes, like a percentage and dispatches this automatically from the Background thread into the ui thread. For the most thread <> update ui tasks the BackgroundWorker is a great tool.
If this is a long calculation then I would go background worker. It has progress support. It also has support for cancel.
http://msdn.microsoft.com/en-us/library/cc221403(v=VS.95).aspx
Here I have a TextBox bound to contents.
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.Write("backgroundWorker_RunWorkerCompleted");
if (e.Cancelled)
{
contents = "Cancelled get contents.";
NotifyPropertyChanged("Contents");
}
else if (e.Error != null)
{
contents = "An Error Occured in get contents";
NotifyPropertyChanged("Contents");
}
else
{
contents = (string)e.Result;
if (contentTabSelectd) NotifyPropertyChanged("Contents");
}
}
You are going to have to come back to your main thread (also called UI thread) in order to update the UI.
Any other thread trying to update your UI will just cause exceptions to be thrown all over the place.
So because you are in WPF, you can use the Dispatcher and more specifically a beginInvoke on this dispatcher. This will allow you to execute what needs done (typically Update the UI) in the UI thread.
You migh also want to "register" the UI in your business, by maintaining a reference to a control/form, so you can use its dispatcher.
Thank God, Microsoft got that figured out in WPF :)
Every Control, like a progress bar, button, form, etc. has a Dispatcher on it. You can give the Dispatcher an Action that needs to be performed, and it will automatically call it on the correct thread (an Action is like a function delegate).
You can find an example here.
Of course, you'll have to have the control accessible from other classes, e.g. by making it public and handing a reference to the Window to your other class, or maybe by passing a reference only to the progress bar.
Felt the need to add this better answer, as nothing except BackgroundWorker seemed to help me, and the answer dealing with that thus far was woefully incomplete. This is how you would update a XAML page called MainWindow that has an Image tag like this:
<Image Name="imgNtwkInd" Source="Images/network_on.jpg" Width="50" />
with a BackgroundWorker process to show if you are connected to the network or not:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
public partial class MainWindow : Window
{
private BackgroundWorker bw = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
// Set up background worker to allow progress reporting and cancellation
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
// This is your main work process that records progress
bw.DoWork += new DoWorkEventHandler(SomeClass.DoWork);
// This will update your page based on that progress
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
// This starts your background worker and "DoWork()"
bw.RunWorkerAsync();
// When this page closes, this will run and cancel your background worker
this.Closing += new CancelEventHandler(Page_Unload);
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
BitmapImage bImg = new BitmapImage();
bool connected = false;
string response = e.ProgressPercentage.ToString(); // will either be 1 or 0 for true/false -- this is the result recorded in DoWork()
if (response == "1")
connected = true;
// Do something with the result we got
if (!connected)
{
bImg.BeginInit();
bImg.UriSource = new Uri("Images/network_off.jpg", UriKind.Relative);
bImg.EndInit();
imgNtwkInd.Source = bImg;
}
else
{
bImg.BeginInit();
bImg.UriSource = new Uri("Images/network_on.jpg", UriKind.Relative);
bImg.EndInit();
imgNtwkInd.Source = bImg;
}
}
private void Page_Unload(object sender, CancelEventArgs e)
{
bw.CancelAsync(); // stops the background worker when unloading the page
}
}
public class SomeClass
{
public static bool connected = false;
public void DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
int i = 0;
do
{
connected = CheckConn(); // do some task and get the result
if (bw.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
Thread.Sleep(1000);
// Record your result here
if (connected)
bw.ReportProgress(1);
else
bw.ReportProgress(0);
}
}
while (i == 0);
}
private static bool CheckConn()
{
bool conn = false;
Ping png = new Ping();
string host = "SomeComputerNameHere";
try
{
PingReply pngReply = png.Send(host);
if (pngReply.Status == IPStatus.Success)
conn = true;
}
catch (PingException ex)
{
// write exception to log
}
return conn;
}
}
For more information: https://msdn.microsoft.com/en-us/library/cc221403(v=VS.95).aspx
Ive got a wpf form, from which i want to display a loading popup as soon as the user makes a choice from the controls, because the loading of the data could take long seeing as the Database is not Local. I got everything working up until where i create the thread for the popup window.
This is where i create my Thread:
public void Start()
{
if (_parent != null)
_parent.IsEnabled = false;
_thread = new Thread(RunThread);
_thread.IsBackground = true;
_thread.SetApartmentState(ApartmentState.STA);
_thread.Start();
_threadStarted = true;
SetProgressMaxValue(10);
Thread th = new Thread(UpdateProgressBar);
th.IsBackground = true;
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
And the thread Method:
private void RunThread()
{
_window = new WindowBusyPopup(IsCancellable);
_window.Closed += new EventHandler(WaitingWindowClosed);
_window.ShowDialog();
}
Now the moment that executes i Get this error :
Cannot use a DependencyObject that belongs to a different thread than its parent Freezable.
Any help would be appreciated :)
Try to use the Dispatcher property of the form.
Dispatcher.BeginInvoke(...)
Or just use the BackgroundWorker class, because it has a method called ReportProgress() to report the progress percentage. This will fire the ProgressChanged event, when you can refresh the value of the progressbar or something...
Cannot use a DependencyObject that belongs to a different thread than its parent Freezable.
This error is observed because your are trying to use a resource(of the type UIElement) which was created in a different thread in your STA thread(which you are using to show the popup window).
In your case it looks like the second thread Thread th = new Thread(UpdateProgressBar); , is trying to manipulate the UI in the WindowBusyPopup. As the popup is owned by a different thread you are getting this exception.
Possible Solution: (as I see you dont show the implementation of the function UpdateProgressBar)
private void UpdateProgressBar()
{
if(_window != null) /* assuming you declared your window in a scope accesible to this function */
_window.Dispatcher.BeginInvoke(new Action( () => {
// write any code to handle children of window here
}));
}