What solutions do I have if I want to prevent the UI from freezing while I deserialize a large number of UI elements in WPF? I'm getting errors complainig that the objects belong on the UI Thread when I'm trying to load them in another thread. So, what options do I have to prevent the Vista "Program not responding" error while I'm loading my UI data? Can I rely on a single-threaded solution, or am I missing something regarding perhaps multiple UI Threads?
If you only use a single thread then the UI will freeze while you do any amount of processing.
If you use a BackgroundWorker thread you'll have more control over what happens & when.
To update the UI you need to use Dispatcher.Invoke from your background thread to marshal the call across the thread boundary.
Dispatcher.Invoke(DispatcherPriority.Background,
new Action(() => this.TextBlock.Text = "Processing");
You can turn the flow of control on its head using DispatcherFrames, allowing a deserialization to proceed on the UI thread in the background.
First you need a way to get control periodically during deserialization. No matter what deserializer you are using, it will have to call property sets on your objects, so you can usually add code to the property setters. Alternatively you could modify the deserializer. In any case, make sure your code is called frequently enough
Each time you receive control, all you need to do is:
Create a DispatcherFrame
Queue an event to the dispatcher using BeginInvoke that sets Continue=false on the frame
Use PushFrame to start the frame running on the Dispatcher
In addition, when calling the deserializer itself make sure you do it from Dispatcher.BeginInvoke, or that your calling code doesn't hold any locks etc.
Here's how it would look:
public partial class MyWindow
{
SomeDeserializer _deserializer = new SomeDeserializer();
byte[] _sourceData;
object _deserializedObject;
...
void LoadButton_Click(...)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
_deserializedObject = _deserializer.DeserializeObject(_sourceData);
}));
}
}
public class OneOfTheObjectsBeingDeserializedFrequently
{
...
public string SomePropertyThatIsFrequentlySet
{
get { ... }
set { ...; BackgroundThreadingSolution.DoEvents(); }
}
}
public class BackgroundThreadingSolution
{
[ThreadLocal]
static DateTime _nextDispatchTime;
public static void DoEvents()
{
// Limit dispatcher queue running to once every 200ms
var now = DateTime.Now;
if(now < _nextDispatchTime) return;
_nextDispatchTime = now.AddMilliseconds(200);
// Run the dispatcher for everything over background priority
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
frame.Continue = false;
}));
Dispatcher.PushFrame(frame);
}
}
Checking DateTime.Now in DoEvents() isn't actually required for this technique to work, but will improve performance if SomeProperty is set very frequently during deserialization.
Edit: Right after I wrote this I realized there is an easier way to implement the DoEvents method. Instead of using DispatcherFrame, simply use Dispatcher.Invoke with an empty action:
public static void DoEvents()
{
// Limit dispatcher queue running to once every 200ms
var now = DateTime.Now;
if(now < _nextDispatchTime) return;
_nextDispatchTime = now.AddMilliseconds(200);
// Run the dispatcher for everything over background priority
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(() => {}));
}
Here is a wonderful blog posting from Dwane Need that discusses all the available options for working with UI elements amongst multiple threads.
You really haven't given enough detail to give a good prescription. For example, why are you creating UI elements yourself at all instead of using databinding? You might have a good reason, but without more details it's hard to give good advice. As another example of detail that would be useful, are you looking to build complex deeply nested control hierarchies for each piece of data or do you just need to draw a simple shape?
I had a similar problem with my panel which was moving its items. The UI was freezing because I was using a DispatcherTimer at priority Loaded. The problem is gone as soon as I changed it to DispatcherPriority.Input.
You can still make your long processing in a separate thread, but when finished you have to synchronize with the UI thread by calling Dispatcher.BeginInvoke(your_UI_action_here)
Recommendations from the OldNewThing blog.
It is best if you do go the threaded route, to have one GUI thread and spawn your work load off to another thread that when finishes reports back to the main GUI thread that its done. The reason for this is because you will not get into thread issues with your GUI interface.
So One GUI Thread
Many worker threads that do the work.
If any of your threads do hang the user is in direct control over your application can can close down the thread without effecting his experience with the application interface. This will make him happy because your user will feel in control other than him constantly click THAT STOP BUTTON AND IT WONT STOP SEARCHING.
Try freezing your UIElements. Frozen objects can be passed between threads without encountering an InvalidOperationException, so you deserialize them & freeze them on a background thread before using them on your UI thread.
Alternatively, consider dispatching the individual deserializations back to the UI thread at background priority. This isn't optimal, since the UI thread still has to do all of the work to deserialize these objects and there's some overhead added by dispatching them as individual tasks, but at least you won't block the UI - higher priority events like input will be able to be interspersed with your lower priority deserialization work.
Related
In my console app I've been trying to start an STA thread and show a WPF window. I've succeeded showing the window, but I had issues with a library using Dispatcher (System.Reactive.Windows.Threading to be precised). I've fixed my problems using code from this doc - what I was missing was calling System.Windows.Threading.Dispatcher.Run() in the right moment.
But after reading this article carefully (and others) and examining Dispatcher's API I still don't know: how to tell WPF Dispatcher is correctly initialized and running? It'd be very useful for libraries requiring Dispatcher, if they could check it.
-- EDIT --
// Extending my question after #Peter Duniho remarks
Having C# console application I wanted to create a WPF window, where I'll observe, on Dispatcher, some data. The full code is here
So I have my program, where Main class looks like that:
static void Main(string[] args)
{
var observable = Observable
.Interval(TimeSpan.FromMilliseconds(500))
.TakeWhile(counter => counter < 10);
var thread = new Thread(() =>
{
new TestWindow(observable);
Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
Console.ReadKey();
}
I create here an observable with Interval operator, which ticks every 500 milliseconds, and I pass it to a TestWindow (code below) which I run on a separate thread. After 10 ticks I end the observable sequence.
TestWindow class:
public class TestWindow : Window
{
public TestWindow(IObservable<long> observable)
{
var isDispatcherInitialized = false;
Dispatcher.Invoke(() => isDispatcherInitialized = true, DispatcherPriority.ApplicationIdle);
if (!isDispatcherInitialized)
throw new ApplicationException("Dispatcher not initialized");
observable
.ObserveOnDispatcher()
.Window(TimeSpan.FromMilliseconds(600))
.Subscribe(_ => Console.WriteLine($"OnNext, observed on dispatcher with Window operator"));
}
}
In TestWindow I observe my observable on Dispatcher (ObserveOnDispatcher()), and I use Window operator.
PROBLEM with that code (tested on .NET Framework and on .NET Core 3.0 preview):
if I don't call Dispatcher.Run(); when starting STA thread, the validation where I call Dispatcher.Invoke() will be passed, but ObserveOnDispatcher() won't work correctly - subscription never stops, and the message: "OnNext, observed on dispatcher with Window operator" goes forever.
That's why I was wondering if I could detect Dispatcher's state.
It would be helpful if you would elaborate on this statement:
It'd be very useful for libraries requiring Dispatcher, if they could check it.
That is, why would it be useful?
For one, if you are using a third-party library (such as the Reactive Extensions (Rx) for .NET you mentioned, how would you knowing how to check for the dispatcher state help that library?
For another, what scenario doesn't work for you? Lacking a specific problem to solve, your question is fairly open-ended. It's not clear what type of answer would actually address your question.
That said, two things come to mind:
If you want to know if a dispatcher has been created for a given thread, you should call System.Windows.Threading.Dispatcher.FromThread(System.Threading.Thread.CurrentThread); This will return null if not dispatcher has been created yet for that thread, or a reference to the dispatcher if it has been.
If you want to know that the dispatcher has completed initialization and is ready to dispatch things, it seems to me that the easiest thing to do is ask it to dispatch something, and when it does, it's ready. Using an overload of one of the invoking methods (BeginInvoke(), Invoke(), or InvokeAsync()) that takes a DispatcherPriority value, you can get fine-grained information regarding just what level of initialization has happened. For example, if you pass DispatcherPriority.Normal or DispatcherPriority.Send, when your delegate is invoked you'll know that the dispatcher is running. But if you pass DispatcherPriority.ApplicationIdle or DispatcherPriority.SystemIdle, you'll know that not only is the dispatcher running, but it's cleared its backlog of initial events to dispatch and the application is sitting waiting for user input.
I'm wondering if there is some technique or method to detect calls in a WPF app that are not using async/await.
The reason I ask is that the WPF app I am working on is stuttering and halting on the screen updates, and I can't seem to track down the source of the calls that are blocking the GUI thread.
I am using VS2012 and VS2013 with the MVVM design pattern.
This doesn't answer your question directly but this will help with identifying when the dispatcher thread is overloaded, the following code uses an event handler around the DispatcherInactive event to calculate how long dispatcher thread has been overloaded (blocked) with work:
var maxThreshold = TimeSpan.FromMilliseconds(750);
var previous = DateTime.Now;
Application.Current.MainWindow
.Dispatcher.Hooks.DispatcherInactive += (sender, eventArgs) =>
{
var current = DateTime.Now;
var delta = current - previous;
previous = current;
if (delta > maxThreshold)
{
Debug.WriteLine("UI Freeze = {0} ms", delta.TotalMilliseconds);
}
};
I would suggest this is only ever used in debug mode, so it would be wrapped in a #if DEBUG block. You don't want this running in production.
I think a performance profiler could help you in this case.
I personally recommend ANTS profiler, you can download a trial and test your application with it. It would tell you where a certain period of the execution of your app is spending its time in.
Usually it is very easy to find what is blocking the UI. There can be 2 cases - either you are performing an expensive operation on the UI thread, you can test if the thread executing is the UI thread using:
if (Thread.CurrentThread == Dispatcher.CurrentDispatcher.Thread)
{
//UI Thread
}
Or, you are displaying to many controls and it takes long time to render. Usually the lists cause this when the list is not virtualizing items.
You can subscribe to events of the WPF dispatcher to track down your problem. The UI thread queues work items inside an object called a Dispatcher. The Dispatcher selects work items on a priority basis and runs each one to completion.
To monitor the Dispatcher you can e.g. subscribe to these operations:
Dispatcher.Hooks.OperationPosted += Hooks_OperationPosted;
Dispatcher.Hooks.OperationStarted += Hooks_OperationStarted;
Dispatcher.Hooks.OperationAborted += Hooks_OperationAborted;
You find a full list here.
Depending on your problem you might find yourself better of with a commercial profiler but quite often you get good results with just observing the dispatcher queue.
I need a thread-safe (concurrent) version of ObservableCollection in Silverlight 5. I'm struggling to find a way to create one given the lack of multi-threading support in SL5 (no ReaderWriterLock, no Collections.Concurrent to speak of, etc).
I need the collection to support UI binding while being updated by another thread. It is not acceptable for my to dispatch all of my updates to the UI thread when the process runs in the background. Ideally, the background process is free to update the collection as needed and the UI receives notifications as changes occur. This is possible with .NET 4 and I've found ways to accomplish this for WPF but nothing for SL. I can't use the WPF examples because they rely on ReaderWriterLock which, AFAIK, is not present in SL5.
Any direction and/or examples is appreciated.
UPDATE
Following the asynchronous communication pattern used (required) in Silverlight, the 'callback' method, or handler, runs on a different thread. Using the TPL (as we do), this is the task's Continuation.
Because this code runs on a different thread, any statements that affect the ObservableCollection have to be marshalled back to the UI thread. This means that the process logic and time are now consuming the resources of the UI thread.
The point of the concurrent collections in .NET is to allow producers and consumers to run in different threads yet seamlessly work with the shared data in the collection. The 'producers' in a SL client application will be the async callback or task continuation with the 'consumers' being the UI which is bound to the collection.
I also ran into this problem repeatedly, which caused me to go down the same road you're looking at. There is a library that has helped me immensely with this task:
http://ch.codeplex.com/
I've implemented my own ConcurrentObservableCollection using the TinyReaderWriterLock and implementing IList, INotifyCollectionChanged, INotifyPropertyChanged
I used this blog post as a starting point.
http://www.deanchalk.me.uk/post/Thread-Safe-Dispatcher-Safe-Observable-Collection-for-WPF.aspx
In my version I allow all calls to execute on the calling thread and only marshal the INotifyCollectionChanged and INotifyPropertyChanged calls back to the UI Thread like this:
public void Add(T item)
{
mSyncLock.LockForWriting();
innerCollection.Add(item);
mSyncLock.ReleaseForWriting();
var index = IndexOf(item);
OnNotifyPropertyChanged(COUNT_PROPERTY);
OnNotifyPropertyChanged(INDEXER_PROPERTY);
OnNotifyCollectionChanged(NotifyCollectionChangedAction.Add, item, index); // This is an overload of OnNotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
}
where
protected virtual void OnNotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (CollectionChanged == null) return;
ThreadSafeInvoke(() => CollectionChanged(this, e));
}
and
private static void ThreadSafeInvoke(Action action)
{
if (Deployment.Current.Dispatcher.CheckAccess())
{
action.Invoke();
}
else
{
Deployment.Current.Dispatcher.BeginInvoke(action);
}
}
This has worked well for me. There is a small performance hit involved with the locking, but it's not significant for most uses.
I'm writing a WPF application (new technique, mostly I've been writing in WinForms). My goal is to make UI responsive whole time, and I've read that it can be achived using Threading/BackgroundWorker. I think that I should use background worker to put there time consuming methods. But I plan to use method *m_AddLog(string logText)* which should append text to textbox. This method I want to call from main UI thread aswell as from background worker, so messages would be sent immediatelly while processing in backround instead of waiting for background task to end. Could you please kindly advise how to write properly write these methods for UI being fully responsive as I don't know much about delegates, invoking, background workers, etc?
If you want to run some background process then update the UI on completion the following pattern works well (if ran from the UI thread).
Task.Factory.StartNew(() =>
{
// Background work
}).ContinueWith((t) => {
// Update UI thread
}, TaskScheduler.FromCurrentSynchronizationContext());
Put the background work in the first task and the UI work in the following his is task. The TaskScheduler option ensures the second task runs on the UI thread.
Most of the items in wpf application using task and dispatcher will give better results.
have a Look at the following code hope this may helps you..
In the below code i have considered a scenario like fetching images from remote server and i created a task for doing that... in the task in side for loop i am using dispatched thread to update UI to notify the progress... and after fetching all the images execution will be moved to continue block....
You can have a look at the following link that may helps you to understand it better
ObservableCollection items= new ObservableCollection();
TaskFactory tFactory = new TaskFactory();
tFactory.StartNew(() =>
{
for (int i = 0; i < 50; i++)
{
//Request to server
System.Windows.Application.Current.Dispatcher.BeginInvoke((Action)delegate()
{
// UPDATE PROGRESS BAR IN UI
});
items.Add(("");
}
}).ContinueWith(t =>
{
if (t.IsFaulted)
{
// EXCEPTION IF THREAD IS FAULT
throw t.Exception;
}
System.Windows.Application.Current.Dispatcher.BeginInvoke((Action)delegate()
{
//PROCESS DATA AND DISPLAY
});
});
As People Said there are tons of question that will show you how to do that But if you want to compare it you can find it here with detailed comparison
I know this question has been asked before, but I feel it wasn't asked correctly.
I have an intensive operation and I'd like the UI to remain responsive. I've read a few posts that say Background worker is the best way to go, however, I think this assumes you have the source code to the intensive task.
I have a library that I have no source code for, the only way I can check on the progress is to attach to events that get fired and get information that way.
The example I saw on the MSDN site assumed one would have the source.
I know how to get progress (which is a percentage value) by attaching to events, but how do I get that value back to the UI?
The following answer is based on my gut feeling and have not actually done it a test with third party libs.
Call your third party lib code as usual you call in a simple background (not BackGroundWorker) thread.
Attach the library components' events to normal event handlers in your code (meant to update UI).
In the event handler code should look like this:
private void EventHandler(object sender, DirtyEventArgs e)
{
if (myControl.InvokeRequired)
myControl.Invoke(new MethodInvoker(MethodToUpdateUI), e);
else
MethodToUpdateUI(e);
}
private void MethodToUpdateUI(object obj)
{
// Update UI
}
Attach to the progress events in the third party component and call ReportProgress on the BackgroundWorker. Have your UI attach to the BackgroundWorker.ProgressChanged event to update the UI.
You can have the desired effect by using a second thread and a thread safe queue.
You can create a second thread that will listen for the events.
When a new event happens it pushes the event information to a queue (thread safe- synchronized).
Using a Timer (Windows.Forms.Timer) that will check that queue every x time and in case new events exist can update the UI.
Because the timer runs in the main thread it can safely update the UI and if you make it light weight it will not block it long enough to be noticed.
A similar discussion is on this Q. If you can't or don't want to use the BackgroundWorker for whatever reason you can use your own thread and marshal events from it back onto your UI thread.
private void Initialise() {
MyLibClass myLibClass = new MyLibClass();
myLibClass.SomeEvent += SomeEventHandler;
ThreadPool.QueueUserWorkItem(myLibClass.StartLongTask);
}
private void SomeEventHandler(EventArgs e) {
if (this.Dispatcher.Thread != Thread.CurrentThread) {
this.Dispatcher.Invoke(delegate { DoStuffOnUIThread(e); });
}
else {
DoStuffOnUIThread(e);
}
}