I know there are a lot of questions about this already, but I seem to have a fundamental misunderstanding about how BindingOperations.EnableCollectionSynchronization(observableC, padlock); works.
I have a WPF app using mvvm and in my viewmodel I want to update my observablecollection.
After some googling I landed on this solution that imo should work: Calling it the first time works fine, but after sleeping for 1 minute it gives me this:
System.NotSupportedException: 'This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.'
public MainViewModel()
{
MainOc= new ObservableCollection<DataModel>();
MainView= CollectionViewSource.GetDefaultView(MainOc);
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
BindingOperations.EnableCollectionSynchronization(MainOc, padlock);
BindingOperations.EnableCollectionSynchronization(MainView, padlock);
}));
Task.Run(() => GetData());
}
private async void GetData()
{
while (true)
{
lock (padlock)
{
MainOc.Clear();
}
foreach (DataRow row in tempTable.Rows)
{
lock (padlock) {
MainOc.Add(new DataModel());
}
}
lock (padlock)
{
MainView= CollectionViewSource.GetDefaultView(MainOc);
}
Thread.Sleep(TimeSpan.FromMinutes(1));
}
}
I would suspect Application.Current.Dispatcher.BeginInvoke, since this will be run at some later time on the UI thread. Presumably the constructor is already running on the UI thread, so this code will be placed last in the queue of tasks the UI thread is scheduled to perform. The documentation for EnableCollectionSynchronization states
The call must occur on the UI thread.
The call must occur before using the collection on a different thread or before attaching the collection to the ItemsControl, whichever is later.
I'm not confident the later point is fulfilled. I would expect the order to be something like:
MainViewModel() is run
GetData() start updating the collection (on background thread)
The viewmodel is attached to the view
BindingOperations.EnableCollectionSynchronization is called
So I would at least try to call BindingOperations.EnableCollectionSynchronization directly, without the BeginInvoke. Or at the very least, place some breakpoints or logging to verify that the EnableCollectionSynchronization is called before the viewmodel is attached.
In any case I would probably not recommend using that kind of synchronization mechanism. My recommendation would be to:
Use a dispatch timer to invoke a method on the UI thread every minute
If method do any slow operation, like fetching data from the database, make the method async and either do a async database call, or a synchronous database call on a background thread that returns the result. In either case the call should be awaited.
Once you have the data, update your collections to update the UI. This code will be run on the UI thread, even if you awaited work on a background thread, so there is no need for synchronization.
Related
EDIT:
please see question history, for unchanged question in order not to invalidate comments.
I am clicking button that executes certain codes and it creates a thread (System.Threading.Thread). When I reclick button which starts process it hangs and freezes ui. What could be the reason?
public partial class ucLoader : UserControl
{
//lock object for whole instance of class ucLoader
private object lockUcLoader = new object();
//bringing info from ui
private void btnBringInfo_Click(object sender, EventArgs e)
{
lock (lockUcLoader)
{
btnBringInfo_PerformClick(false);
}
}
//using this method because it could be called when even button not visible
internal void btnBringInfo_PerformClick(bool calledFromBandInit)
{
lock (lockUcLoader) //HANGS HERE when called multiple times and ui freeze as well
//by the way I am using (repetitive) lock, because this method also called independently from btnBringInfo_Click
{
//...
this.btnLoad_PerformClick();
}
}
//Another button perform click that could be triggered elsewhere when even button not visible
private void btnLoad_PerformClick()
{
lock (lockUcLoader) //I am using (repetitive) lock, because this method also called independently from btnBringInfo_PerformClick
{
//...
Run();
}
}
//method for creating thread which System.Threading.Thread
private void Run()
{
lock (lockUcLoader) //Maybe this lock is NOT REQUIRED, as it is called by only btnLoad_PerformClick(), could you please confirm?
{
//some code that thread can be killed when available, you can ingore this two lines as they are irrelevant to subject, I think
Source = new CancellationTokenSource();
Token = Source.Token;
var shell = new WindowsShell();
Thread = new Thread((object o) =>
{
//...
var tokenInThread = (CancellationToken)o;
exitCode =TaskExtractBatchFiles(cls, shell, exitCode);
using (var logEnt = new logEntities())
{
//Do some db operation
//...
this.Invoke((MethodInvoker)delegate
{
//do some ui update operation
//...
});
}
}
Thread.Start(Token);
}
}
public void Progress(string message)
{
Invoke((MethodInvoker)delegate //ATTENTION HERE see below picture Wait occurs here
{
if (message != null && message.Trim() != string.Empty)
{
this.txtStatus.AppendText(message + Environment.NewLine);
}
});
}
}
In order to avoid get closed question, what my question is how can I prevent
below method can be accesses with out lock from background thread and ui thread
public void Progress(string message)
{
Invoke((MethodInvoker)delegate //ATTENTION HERE see below picture Wait occurs here
{
if (message != null && message.Trim() != string.Empty)
{
this.txtStatus.AppendText(message + Environment.NewLine);
}
});
}
Invoke((MethodInvoker)delegate ...
Whenever you use the lock statement in your code then you always run the risk of inducing deadlock. One of the classic threading bugs. You generally need at least two locks to get there, acquiring them in the wrong order. And yes, there are two in your program. One you declared yourself. And one you cannot see because it is buried inside the plumbing that makes Control.Invoke() work. Not being able to see a lock is what makes deadlock a difficult problem to debug.
You can reason it out, the lock inside Control.Invoke is necessary to ensure that the worker thread is blocked until the UI thread executed the delegate target. Probably also helps to reason out why the program deadlocked. You started the worker thread, it acquired the lockUcLoader lock and starts doing its job, calling Control.Invoke while doing so. Now you click the button before the worker is done, it necessarily blocks. But that makes the UI thread go catatonic and no longer capable of executing the Control.Invoke code. So the worker thread hangs on the Invoke call and it won't release the lock. And the UI thread hangs forever on the lock since the worker can't complete, deadlock city.
Control.Invoke dates from .NET 1.0, a version of the framework that has several serious design mistakes in code related to threading. While meant to be helpful, they just set death-traps for programmers to blunder into. What is unique about Control.Invoke is that it is never correct to use it.
Distinguish Control.Invoke and Control.BeginInvoke. You only ever need Invoke when you need its return value. Note how you don't, using BeginInvoke instead is good enough and instantly solves the deadlock. You'd consider Invoke to obtain a value from the UI so you can use it in the worker thread. But that induces other major threading issue, a threading race bug, the worker has no idea what state the UI is in. Say, the user might be busy interacting with it, typing a new value. You can't know what value you obtain, it will easily be the stale old value. Inevitably producing a mismatch between the UI and the work being done. The only way to avoid that mishap is to prevent the user from typing a new value, easily done with Enable = false. But now it no longer makes sense to use Invoke, you might as well pass the value when you start the thread.
So using BeginInvoke is already good enough to solve the problem. But that is not where you should stop. There is no point to those locks in the Click event handlers, all they do is make the UI unresponsive, greatly confuzzling the user. What you must do instead is set the Enable properties of those buttons to false. Set them back to true when the worker is done. Now it can't go wrong anymore, you don't need the locks and the user gets good feedback.
There is another serious problem you haven't run into yet but you must address. A UserControl has no control over its lifetime, it gets disposed when the user closes the form on which it is hosted. But that is completely out of sync with the worker thread execution, it keeps calling BeginInvoke even though the control is dead as a doornail. That will make your program bomb, hopefully on an ObjectDisposedException. A threading race bug that a lock cannot solve. The form has to help, it must actively prevent the user from closing it. Some notes about this bug in this Q+A.
For completeness I should mention the third most common threading bug that code like this is likely to suffer from. It doesn't have an official name, I call it a "firehose bug". It occurs when the worker thread calls BeginInvoke too often, giving the UI thread too much work to do. Happens easily, calling it more than about thousand times per second tends to be enough. The UI thread starts burning 100% core, trying to keep up with the invoke requests and never being able to catch up. Easy to see, it stops painting itself and responding to input, duties that are performed with a lower priority. That needs to be fixed the logical way, updating UI more than 25 times per second just produces a blur that the human eye can't observe and is therefore pointless.
In doing my research here there seem to be about a million different ways to accomplish this, but the pros and cons of each are less unclear. One possibility that seems to accomplish what I'm after is:
private async Task SomeMostlyUIMethod(byte[] someParam = null)
{
if (InvokeRequired)
{
Task result = Task.Run(() => Invoke((Action)(async () => await SomeMostlyUIMethod(someParam))));
await result;
return;
}
else
{
// do some stuff
}
}
That seems to work, it feels like there should be a more clear solution for this. I'm not invoking on a per control modified basis because the method modifies a large number of different UI components, but also need to keep the method asynchronous since it has some expensive non-ui tasks it carries out as well.
to make work item will be executed on UI thread, you probably need the current synchronization context:
factory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
and use that factory to StartNew any task involved in GUI control updating.
You need to launch the async operation from an UI thread (main thread):
await Task.Run(DoYourStuffAsync);
This is equivalent to:
await Task.Run(DoYourStuffAsync).ConfigureAwait(true);
If the boolean argument of ConfigureAwait (bool continueOnCapturedContext) is true, the code that is below the await (also called continuation) will be executed in the calling thread (UI thread).
What I suggest is to do all your processing in an async way, create an outcome object, and then update the UI element in the continuation with the outcome object.
In this way you are using the UI thread only for UI stuff.
I am developping a WPF application.
I have a couple of timers that work asynchronously and they are created with System.Threading.Timer objects.
new System.Threading.Timer(
new System.Threading.TimerCallback(Timer_Function),
null,
timing,
timing
);
Timer_Function()
{
/*code that runs asynchronously */
}
In order to update the controls that are in WPF view I use delegate methods called by Dispatcher.Invoke otherwise the compiler would raise InvalidOperationException (The calling thread cannot access this object because a different thread owns it.)
My problem is that the delegate method do not run asynchronously and i have to do a lot of work in it so the application stops.
What can i do to run delegate method asynchronously?
What you need to do is separate out your business logic for determining what you should display, from the code that displays the results of those calculations to the UI. The business logic, the non-UI code, should be run in a non-UI thread and compute some result. That result should then be given to a method that will marshal to the UI thread and then display those results.
If you need your program to continue executing when the Timer_Function() code is run you could use a Task.Run to perform the work on a worker thread.
As always with parallel execution you need to beware of synchronization issues. Make sure you don't need the results before the work is processed and dispathed. Using the dispatcher as you mentioned might be enough, just make sure you think it through.
Something like:
Timer_Function()
{
Task.Run(() =>
{
/* do your work here */
});
}
Sorry if I misunderstood your issue
For asynchronous tasks, use this -
Task.Factory.StartNew(() =>
{
// Code which needs to run asynchronously
}.ContinueWith(task =>
{
Application.Current.Dispatcher.Invoke(new Action(() =>
{
// Code in which you are updating UI
});
}
I have a Task that I am starting and wish to wait for completion in a WPF app. Inside this task I invoke an Action on the dispatcher.
If I use Task.Wait() it appears to hang as if the method never finished. Also, breakpoints inside the Dispatcher.Invoke are never hit.
If I use Task.RunSyncronously() it appears to work correctly and breakpoints inside the Dispatcher are hit.
Why is there a difference?
Code sample below:
public void ExampleMethod()
{
// When doing the following:
var task = new Task(LoadStuff);
// This never returns:
task.Start();
task.Wait();
// This version, however, does:
task.RunSyncronously();
}
private void LoadStuff()
{
ObservableCollection<StuffObj> stuff = Stuff.Load(arg1, true);
DispatchHelper.RunOnDispatcher(() =>
{
...
});
}
public static class DispatchHelper
{
public static void RunOnDispatcher(Action action)
{
Application.Current.Dispatcher.Invoke(action);
}
}
Yes, there's a major difference. If you use RunSyncronously you just run the task in the UI thread. If you start it up in a background thread and us Wait then the code is running in a background thread and the UI thread is blocked. If the code within that task is invoking to the UI thread, and the UI thread is being blocked (by the Wait) then you've created a deadlock, and the application will remain frozen.
Note that if you used, RunSyncronously on that task from a non-UI thread, and the UI thread was being blocked by something else, you would still see the deadlock.
Now, as for what you should do, there are really two options here:
The task itself doesn't actually take a long time, and it really should run in the UI thread rather than in a background thread. The UI thread won't be frozen (temporarily) for long enough to be a problem doing all of this work directly in the UI. If this is the case, you probably shouldn't even make it a Task, just put the code in a method and call the method.
The task does take a long time to run, and then it updates the UI after doing that work. If that is the case then it's important that it not be RunSyncronously but started in a background thread. In order to prevent your entire application from deadlocking it will mean that you'll need to not block the UI thread through a Wait call. What you need to do if you have some code that you want to run after the task finishes, is to add a continuation to the task. In C# 4.0 this could be done by calling ContinueWith on the task, and adding in a delegate to be run. In C# 5.0+ you could instead await on the relevant task (rather than Waiting on it, which is actually a big difference) and it will automatically wire up the remainder of the method to run as a continuation for you (in effect it is syntactic sugar for an explicit ContinueWith call, but it's a very useful one).
I have the doubt regarding when to use the Dispatcher.Invoke to update something on UI from different Thread.
Here's my code...
public Window4()
{
InitializeComponent();
this.DataContext = this;
Task.Factory.StartNew(() => Test() );
}
private List<string> listOfString = new List<string>();
public List<string> ListOfString
{
get { return listOfString; }
set { listOfString = value; }
}
public void Test()
{
listOfString.Add("abc");
listOfString.Add("abc");
listOfString.Add("abc");
}
<Grid>
<ListView ItemsSource="{Binding ListOfString}" />
</Grid>
I am starting a new Task on the different Thread, do i need to use Dispatcher.BeginInvoke to update the UI.
In this case it is updating the UI, but i've seen some scenarios where people update UI using Dispatcher.Invoke or BeginInvoke from the different Thread.
So my question is when we have to do that and why in this case it is working fine.
Thanks & Regards,
BHavik
I have the doubt regarding when to use the Dispatcher.Invoke to update
something on UI from different Thread.
When you are on a different thread you will always have to use the dispatcher to update a ui component that belongs to another thread.
I am starting a new Task on the different Thread, do i need to use
Dispatcher.BeginInvoke to update the UI.
Tasks allow for multiple operations to be performed without blocking the thread they are called from but that doesn't mean they are on a different thread. However when updating the UI from inside a Task you will need to use the dispatcher.
In this case it is updating the UI, but i've seen some scenarios where
people update UI using Dispatcher.Invoke or BeginInvoke from the
different Thread.
Invoke will block the calling thread while it is performing the action and BeginInvoke will not. BeginInvoke will return control immediately to the caller, Invoke may cause the calling thread to hang if it is performing a heavy operation.
This is from msdn documentation,
In WPF, only the thread that created a DispatcherObject may access
that object. For example, a background thread that is spun off from
the main UI thread cannot update the contents of a Button that was
created on the UI thread. In order for the background thread to access
the Content property of the Button, the background thread must
delegate the work to the Dispatcher associated with the UI thread.
This is accomplished by using either Invoke or BeginInvoke. Invoke is
synchronous and BeginInvoke is asynchronous.
Edit: In response to your comment I ran some tests.
When calling Test() from a task (without using the dispatcher) I got this error "The calling thread cannot access this object because a different thread owns it."
So I created a method called PrintThreadID(). I printed the thread before entering the task then from inside the task and it does report both are running on the same thread ID.
The error is misleading because it says the calling thread is different than the one that owns it which the PrintThreadID() function shows is not true, they are in fact on the same thread. Tasks while on the same thread still cannot update a UI component without using Dispather.Invoke().
So here is a working example which will update the Grid from a task.
public partial class MainWindow : Window
{
public List<string> myList { get; private set; }
public MainWindow()
{
InitializeComponent();
myList = new List<string>();
label1.Content = Thread.CurrentThread.ManagedThreadId.ToString();
Task.Factory.StartNew(PrintThreadID);
Task.Factory.StartNew(Test);
}
private void PrintThreadID()
{
label1.Dispatcher.Invoke(new Action(() =>
label1.Content += "..." + Thread.CurrentThread.ManagedThreadId.ToString()));
}
private void Test()
{
myList.Add("abc");
myList.Add("abc");
myList.Add("abc");
// if you do not use the dispatcher you will get the error "The calling thread cannot access this object because a different thread owns it."
dataGrid1.Dispatcher.Invoke(new Action(() =>
{
dataGrid1.ItemsSource = myList.Select(i => new { Item = i });
}));
}
}
Your test isn't valid as it isn't actually updating your UI. If you want proof, add this sleep call:
public void Test()
{
Thread.Sleep(10000);
listOfString.Add("abc");
listOfString.Add("abc");
listOfString.Add("abc");
}
You'll find that your UI appears and the list is empty. 10 seconds, 30 seconds, 3 months later, the list won't contain your strings.
Instead your test is demonstrating a race condition - your Test() method is completing fast enough that the strings are added to the list before the UI appears on screen and reads the list.
To fix it, change your collection to an ObservableCollection<string>. But then you'll encounter the next problem - you can't update an ObservableCollection on a background thread. So that's where the Dispatcher comes in.