Call delegate method with controls asynchronously in a C# WPF application - c#

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
});
}

Related

How to dispatch to main thread?

I would like to execute some code from a non-main thread inside the main thread (UI thread) in .Net 6 with C#.
I've tried to use this code:
await Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
() => { }
);
This doesn't work, since Windows.UI.Core.CoreWindow.GetForCurrentThread() returns null.
My second try was:
await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
() => { }
);
This fails, because Windows.ApplicationModel.Core.CoreApplication.MainView throws a System.InvalidOperationException.
Another way should be:
await System.Windows.Threading.Dispatcher.RunAsync(
Windows.UI.Core.CoreDispatcherPriority.Normal,
() => { }
);
But the System.Windows.Threading namespace is not available for me, since I'm using .Net 6 and it's not longer supported in it.
Any idea, how I can execute some code from a non-main thread inside the main-thread (UI thread)?
I would like to execute some code from a non-main thread inside the main thread (UI thread) in .Net 6 with C#.
I strongly recommend that you don't. It's far cleaner to have your async methods use something like IProgress<T> to indirectly update the UI as necessary. If you structure your code so that the main thread calls the background threads instead of the background threads manipulating the UI through the UI thread, then you'll end up with a much cleaner design where your logic is less tied to your UI controls.
That said, if you really want to, then the solution is to capture the dispatcher on the UI thread before the background work begins, and have the background work use that dispatcher (not the "current dispatcher") when posting work to the UI thread.
SynchronizationContext is a good solution to switch to the main thread. But it's not implemented for all .Net app types.
For example, for a console app, there is no solution implemented.
But for Windows Forms, WindowsFormsSynchronizationContext works fine.
private SynchronizationContext _synchronizationContext;
Initialization inside, called inside the main thread:
_synchronizationContext = new WindowsFormsSynchronizationContext();
After this, you can call from a different thread:
SynchronizationContext.SetSynchronizationContext(_synchronizationContext);
... here we are in a separate thread
_synchronizationContext.Post(
(state) => {
... this will be executed in the main thread
},
null);
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync
(CoreDispatcherPriority.Normal, () =>
{
do something on UI thread
});

BindingOperations.EnableCollectionSynchronization The calling thread cannot access this object

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.

Deadlock using Control.Invoke?

I'm building an app using TPL in VS2010 Ultimate. The most of the times I run the app it becomes unresponsive when I Call DoRepresentation() from the UI's thread.
void DoRepresentation()
{
Parallel.ForEach(cgs, loopOptions, g =>
{
UpdateRepresentation(g);
});
}
void UpdateRepresentation(object g)
{
view.Invoke(new Action(() =>
{
representation = new MyRepresentation(g);
}));
}
I don't know why the app is becoming unresponsive. Am I having a deadlock?
Inside MyRepresentation I do some calls to OpenGL.
view is a Control inside Form1 (the main form).
When the app become unresponsive I pause it from the VS IDE and here's the info I get
In the "Parallel Tasks" window I get the following:
ID Status Message<br>
1 ?Waiting Task1 is waiting on object: "Task2"<br>
2 ?Waiting No waiting information available<br>
In the "Call Stack" window I get the following:
[In a Sleep, wait, or join]<br>
[External Code]<br>
Test.dll!Render.DoRepresentation()<br>
App1.exe!Form1.Button1_Click<br>
Any help will be appreciated.
Yes, you are having a deadlock. What Parallel.ForEach() does is that it runs the iterations using one or more threads including the current one and then blocks the current thread until all iterations are complete.
This means that if you call DoRepresentation() from the UI thread, you get a deadlock: the UI thread is waiting for iterations on other threads to finish, while those other threads are waiting for Invoke() to finish, which can't happen if the UI thread is blocked.
Also, in your case, using Parallel.ForEach() doesn't make any sense (assuming this is your actual code): you run new MyRepresentation() on the UI thread.
I don't understand what exactly is the code doing (it seems it overwrites representation in each iteration), but I think you should run ForEach() from a background thread. This means DoRepresentation() will return before it finishes its work and so Invoke() will work correctly.
In general, it's not a good idea to block the UI thread for a long time, so you should run any time-consuming code on another thread.
you can use the BeginInvoke insteed of Invoke Method. if you still need then you can lock an object and make sure that this will not be accessible from the other thread until its realized.
using the Begin Invoke Method
void UpdateRepresentation(object g)
{
view.BeginInvoke( new Action(() =>
{
representation = new MyRepresentation(g);
}));
}
Using the Lock
void UpdateRepresentation(object g)
{
lock(this)
{
view.Invoke(new Action(() =>
{
representation = new MyRepresentation(g);
}));
}
}
This comment applies to my specific app, which is a Windows app in C#: Using a Lock did not work for me either, and the application just froze up.
BeginInvoke worked, but I didn't like the effect of having UI controls being updated asynchronously.
I ended up starting the main process as a separate thread (System.Threading.Tasks.Task), which would start and instantly give me back control of the main thread. Afterwards, while waiting for several other tasks to end execution in a loop, I also ended up having to insert this line: System.Windows.Forms.Application.DoEvents() to enable the system to process all messages waiting in the queue. Now it works right for my application. There might be another way to skin this cat, but it works now.

How can I tell when a thread have finished when using a thread pool?

My thread:
public void main_news_thread(MainApplication main)
{
ThreadPool.QueueUserWorkItem(p => check_news(validrsslist, 0));
}
I call this thread every interval of time...
How can I know when the thread finishes so I can call two other methods which deal with the GUI? How can I refer to this threadpool thread?
Since you are talking about UI, you might want to look at BackgroundWorker, which offers a RunWorkerCompleted event that fires on the UI thread, and indicate success/failure/cancel etc.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker_events.aspx
Personally, though, I'd just run a callback method at the end of my worker code (remembering to switch back to the UI thread, via Dispatcher.Invoke in WPF or this.Invoke in winforms).
You can execute the methods in the thread itself (you have to take care of invoking yourself to access the gui thread):
ThreadPool.QueueUserWorkItem(p => {
check_news(validrsslist, 0);
//do something after the task is finished
});

How to check a thread is done, then fill progress bar in C# / WPF

I am just working on my first GUI application on Windows.
I have a WPF GUI to a small C# utility which copies files. When the button is clicked to copy, I obviously don't want the GUI to hang. So, I fire off a new thread to run the method which copies the files. I assume I'm on track so far and there's no "better" way of doing it in C#?
Now, I have a ProgressBar which I want to appear filled when the thread is done. (It's fine running as indeterminate for now). How do I check when the copying is done?
So, so far I have:
Thread t = new Thread(delegate()
{
po.Organise(inputPath, outputPath, recursive);
});
t.Start();
PBar.IsIndeterminate = true;
And I want something after that that works like:
if (t.Done)
{
PBar.Value = 100;
}
Have a look at the BackgroundWorker class. It supports events like RunWorkerCompleted or ProgressChanged.
Have a look here, too (this is about threading in general + backgroundworker, again).
As already stated, consider the use of the BackgroundWorker class. It was designed for these situations and exposes events suited for what you are trying to accomplish.
Use the ProgressChangedevent to report progress incrementally and the RunWorkerCompleted for when the task finishes. Check the MSDN page for code samples.
Wrap the if (t.Done) block in its own method. Invoke this method from the end of your worker thread.
Also, you might want to give the worker thread a name to make it easier to spot in the debugger.
You need a callback method. This should get you started. It uses an AsyncCallback, which is the best way to tackle this type of issue.
I just looked up an example I've been using for a project and stripped out the code specific to my app:
System.Windows.Forms.MethodInvoker mi = new System.Windows.Forms.MethodInvoker(delegate()
{
// Do your file copy here
});
AsyncCallback ascb = new AsyncCallback(delegate(IAsyncResult ar)
{
this.Dispatcher.Invoke(new ThreadStart(delegate (){
// set progressbar value to 100 here
}), null);
});
mi.BeginInvoke(ascb, null);
The quick and easy hack would be to just update the UI at the end of your anonymous method in your thread. Obviously you can't update it directly, but you can use Dispatcher.Invoke:
Thread t = new Thread(delegate()
{
po.Organise(inputPath, outputPath, recursive);
Dispatcher.Invoke(new Action(()=>{PBar.Value = 100;}),null);
});
t.Start();
As a general Windows programming principal, you have to make calls to update the UI from the UI thread (the one that is processing messages through a message pump).
In Windows Forms, the way that this was done was through the implementation of the ISynchronizeInvoke interface on the Control class, primarily through the implementation of the Invoke method.
With the release of .NET 2.0, it was realized that a better mechanism was needed to marshal calls into the correct context. That's where the SynchronizationContext comes in.
This class abstracts the interface you would use for marshaling calls to different contexts, allowing for specific implementations depending on the context.
So whether or not Windows Forms is the environment, or WPF, one call can be made in the same way across those contexts with the same effect (marshaling the call).
In your particular case, because you are using a closure (anonymous method), you can take advantage of the fact that a SynchronizationContext is available to you (through the static Current property) at the invocation site of the Thread to provide the mechanism to call back to the UI thread from your background thread:
// Get the synchronization context.
// This is in the UI thread.
SynchronizationContext sc = SynchronizationContext.Current;
// Create the thread, but use the SynchronizationContext
// in the closure to marshal the call back.
Thread t = new Thread(delegate()
{
// Do your work.
po.Organise(inputPath, outputPath, recursive);
// Call back using the SynchronizationContext.
// Can call the Post method if you don't care
// about waiting for the result.
sc.Send(delegate()
{
// Fill the progress bar.
PBar.Value = 100;
});
});
// Make the progress bar indeterminate.
PBar.IsIndeterminate = true;
// Start the thread.
t.Start();
Note, if you don't care about waiting for the result of the call back to the UI thread, you can make a call to the Post method instead, which will dispatch the call to the UI thread without waiting for that call to complete.

Categories