You can find some essays from net about this problem. I explain it in my own view and words.
Normally, INotifyPropertyChanged interface is used when you want to update the UI as soon as the underlying data has been changed (in this context, mostly in a programmatic way). You will have your data object inherits from this interface, add an event and a method called PropertyChanged(). In your method, you will call any handler to the event if there is any. You will call your PropertyChanged() method at the end of every property setter attribute accessor or something that changes your data. Say more about it, the UI will subscribe the event when you bind the data to the UI. All simple and is good to use.
INotifyPropertyChanged doesn’t work in aschronized style. That is, if your PropertyChanged() method is called in a thread other than the thread creating the UI, you will get random errors. The ultermate evil is that UI updates should be performed in the same thread as it is created. When your PropertyChanged() method is called in a sub-thread, that sub-thread will call the event of INotifyPropertyChanged interface. As I said, that event will be subscribed by some UI control to update itself. So actually you try to update a UI in a different thread and that gives you the headaches.
A common scenario for this problem is the log system. You have a log system, which provides some kind of UI to show the tasks. When a task starts to execute, you want to update the UI about the change of the task status. When the task is running, you want to update the progress of the task. When the task is done, you want to show the end timestamp of the task. All these jobs involve updating the UI. If you bind the tasks to the UI using databinding, you will tend to use INotifyPropertyChanged to update the UI when the task data is changed. Since all tasks will be run in a BackgroundWorker, it is very likely that the BackgroundWorker will change the data of the tasks. So eventually, you will end up using the BackgroundWorker’s thread to call the PropertyChange() method in your task object, and the event of INotifyPropertyChanged interface as well. This is a common scenario to have the problem happening. It is my own experience by the way.
To fix this problem, you will need to make sure that your PropertyChanged() method uses InvokeRequired() and BeginInvoke() methods to make sure the calling of the event subscribers happens in the same thread as the UI. There are many ways to do this. For example, you can pass the reference of the UI control to your task object so when it is the time, it can check thread and execute the UI update in the correct one. Because most of the time, it is the main thread that owns all UI controls, we can even create a non-visible static singleton control object in a static method which will be sure to get called in the main thread. And everytime we create a new task item, we pass that non-visible control to the task item. As long as all the controls are in the same thread, using which one to call InvokeRequired() and BeginInvoke() doesn’t really matter.
Until next time, happy coding!
Recent Comments