I am experimenting with a simple ViewModel-first based WPF application and some primitive navigation logic. The application consists of two views (screens). One screen contains a button "Go forward" and the other a button "Go backward". By pressing one of the buttons a delegate command is invoked, which in turn causes the shell view-model to switch the active screen. Screen 1 switches to Screen 2, whereas Screen 2 switches to Screen 1.
The problem with this approach is, that it introduces a race condition. When clicking fast enough there is a chance that the corresponding action (go forward/go backward) is executed twice, thus causing the application to fail. The interesting thing about that is that the screen has already been changed, but the UI doesn't reflect the state changes instantaneously. Until now I never had experienced this kind of gap and I made this experiment just to prove, that a single-threaded (dispatched) WPF application is automatically thread-safe.
Does somebody have an explanation for this odd behavior? Is the WPF binding mechanism too slow, so that the button can be pressed a second time, until the UI has updated itself to represent the new screen state?
I have no idea how to fix this according to the recommendations for developing mvvm applications. There is no way to synchronize the code, because there is only one thread. I hope you can help me, because now I feel very unsecure with relying on the WPF data binding and templating system.
Zip archive containing the project files
MainWindow.xaml:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:Screen1}">
<local:View1/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Screen2}">
<local:View2/>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<local:ShellViewModel/>
</Window.DataContext>
<Grid>
<ContentControl Content="{Binding CurrentScreen}"/>
</Grid>
</Window>
The ShellViewModel containing a "go forward" and "go backward" method:
Public Class ShellViewModel
Inherits PropertyChangedBase
Private _currentScreen As Object
Public Property Screens As Stack(Of Object) = New Stack(Of Object)()
Public Sub New()
Me.Screens.Push(New Screen1(Me))
Me.GoForward()
End Sub
Property CurrentScreen As Object
Get
Return _currentScreen
End Get
Set(value)
_currentScreen = value
RaisePropertyChanged()
End Set
End Property
Public Sub GoBack()
Log("Going backward.")
If (Me.Screens.Count > 2) Then
Throw New InvalidOperationException("Race condition detected.")
End If
Log("Switching to Screen 1")
Me.Screens.Pop()
Me.CurrentScreen = Me.Screens.Peek()
End Sub
Public Sub GoForward()
Log("Going forward.")
If (Me.Screens.Count > 1) Then
Throw New InvalidOperationException("Race condition detected.")
End If
Log("Switching to Screen 2.")
Me.Screens.Push(New Screen2(Me))
Me.CurrentScreen = Me.Screens.Peek()
End Sub
End Class
The Screen class containing just a delegate command to start the action:
Public Class Screen1
Inherits PropertyChangedBase
Private _clickCommand As ICommand
Private _shellViewModel As ShellViewModel
Public Sub New(parent As ShellViewModel)
_shellViewModel = parent
End Sub
Public ReadOnly Property ClickCommand As ICommand
Get
If _clickCommand Is Nothing Then
_clickCommand = New RelayCommand(AddressOf ExecuteClick, AddressOf CanExecute)
End If
Return _clickCommand
End Get
End Property
Private Function CanExecute(arg As Object) As Boolean
Return True
End Function
Private Sub ExecuteClick(obj As Object)
Threading.Thread.SpinWait(100000000)
_shellViewModel.GoForward()
End Sub
End Class
There is no weird race condition
I've run your code. There is one thread. The main one.
One thread = no race condition.
Why do you want to prove the following ?
I made this experiment just to prove, that a single-threaded
(dispatched) WPF application is automatically thread-safe.
It's a bullet proof fact. One thread = thread safe (as long as you don't share data process wide, but then it's not thread safety anymore).
Binding and Method no supporting successive calls
In fact, your methods GoBack and GoForward are not supporting successive calls. They should be called one after another.
Thread safety here doesn't imply that your methods cannot be call twice in a row. If there is any task queue in the process, methods can be called twice.
What you may intend to prove is maybe the following:
Clicks are captured and processed in line, without any task queuing between
the click, the property changed event raised, the dispatcher
invocation, the binding / display refresh.
It's clearly Wrong!
When you call Dispatcher.BeginInvoke or Invoke, it's using internally a queue of tasks. And nothing prevent you from queuing twice the same task coming from two similar clicks for example.
To be frank, I was unable to reproduce your bug. I think it's the same thread that captures clicks that dispatch it to your code and then display it on screen. However since task for click events, display refresh are in the same queue, it is theoretically possible to enqueue two clicks before screen change. However :
I cannot click fast enough to beat my cpu.
I don't think the SpinWait are needed.
Something may miss in my configuration.
Why not making your methods supporting successive calls ?
GoBack and GoBackward could check a status and do nothing if the current status is not valid.
You could have used:
1. Two screens both instantiated from the start.
2. A bool to indicate the current state (Forward or Back).
3. An enum to be more clearer in code.
4. A state machine.. no! I'm kidding.
Note: Why using a Stack to push and pop screen(only one by the way) ? and...
in case, you add another thread:
Stack pop / push are not thread safe.
Instead use ConcurrentStack<T>
Simulation
Even when the UI thread is frozen or doing something, another inputs are being collected. Try this out (Sorry for C# but you get the point):
private void ButtonClick(object sender, EventArgs args)
{
Debug.WriteLine("start");
Thread.Sleep(6000);
Debug.WriteLine("End");
}
Click the button, then place a breakpoint on the Start line, click the button again before the UI thread unfreezes. and you will see that exactly 6 seconds after your first click the breakpoint gets hit.
Explanation
The UI thread can obviously only perform 1 action at a time, but it has to be optimized for multithreading - meaning it queues it's actions. Therefore any PropertyChanged (or any handler at all including the OnClick) is only queueing the action for the UI thread. It doesn't jump out of your code to update the UI elements in the middle of your setter. If you call Thread.Sleep after the setter you will see that you don't see any change - because the UI thread didn't get to invoke the update yet.
Why is this important
In your code you first Push a screen and then set is as current, calling propertyChanged. That does not change the screens immediately, it just queues it for the update. There is no guarantee that another click doesn't get scheduled before that.
You could also achieve freezing your UI thread by calling PropertyChanged a million times causing it to freeze during the update itself. Yet the clicks in the meantime would be collected.
So your "safepoint" - the place where it is safe that no other click can be scheduled now - is not after the Setter is finished, but after the Loaded Event is called on the new window.
How to fix
Read
Fab
's answer :)
Dont think that just because the UI thread is blocked at the moment nothing gets in. If you want to disable inputs while something is being calculated you do need to disable the inputs manually.
Possible solutions
Set IsEnabled, Visibility, IsHitTestVisible
Some Overlay or whatever
Boolean parameter, that could globally allow or disallow all methods coming (basically a lock)
I cannot reproduce the described behavior - double clicking causes the app to first "go backward", and then "go forward" at my side. Nevertheless, I think that expecting the button to disappear before the user can click it for the second time is not a good design (especially in case of devices that for instance have a separate "double-click" button), and I would personally never rely on that.
What I think is the best way to proceed in this situation is to properly implement the CanExecute method, so that it not only returns true (which by the way is most likely redundant), but rather queries the _shellViewModel whether it's in a state allowing to invoke the method called by ExecuteClick (in case of GoForward it should return true if there is only one element on the stack). I cannot test that (because I cannot reproduce the behavior in question), but I'm pretty sure that even if the user clicks the same button twice, the second call to CanExecute will occur after the first call to ExecuteClick, thus the model will be guaranteed to be "up-to-date" (the result will be false and GoForward will not be called again).
#Pavel Kalandra:
While it is possible for a simple click event-handler to be queued multiple times, even if the UI thread is blocked, I can't reproduce this behavior with a delegate command. Hence I assume that the WPF framework does handle the invocation of an command a little bit differently compared to a simple click event-handler. Moreover, in your example the click event is already queued before the execution of the event-handler has finished. In my situation this is not the case.
To prove this assumption I made a further experiment: By using a command that blocks the UI thread for a few seconds and then shows a message, you can see that it is not possible to invoke it multiple times during its invocation. I believe that the WPF framework is somehow preventing this from happening. Therefore both scenarios aren't comparable to one.
But I think that your explanation is still correct. Pushing the screen causes the PropertyChanged-event to be fired, but the screen is not updated immediately. Indeed the associated job is pushed onto the dispatcher queue and is scheduled. As a consequence there is a short time span during which it is possible to invoke the command a second time.
#Fab:
When you strongly rely on the accepted definition of a race condition, then there shouldn't be one in my sample application. But for simplicity purposes I would like to call it still a race condition because the scheduling of jobs makes the execution nondeterministic.
Nevertheless, the assumption I was intended to prove, is wrong. I wanted to prove it because of threading problems we are currently faced with. Our application simulates multiple modal methods at the same time, therefore it relies on multiple threads. Because the interactions, a user is allowed to, aren't properly synchronized there is a high chance for race conditions to happen (synchronizing them is not an option because of other reasons).
At the moment I am working on a prototype which doesn't use threads so heavily. My hope was, that by executing everything on the dispatcher thread race conditions (or similar problems) shouldn't be possible. At least for a ViewModel-first approach this seems to be wrong because of the way the WPF is scheduling binding updates.
I have used a simple scenario where it is easy to provide a fix to the potential "race condition". But in general it won't be easy to write a Bulletproof WPF application. A flag to indicate the direction (forward/backward) won't be enough when dealing with multiple screens. But the command delegate could check if it is invoked from the active screen.
PS: As long as I rely exclusively on the dispatcher thread to execute actions, I see no need for using a ConcurrentStack ;-)
I have come across another similar issue, that proves that UI scheduling can in fact introduce race conditions even if the application is single-threaded.
In the example a piece of code is called, that is supposed to be atomic. Because scheduling is used using different priorities, the code may be interrupted in the middle of execution.
This is an example that I found in a similar form in our production code. Users have mentioned an issue that is spontaneously occuring. I have found out then that a SelectionChanged-event was interrupting a piece of code that was supposed to be executed as a block.
public partial class MainWindow : Window
{
private bool inBetweenMethod;
public MainWindow()
{
InitializeComponent();
this.timer = new DispatcherTimer(DispatcherPriority.Loaded);
this.timer.Interval = TimeSpan.FromMilliseconds(10);
this.timer.Tick += Timer_Tick;
this.timer.Start();
this.MethodThatIsSupposedToBeAtomic();
}
private void Timer_Tick(object sender, EventArgs e)
{
if (inBetweenMethod)
{
throw new Exception("Method was interrupted in the middle of execution".);
}
}
private void MethodThatIsSupposedToBeAtomic()
{
inBetweenMethod = true;
Dispatcher.Invoke(new Action(() =>
{
for (int i = 0; i < 100; i++)
{
Console.WriteLine("iterating");
}
}), DispatcherPriority.ContextIdle);
inBetweenMethod = false;
}
}
Related
I am reading a large Txt document into a WPF app for some serious swap/replacemnt operations. The files are actually 3D STP models so they are fairly large, but im working with them as raw text for this project. The files are read into List to avoid having to open them multiple times, and to make comparisons easier.
Anyway, I'm trying to get the listbox to scroll dynamically as lines are added to it, ala a console window so the user can see that something is happening since calculations can take a bit of time depending on filesize. I also added a progress bar to count away as the total line number is read through.
Neither my progress bar, nor ListBox seem to update as work progresses though. The final output simply lands in the listbox completed, and the progress bar goes from 0-max at the same time.
This is the gist of what I am doing, which is fairly simple:
foreach (string Line in OriginalSTPFile.Lines)
{
string NewLine = EvaluateString(Line); //string the modified to whatever here
pBar.Value++; //increment progressbar
OutputWindow.Items.Add(NewLine); //add line to the ListBox
}
I just want the listbox an progress bar to update in realtime as progress changes. I tried using:
Dispatcher.BeginInvoke(new Action(() => OutputWindow.Items.Add(NewLine));
But got the same results. Do I need a more elaborate method of multithreading here? I assumed the first method would've worked since I wasn't generating any cross-thread exceptions either.
This article will give you all the code that you need.
Backgroundworker with Progressbar
It describes very well what to do and which elements to use.
Dispatcher.BeginInvoke signals to invoke a method on the Dispatcher's thread. However, that's essentially like a post message, as it won't occur while the main thread is locked up doing work. And until the main thread is available again, it won't update the UI visually, even if you change values.
You'll need to perform the work in a background thread.
But to update the UI, you'll have to do so on the UI's main thread. This is a limitation of WPF. This is why you were directed to Dispatcher. I'm guessing someone assumed your work was already on a background thread.
To create a thread, you use Thread.Start passing it a delegate to perform. If you use a anonymous delegate or a lambda, you can refer to variables on the stack, but be aware that they will persist until the delegate quits. This is why you cannot use reference variables in a anonymous delegate.
Backgroundworker is a special type of background thread. It automates some of the expectations of a worker thread (notifying of completion, and updating on progress), but you can achieve the same results without it.
To update the UI during the thread's process, you'll need for that thread to be able to access the main UI thread. You can do that by passing it a dispatcher, referring to a dispatcher from outside the anonymous delegate, or by an object that contains a dispatcher. You can always read values from any object on any thread, so accessing the dispatcher by UIElement on another thread is fine.
To update the UI, you'll call Dispatcher.BeginInvoke with a delegate that entails the work to perform.
Here's psuedo-code of the overall scheme
class TestProgress
{
ProgressBar _ProgressBar;
void DoWork()
{
var worker = (Action)(() =>
{
int progress = 0;
// do stuff, delta is change in progress
progress += delta;
_ProgressBar.Dispatcher.BeginInvoke((Action)(() =>
{
_ProgressBar.Value = progress;
}));
});
Thread.Start(worker);
}
}
I have this:
Shows a waiting animation to 'block' the UI while performs a loading operation in the background.
At the end of the loading I call a method that instances a User Control and displays some data by using Bindings (and ObservableCollection among others)
This User Control gets displayed and user can interact with it, however the ObservableCollection seems to be stuck in another thread as it doesn't allow to add new items to it.
I've tried to update the UI at the Completed event of a BackgroundWorker, using Dispatcher, using DispatchTimer... all of this displays the User Control, but the ObservableCollection stays of out reach for adding.
The code that tries to add items to the collection is inside the UserControl.
The exact error is: "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread"
This does not happen if I don't do the loading in the background.
Thank you for any workaround for this.
By the way, trying to add the items using Dispatcher doesn't work either.
In other words, what I would like to do is to create an object in the UI Thread while being in the background... I know this may sounds silly.
You may have to check which Dispatcher you are using? In your case you could be referring to two different dispatchers.
Also why not use thread safe observable collection?
Usually I will create the objects on my UI thread, then populate them with data obtained from a background thread.
For example,
void async LoadButton_Clicked(object sender, EventArgs e)
{
MyCollection = new ObservableCollection<SomeItem>();
// Can also use a BackgroundWorker
var collectionData = await GetCollectionData();
foreach(var item in collectionData)
{
MyCollection.Add(item);
}
}
I'm using C# 5.0 async and await keywords for asynchronous operations, but you can also use a BackgroundWorker that does your background work.
You can also use Dispatcher.BeginInvoke() for some lighter background work (such as copying data into MyCollection), although for heavy work I find it still locks up the UI so I prefer to use background threads.
It is not possible to modify the contents of an ObservableCollection on a separate thread if a view is bound to this collection, instead you can override ObservableCollection and provide support for it and use it across your application.
This sample contains exactly what you want - http://tomlev2.wordpress.com/2009/04/17/wpf-binding-to-an-asynchronous-collection/
When it comes to threads and ui-elements one of the most important rules to follow which may safe you a lot of trouble in the long run is to keep ui-element instantiation on the ui-thread. Surely you can manage that. And if you need to change those objects from another thread you can use the Dispatcher.
(The threading model reference may also be of interest)
Thank you everyone for your help... a guy from MS visited the company (sorry for the commercial annotation) to do other things, I stoled him and show this behavior. In a matter of 2 minutes founds the source of the problem... which I'm not sure to really understand.
It happens that I'm using an ICollectionView to display a sorted/filtered version of my problematic ObservableCollection. I was creating this ICollectionView in the constructor of my class, so at the moment of deserialization it was created in another thread. He suggested to move this creation to a further time in code (when the related property gets read). This solved the problem.
However the ObservableCollection, created in that other thread, now lets me add new item. Not sure why, but now it works.
Sorry for being this late and thank you again.
We've got a Model-View-Presenter setup with our .NET Compact Framework app. A standard CF Form is implementing the view interface, and passed into the constructor of the presenter. the presenter tells the form to show itself by calling view.Run(); the view then does a Show() on itself, and the presenter takes over again, loading up data and populating it into the view.
Problem is that the view does not finishing showing itself before control is returned to the presenter. since the presenter code blocks for a few seconds while loading data, the effect is that the form is not visible for a few seconds. it's not until after the presenter finishes it's data load that the form becomes visible, even though the form called Show() on itself before the presenter started its data loading.
In a standard windows environment, i could use the .Shown event on the form... but compact framework doesn't have this, and I can't find an equivalent.
Does anyone know of an even, a pinvoke, or some other way to get my form to be fully visible before kicking off some code on the presenter? at this point, i'd be ok with the form calling to the presenter and telling the presenter to start it's data load.
FYI - we're trying to avoid multi-threading, to cut down on complexity and resource usage.
The general rule is: never do anything blocking on the UI thread
The UI in Windows (and in Windows CE as well) has an asynchronous nature. Which means that most API calls do not necessarily do whatever they're supposed to do immediately. Instead, they generate a series of events, which are put into the event queue and later retrieved by the event pump, which is, essentially, an infinite loop running on the UI thread, picking events from the queue one by one, and handling them.
From the above, a conclusion can be drawn that if you continue to do something lengthy on the UI thread after requesting a certain action (i.e. showing the window in your case), the event pump cannot proceed with picking events (because you haven't returned control to it), and therefore, your requested action cannot complete.
The general approach is as follows: if you must do complex data transformation/loading/preparing/whatever, do it on a separate thread, and then use Control.BeginInvoke to inject a delegate into the UI thread, and touch the actual UI controls from inside that delegate.
Despite your irrational fear of "complexity" that multithreading brings with it, there is very little to be afraid of. Here's a little example to illustrate the point:
public void ShowUI()
{
theForm = new MyForm();
theForm.Show();
// BeginInvoke() will take a new thread from the thread pool
// and invoke our delegate on that thread
new Action( PrepareData ).BeginInvoke(null,null);
}
public void PrepareData()
{
// Prepare your data, do complex computation, etc.
// Control.BeginInvoke will put our delegate on the UI event queue
// to be retrieved and executed on the UI thread
theForm.BeginInvoke( new Action( PutDataInTheForm ) );
}
public void PutDataInTheForm()
{
theForm.textBox1.Text = "data is ready!";
}
While you may play with alternative solutions, the general idea always remains the same: if you do anything lengthy on the UI thread, your UI will "freeze". It will not even redraw itself as you add new UI elements on the screen, because redrawing is also an asynchronous process.
Therefore, you must do all the complex and long stuff on a separate thread, and only do simple, small, guaranteed to run fast things on the UI thread. There is no other alternative, really.
Hope this helps.
If your key problem is that the form won't paint before your presenter data loading methods are completed, and you have a call to this.Show() in your Form_Load, try putting Application.DoEvents() directly after this.Show() to force/allow the form to paint.
protected void Form_Load(blah blah blah)
{
this.Show();
Application.DoEvents();
... data loading methods ...
}
No need to create another thread if you don't want to (although a couple of seconds have to be dealt with somehow).
You can use the activated event. Because it will fire when the form is activated, you need a boolean local to the form to check wether or not the form has been created for the first time.
Another option for you is to disconnect the event handler right after you finish presenting the form.
In my WinForms application, I need to pop up a little custom dialog that stays on the screen for X amount of seconds and then disappears. So I use a System.Threading.Timer to invoke the _dialog.Close() method once the appropriate amount of time has elapsed. This of course means that I have to do the whole "if InvokeRequired BeginInvoke" dance which isn't really a problem.
What is a problem however is that my main thread might be off doing god knows what by the time the BeginInvoke is called. It might not get around to closing the window for quite a while. I don't need the window to close at a millisecond's notice, but within a second or so is really necessary.
So my question is how does BeginInvoke actually work itself into the main thread and how can I get around this odd limitation?
If your UI thread is busy for many seconds at a time, then:
You won't be able to close a window associated with that UI thread, without peppering your code with Application.DoEvents calls (a bad idea)
Your whole UI will be unresponsive during this time. The user won't be able to move any of the application's windows, and if the user drags other windows over the top of it and off again, you'll end up with an ugly mess while the UI waits to repaint itself.
Certainly use a System.Windows.Forms.Timer instead of a System.Threading.Timer for simplicity, but more urgently, look at fixing your code to avoid having such a busy UI thread.
UPDATE: The conclusion would seem to be that utilising ['BackgroundWorker](http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx) along with a System.Windows.Forms.Timer would be the best approach.
Best to use System.Windows.Forms.Timer for this purpose - this is precisely the sort of application it was designed for. Add one to the pop up form and start it as soon as the form is shown, then hide the form on the Tick event. This solution won't give you any threading issues because the timer runs purely on the UI thread.
Edit: If you want to move the logic outside of your popup form, then I recommend you just create an overload for the Show method within the form code that takes a timespan for its parameter and does the job of setting the Timers's interval and starting it.
Edit 2: If you're main (UI) thread is doing too much work and therefore blocking the message pump and not allowing the timer to fire, then it's the design that's the issue I'm afraid. Your UI thread should never be blocking for more than a fraction of a second. If you need to do serious work, do it in the background using a worker thread. In this case, because you are using WinForms, BackgroundWorker is probably the best option.
Create a dedicated thread and use Application.Run to create and show your form. This will start up a message pump on the second thread which is independent of the main thread. This can then close exactly when you want it, even if the main thread is blocked for any reason.
Invoke and BeginInvoke do get into the main thread by using a window message posted into that thread, waiting for it to be processed. Therefore, if the message pump of the main thread is not processing messages (e.g. busy), it will have to wait. You can mitigate this factor by calling Application.DoEvents() when doing time-consuming operations in the main thread, but that's not really a solution to the problem.
Edit: Sample from some splash screen code (the form requires no special code or logic):
private void ShowSplashInSeparateMessageQueue() {
Thread splash = new Thread(ShowSplashForm);
splash.IsBackground = true;
splash.Start();
}
private void ShowSplashForm() { // runs in a separate thread and message queue
using (SplashForm splashForm = new SplashForm()) {
splashForm.Load += AddDestroyTimer;
Application.Run(splashForm);
}
}
private void AddDestroyTimer(object sender, EventArgs e) {
Form form = (Form)sender;
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(form.Container);
timer.Tick += delegate { form.Close(); };
timer.Interval = 5000;
timer.Start();
}
Invoke just places the delegate into the message queue of the thread you want to invoke it on. You could use the Dispatcher class to insert the delegate with a high priority, but there is no gurante that this will meet you timing constraints if the thread is doing a lot of work.
But this might be an indication that you are doing to much work on the user interface thread. Not responding for a second is a pain to a user. So you might think about moving some work out of the user interface thread.
I'm currently designing/reworking the databinding part of an application that makes heavy use of winforms databinding and updates coming from a background thread (once a second on > 100 records).
Let's assume the application is a stock trading application, where a background thread monitors for data changes and putting them onto the data objects. These objects are stored in a BindingList<> and implement INotifyPropertyChanged to propagate the changes via databinding to the winforms controls.
Additionally the data objects are currently marshalling the changes via WinformsSynchronizationContext.Send to the UI thread.
The user is able to enter some of the values in the UI, which means that some values can be changed from both sides. And the user values shouldn't be overritten by updates.
So there are several question coming to my mind:
Is there a general design-guildline how to do that (background updates in databinding)?
When and how to marshal on the UI thread?
What is the best way of the background thread to interact with
binding/data objects?
Which classes/Interfaces should be used? (BindingSource, ...)
...
The UI doesn't really know that there is a background thread, that updates the control, and as of my understanding in databinding scenarios the UI shouldn't know where the data is coming from... You can think of the background thread as something that pushes data to the UI, so I'm not sure if the backgroundworker is the option I'm searching for.
Sometimes you want to get some UI response during an operation in the data-/business object (e.g. setting the background during recalculations). Raising a propertychanged on a status property which is bound to the background isn't enough, as the control get's repainted after the calculation has finished? My idea would be to hook on the propertychanged event and call .update() on the control...
Any other ideas about that?
This is a hard problem since most “solutions” lead to lots of custom code and lots of calls to BeginInvoke() or System.ComponentModel.BackgroundWorker (which itself is just a thin wrapper over BeginInvoke).
In the past, I've also found that you soon wish to delay sending your INotifyPropertyChanged events until the data is stable. The code that handles one propriety-changed event often needs to read other proprieties. You also often have a control that needs to redraw itself whenever the state of one of many properties changes, and you don’t wan the control to redraw itself too often.
Firstly, each custom WinForms control should read all data it needs to paint itself in the PropertyChanged event handler, so it does not need to lock any data objects when it was a WM_PAINT (OnPaint) message. The control should not immediately repaint itself when it gets new data; instead, it should call Control.Invalidate(). Windows will combine the WM_PAINT messages into as few requests as possible and only send them when the UI thread has nothing else to do. This minimizes the number of redraws and the time the data objects are locked. (Standard controls mostly do this with data binding anyway)
The data objects need to record what has changed as the changes are made, then once a set of changes has been completed, “kick” the UI thread into calling the SendChangeEvents method that then calls the PropertyChanged event handler (on the UI thread) for all properties that have changed. While the SendChangeEvents() method is running, the data objects must be locked to stop the background thread(s) from updating them.
The UI thread can be “kicked” with a call to BeginInvoke whenever a set of update have bean read from the database. Often it is better to have the UI thread poll using a timer, as Windows only sends the WM_TIMER message when the UI message queue is empty, hence leading to the UI feeling more responsive.
Also consider not using data binding at all, and having the UI ask each data object “what has changed” each time the timer fires. Databinding always looks nice, but can quickly become part of the problem, rather then part of the solution.
As locking/unlock of the data-objects is a pain and may not allow the updates to be read from the database fast enough, you may wish to pass the UI thread a (virtual) copy of the data objects. Having the data object be persistent/immutable so that any changes to the data object return a new data object rather than changing the current data object can enable this.
Persistent objects sound very slow, but need not be, see this and that for some pointers. Also look at this and that on Stack Overflow.
Also have a look at retlang - Message-based concurrency in .NET. Its message batching may be useful.
(For WPF, I would have a View-Model that sets in the UI thread that was then updated in ‘batches’ from the multi-threaded model by the background thread. However, WPF is a lot better at combining data binding events then WinForms.)
Yes all the books show threaded structures and invokes etc. Which is perfectly correct etc, but it can be a pain to code, and often hard to organise so you can make decent tests for it
A UI only needs to be refreshed so many times a second, so performance is never an issue, and polling will work fine
I like to use a object graph that is being continuously updated by a pool of background threads. They check for actual changes in data values and when they notice an actual change they update a version counter on the root of the object graph (or on each main item whatever makes more sense) and updates the values
Then your foreground process can have a timer (same as UI thread by default) to fire once a second or so and check the version counter, and if it changes, locks it (to stop partial updates) and then refreshes the display
This simple technique totally isolates the UI thread from the background threads
There is an MSDN article specific on that topic. But be prepared to look at VB.NET. ;)
Additionally maybe you could use System.ComponentModel.BackgroundWorker, instead of a generic second thread, since it nicely formalize the kind of interaction with the spawned background thread you are describing. The example given in the MSDN library is pretty decent, so go look at it for a hint on how to use it.
Edit:
Please note: No marshalling is required if you use the ProgressChanged event to communicate back to the UI thread. The background thread calls ReportProgress whenever it has the need to communicate with the UI. Since it is possible to attach any object to that event there is no reason to do manual marshalling. The progress is communicated via another async operation - so there is no need to worry about neither how fast the UI can handle the progress events nor if the background thread gets interruped by waiting for the event to finish.
If you prove that the background thread is raising the progress changed event way too fast then you might want to look at Pull vs. Push models for UI updates an excellent article by Ayende.
I just fought a similar situation - badkground thread updating the UI via BeginInvokes. The background has a delay of 10ms on every loop, but down the road I ran into problems where the UI updates which sometimes get fired every time on that loop, can't keep up with teh freq of updates, and the app effectively stops working (not sure what happens- blew a stack?).
I wound up adding a flag in the object passed over the invoke, which was just a ready flag. I'd set this to false before calling the invoke, and then the bg thread would do no more ui updates until this flag is toggled back to true. The UI thread would do it's screen updates etc, and then set this var to true.
This allowed the bg thread to keep crunching, but allowed the ui to shut off the flow until it was ready for more.
Create a new UserControl, add your control and format it (maybe dock = fill) and add a property.
now configure the property to invoke the usercontrol and update your element, each time you change the property form any thread you want!
thats my solution:
private long value;
public long Value
{
get { return this.value; }
set
{
this.value = value;
UpdateTextBox();
}
}
private delegate void Delegate();
private void UpdateTextBox()
{
if (this.InvokeRequired)
{
this.Invoke(new Delegate(UpdateTextBox), new object[] {});
}
else
{
textBox1.Text = this.value.ToString();
}
}
on my form i bind my view
viewTx.DataBindings.Add(new Binding("Value", ptx.CounterTX, "ReturnValue"));
This is a problem that I solved in Update Controls. I bring this up not to suggest you rewrite your code, but to give you some source to look at for ideas.
The technique that I used in WPF was to use Dispatcher.BeginInvoke to notify the foreground thread of a change. You can do the same thing in Winforms with Control.BeginInvoke. Unfortunately, you have to pass a reference to a Form object into your data object.
Once you do, you can pass an Action into BeginInvoke that fires PropertyChanged. For example:
_form.BeginInvoke(new Action(() => NotifyPropertyChanged(propertyName))) );
You will need to lock the properties in your data object to make them thread-safe.
This post is old but I thought I'd give options to others. It seems once you start doing async programming and Windows Forms databinding you end up with problems updating Bindingsource datasource or updating lists bound to windows forms control. I am going to try using Jeffrey Richters AsyncEnumerator class from his powerthreading tools on wintellect.
Reason:
1. His AsyncEnumerator class automatically marshals background threads to UI threads so you can update controls as you would doing Synchronous code.
2. AsyncEnumerator simplifies Async programming. It does this automatically, so you write your code in a Synchronous fashion, but the code is still running in an asynchronous fashion.
Jeffrey Richter has a video on Channel 9 MSDN, that explains AsyncEnumerator.
Wish me luck.
-R
I am late to the party but I believe this is still a valid question.
I would advise you to avoid using data binding at all and use Observable objects instead.
The reason is, data binding looks cool and when implemented the code looks good, but data binding miserably fails when there is lot os asynchronous UI update or multi-threading as in your case.
I have personally experienced this problem with asynchronous and Databinding in prod, we even didn't detect it in testing, when users started using all different scenarios things started to break down.