fbpx

update UI in Task?

More
10 months 2 days ago #1 by Stefan Hirsch
update UI in Task? was created by Stefan Hirsch
Hi all,

source is following code:
SELF:obtnInstallService:Enabled := FALSE
AWAIT Task.Run(Action{{ => 
   VAR helper := WindowsServiceHelper{}
   helper:InstallService()
   SELF:CheckButtons()
}})

In another thread there was a suggestion to move CheckButtons (update of UI, with checking InvokeRequired) after AWAIT because 'It's generally better to avoid updating the UI thread from inside a task.' (by Nick).
My questions:
1. Why (is better to avoid...)?
2. How should progressbar update be done in long running task?

Regards,
Stefan

Please Log in or Create an account to join the conversation.

More
10 months 2 days ago #2 by Nick Friend
Replied by Nick Friend on topic update UI in Task?
Hi Stefan,

As to why, I'm sure Robert or Chris can give a better answer than me, but I think the basic idea is that when you start a task it runs on a separate thread from the UI. If you then carry out processes that directly affect the UI, then you're literally crossing your threads!... anyway you get the idea ;)

To update the UI thread, you need to use a TaskScheduler. In pseudo code (C# as I'm not reliable in X#)
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
await Task.Factory.StartNew(()=> { MyMethod(uiScheduler, otherparams...); });

private void MyMethod(TaskScheduler uiScheduler, otherparams...)
{
    do stuff....

    // update the UI
    Task.Factory.StartNew(()=>
    {
       // from here you can now safely access any methods or properties affecting the ui
    }, CancellationToken.None, TaskCreationOptions.None, uiScheduler);

    continuing doing more stuff
}

HTH

Nick

Please Log in or Create an account to join the conversation.

More
10 months 2 days ago #3 by Dick
Replied by Dick on topic update UI in Task?
I would also like to add the so called non recommended way to do this. Not sure why it's not recommended, usually that it not explained, as it works fine. Nick's method certainly works 'by the book' but you need to 'await' all your methods to use it.

Dick

this.UpdateProgressBar(1);
ExtensionMethods.ProcessUITasks();

public static void ProcessUITasks()
// When called, forces the UI to redraw.
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(delegate (object parameter) {
frame.Continue = false;
return null;
}), null);
Dispatcher.PushFrame(frame);
}

Please Log in or Create an account to join the conversation.

More
10 months 1 day ago #4 by Wolfgang Riedmann
Replied by Wolfgang Riedmann on topic update UI in Task?
Hello,

AFAIK there is BackgroundWorker class ( https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx ) for operations on a separate thread, usable for WPF applications.

It can be used as follows:
_oWorker := BackgroundWorker{}
_oWorker:WorkerReportsProgress := true
_oWorker:WorkerSupportsCancellation := true
_oWorker:DoWork += ExecuteProcessAsync
_oWorker:ProgressChanged += ProgressProcessAsync
_oWorker:RunWorkerCompleted += CompletedProcessAsync
_oWorker:RunWorkerAsync()

method ProgressProcessAsync( oSender as object, e as ProgressChangedEventArgs ) as void
	
_oProgress:Text	:= ( string ) e:UserState
	
return   

method CompletedProcessAsync( oSender as object, e as RunWorkerCompletedEventArgs ) as void	

_oProgress:Text	:= ( string ) e:UserState
_oWorker := null                            
	
return  

method ExecuteProcessAsync( oSender as object, e as DoWorkEventArgs ) as void
local oProcess as AsyncProcess
	
oProcess := AsyncProcess{ _oWorker }
oProcess:Process()
	
return

I have also done a sample in X#/WPF - I've attached a XIDE export file of a complete sample of it.
Or you can look here:

https://www.dotnetperls.com/backgroundworker

Wolfgang
Attachments:

Please Log in or Create an account to join the conversation.

More
10 months 1 day ago #5 by Nick Friend
Replied by Nick Friend on topic update UI in Task?
Hi Dick,

The code you posted is a way of forcing the UI to update when you've blocked it by some long-running process, it has nothing to do with async programming or await. The whole point of asynchronous programming is to avoid blocking the UI in the first place. This is what task-based async is all about.

I've used all three proposed methods - in fact I think I gave you that ProcessUITasks code way back in the Vulcan ng days, before I knew better ;-)- and I can categorically state that task based is the way to go for async. It results in very clear code, which is very important if you apply async programming large scale, and it works 100%.

BackgroundWorker as illustrated by Wolfgang will work, but it results in much more convoluted code (though I'm sure Wolfgang will disagree!).

Nick

Please Log in or Create an account to join the conversation.

More
10 months 1 day ago #6 by Juraj Halás
Replied by Juraj Halás on topic update UI in Task?
Hi Wolfgang,

My English is not very good but I will try to formulate my question.
I want to ask what is the best solution.
The client runs an app and works in it. While running an app, I need to track the partition of the database where a new table appears. If it appears, add it to another table and it will be deleted. This will happen several times during app launch.
The question is what to use - bacgroudworker in the application or write another program as a system service?

Juraj

Please Log in or Create an account to join the conversation.

More
10 months 1 day ago #7 by Stefan Hirsch
Replied by Stefan Hirsch on topic update UI in Task?
Hi all,

in the current project I'm using Windows.Forms. So complete call looks like this:
PRIVATE METHOD CheckButtons() AS VOID
    IF SELF:InvokeRequired == TRUE
        SELF:BeginInvoke(Action{CheckButtons})
        RETURN
    ENDIF
    //savely executed UI Code
RETURN 
So it doesn't matter from which task or thread the method is called it's always executed savely.

In WPF I have following code that is called from tasks or threads:
void runCopyFileEvent(CopyInfo cpi)
{
   this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal,
         new UpdateProgressBarDelegate(UpdateProgressBar), cpi);
}

This way I do not have to implement UI update handling in every task or thread. Just call the method inside the task and everything else is handled in UI class. OK, the method is not called directly from threads, here I use delegates. Advantage in my opinion is that the code of the thread is independable of UI framework.

Any drawbacks?

Regards,
Stefan

Please Log in or Create an account to join the conversation.

More
10 months 1 day ago #8 by Wolfgang Riedmann
Replied by Wolfgang Riedmann on topic update UI in Task?
Hi Juraj,

I would do that definitely in a separate Windows service. It is a separate work that has nothing to do with the currently running application.

If you need a sample for a Windows service, I can give you one.

Wolfgang

Please Log in or Create an account to join the conversation.

More
10 months 1 day ago #9 by Dick
Replied by Dick on topic update UI in Task?
Hello Nick,

The whole point of asynchronous programming is to avoid blocking the UI in the first place. This is what task-based async is all about.

I've used all three proposed methods - in fact I think I gave you that ProcessUITasks code way back in the Vulcan ng days, before I knew better ;-)- and I can categorically state that task based is the way to go for async. It results in very clear code, which is very important if you apply async programming large scale, and it works 100%.


I agree with you and as I wrote, the code you gave here (and earlier to me) works. But the program needs to be async all over for it to work. I've applied the code I gave in a program which was not async and that code also works 100%.

I do not consider it less readable, actually on the contrary: I just add one line of code after the update of the progress bar and it remains visible. Like with the VO ApplcationExecWhileEvent() which worked even better because you only had to issue it once.

I must add that I consider it pretty poor that in .Net there is something like a progress bar but when applied it simply doesn't work. Until you transform your program to a fully separated set of tasks, or have it followed by the "ProcessUITasks" task method. If .Net was well designed a programmer shouldn't have to worry about how it works, as long as it works 'out of the box'. I always thought that was the whole idea of .Net but the more I work with it the more I methods and namespaces I see which do not work without a lot of extra research and programming.

Dick

Please Log in or Create an account to join the conversation.

More
10 months 1 day ago #10 by Nick Friend
Replied by Nick Friend on topic update UI in Task?

Dick wrote: I do not consider it less readable

Hi Dick,

Re. the readability, I was referring to BackgroundWorker which is a valid alternative for async programming.

Anyway, I was giving an opinion over the general approach to async and Stefan obviously has different requirements, and an approach which I'm not qualified to comment on.

Nick

Please Log in or Create an account to join the conversation.

More
10 months 1 day ago #11 by Juraj Halás
Replied by Juraj Halás on topic update UI in Task?
Hi Wolfgang,

Thank you for your response. Any service sample would help me. My mail - "This email address is being protected from spambots. You need JavaScript enabled to view it."

Juraj

Please Log in or Create an account to join the conversation.

More
10 months 1 day ago #12 by Wolfgang Riedmann
Replied by Wolfgang Riedmann on topic update UI in Task?
Hi Juraj,

you can find a sample here:

https://www.riedmann.it/download/VulcanService.viaef

It is a XIDE export file.

Wolfgang

Please Log in or Create an account to join the conversation.