Displaying a custom dialog window during a long-running task - c#

Let's say I have a very simple ProgressBar with IsIndeterminate=true:
<Window x:Class="My.Controls.IndeterminateProgressDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="Window"
Width="300" Height="110" ResizeMode="NoResize" Topmost="True"
WindowStartupLocation="CenterScreen" WindowStyle="None">
<Grid>
<ProgressBar Width="200" Height="20" IsIndeterminate="True" />
</Grid>
</Window>
I want to show this dialog during a Task that may take a while. I don't care about progress (I can't determine it), I just want to inform the user that I do something that may take some seconds.
public void GetResult()
{
string result = DoWhileShowingDialogAsync().Result;
//...
}
private async Task<string> DoWhileShowingDialogAsync()
{
var pd = new IndeterminateProgressDialog();
pd.Show();
string ret = await Task.Run(() => DoSomethingComplex()));
pd.Close();
return ret;
}
However the UI just freezes infinitely and the Task seems to never return. The problem doesn't lie within DoSomethingComplex(), it completes without issues if I run it synchronously. I'm pretty sure it's because I misunderstood something with await/async, can someone point me in the right direction?

.Result
That's a classic UI thread deadlock. Use await. Use it all the way up the call tree.

Just for some clarification, 'use it all the way up the call tree' means you need to call it from the UI thread. Something like this:
private Task<string> DoWhileShowingDialogAsync()
{
return Task.Run(() => DoSomethingComplex());
}
private string DoSomethingComplex()
{
// wait a noticeable time
for (int i = 0; i != 1000000000; ++i)
; // do nothing, just wait
}
private async void GetResult()
{
pd.Show();
string result = await DoWhileShowingDialogAsync();
pd.Close();
}

Related

Can't understand how to use Progress(T) to update UI during async process

I have been googling this for quite a few hours, and read quite a few SO questions where this is discussed but I am sorry to say I just don't get how to use it.
Basically what I am trying to do is to have a label in a WPF/Win Forms app display the following while an async task is running:
Processing .
and at each 1 second interval to add another dot until I get to three and then start over at 1 until the task is done.
As a first step I am only trying to add a dot after each second and have tried it with an IProgress action but the only thing that I have been able to accomplish is either nothing or the label gets populated with dots in one shot and the other task seems to run after that is done.
I next tried doing the following:
private async void startButton_Click(object sender, RoutedEventArgs e)
{
resultsTextBox.Text = "Waiting for the response ...";
startButton.IsEnabled = false;
resultsTextBox.Clear();
var task = SumPageSizesAsync();
var progress = Task.Run(() =>
{
var aTimer = new System.Timers.Timer(1000);
aTimer.Elapsed += OnTimedEvent;
aTimer.AutoReset = true;
aTimer.Enabled = true;
void OnTimedEvent(object source, ElapsedEventArgs et)
{
if (!lblProgress.Dispatcher.CheckAccess())
{
Dispatcher.Invoke(() =>
{
lblProgress.Content += ".";
});
}
}
});
await task;
await progress;
resultsTextBox.Text += "\r\nControl returned to startButton_Click.";
startButton.IsEnabled = true;
}
But again the label just gets populated with dots at once while the other task keeps running.
I took this example from the Microsoft Docs
UPDATE:
I have now tried removing the loop while(!task.IsComplete) which basically makes the label start to be updated after the first task has finished. Then I tried to the following:
var task = SumPageSizesAsync();
var progress = GetProgress();
await Task.WhenAll(SumPageSizesAsync(), GetProgress());
But got the same result, the label begins to update after the first task has concluded.
Thank you for your help.
"Progress(T)" is the wrong pattern for this.
Here is the code for a WPF application that does this with 100% async / await code, no additional threads are created.
It starts two async tasks. The first simulates the long running async process. The second one starts another async Task that takes the first task as a parameter. It loops until the first task is completed, while updating a label with a "..." pattern. It awaits a Task.Delay to control the animation speed.
Both those tasks are placed in to a list, and the we await the completion of both of them.
This could all be wrapped up in in to a ShowProgressUntilTaskCompletes method (or extension method) that takes the worker Task as a parameter, which gives you an easily reusable method of showing a progress indicator for any Task.
MainWindow.xaml:
<Window
x:Class="LongProcessDemo.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"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<StackPanel Margin="100" Orientation="Vertical">
<Button Click="StartProcess_OnClick" Content="Start" />
<TextBlock
Name="LoadingText"
Padding="20"
Text="Not Running"
TextAlignment="Center" />
</StackPanel>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows;
namespace LongProcessDemo
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void StartProcess_OnClick(object sender, RoutedEventArgs e)
{
var longRunningTask = SimulateLongRunningTask();
var spinner = ShowSpinner(longRunningTask);
var tasks = new List<Task>
{
longRunningTask,
spinner,
};
await Task.WhenAll(tasks);
}
private async Task ShowSpinner(Task longRunningTask)
{
var numDots = 0;
while (!longRunningTask.IsCompleted)
{
if (numDots++ > 3) numDots = 0;
LoadingText.Text = $"Waiting{new string('.', numDots)}";
await Task.Delay(TimeSpan.FromSeconds(.5));
}
LoadingText.Text = "Done!";
}
private async Task SimulateLongRunningTask()
{
await Task.Delay(TimeSpan.FromSeconds(10));
}
}
}
Here is a recording of it running, with window interaction proving that the UI is not blocked.
As an extra bonus, I got bored and implemented the extension method I mentioned (with super special bonus, a "local function" feature from C# 7!).
public static class TaskExtensions
{
public static async Task WithSpinner(this Task longRunningTask, TextBlock spinnerTextBox)
{
async Task ShowSpinner()
{
var numDots = 0;
while (!longRunningTask.IsCompleted)
{
if (numDots++ > 3) numDots = 0;
spinnerTextBox.Text = $"Waiting{new string('.', numDots)}";
await Task.Delay(TimeSpan.FromSeconds(.5));
}
spinnerTextBox.Text = "Done!";
}
var spinner = ShowSpinner();
var tasks = new List<Task>
{
longRunningTask,
spinner,
};
await Task.WhenAll(tasks);
}
}
You use it like this:
await SimulateLongRunningTask().WithSpinner(LoadingTextBlock);
If you use the await, it means that your code will wait for the async operation to finish at that line, and then continue.
That is why your progress task is not started until task task is finished.
You can create a background thread that runs in parallel with the task until it is finished and in there you can tell the UI thread to animate the dots once per second. Since the UI thread is NOT blocked (but only waiting for the task to finish), this works.
Example code:
string originalLblContent = (lblProgress.Content as string) ?? "";
bool taskStarted = false;
var progressThread = new Thread((ThreadStart)delegate
{
// this code will run in the background thread
string dots = "";
while(!taskStarted || !task.IsCompleted) {
if(dots.Length < 3) {
dots += ".";
} else {
dots = "";
}
// because we are in the background thread, we need to invoke the UI thread
// we can invoke it because your task is running asynchronously and NOT blocking the UI thread
Dispatcher.Invoke(() =>
{
lblProgress.Content = originalLblContent + dots;
});
Thread.Sleep(1000);
}
});
progressThread.Start();
taskStarted = true;
await task;
// the task is now finished, and the progressThread will also be after 1 second ...
Your approach is a little funky here. The await statements will prevent the method returning until each thread is finished. The await feature is not a completely asynchronous execution (why would it be? you have threads for that).
You need to re-think your approach to the problem. Fundamentally, you want to update the UI while another process is in progress. This calls for multithreading.
From Microsoft:
"Handling blocking operations in a graphical application can be difficult. We don’t want to call blocking methods from event handlers because the application will appear to freeze up. We can use a separate thread to handle these operations, but when we’re done, we have to synchronize with the UI thread because we can’t directly modify the GUI from our worker thread. We can use Invoke or BeginInvoke to insert delegates into the Dispatcher of the UI thread. Eventually, these delegates will be executed with permission to modify UI elements.
In this example, we mimic a remote procedure call that retrieves a weather forecast. We use a separate worker thread to execute this call, and we schedule an update method in the Dispatcher of the UI thread when we’re finished."
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/threading-model

Using ReactiveUI, Observables, SubscribeOn, and ObserveOn to display an output log in UI during a long-running process

I have a WPF application that will launch a long-running task (60+ seconds) that uses a System.Reactive.Subject<string> to push status messages periodically. The idea was that I could then Subscribe to the observable from my ViewModel and have ReactiveUI automatically update my UI through a Data Binding. This all works fine except that the TextBox is not updating in real-time. It only updates after long-running task has completed. I presume this is because my UI thread is being blocked and cannot update.
Working under that assumption, my research suggested that I could put the subscription on a background thread using SubscribeOn and then push the notifications back to the UI thread using ObserveOnDispatcher. However, this still did not produce the results that I wanted -- the UI only updated after long-running task had returned.
Can anybody give me some insight on what I need to do to allow my Output log to update in real time? Below are the related pieces of code.
XAML:
<TextBox Grid.Row="1" Text="{Binding Output}" IsReadOnly="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Margin="10,0,10,10" x:Name="OutputTextBox" />
Code-Behind:
protected override void OnContentRendered(EventArgs e)
{
if (Converter == null) return;
_viewModel = new ConversionOutputWindowViewModel(Converter);
DataContext = _viewModel;
_viewModel.StartConversion(); // Long-running Task
//_viewModel.StartSave();
FinishButton.IsEnabled = true;
}
ViewModel:
private string _output;
public string Output // Data bound in XAML
{
get { return _output; }
set { this.RaiseAndSetIfChanged(ref _output, value); }
}
public void StartConversion()
{
_edmxConverter.Convert(); // Long-running Task
}
public ConversionOutputWindowViewModel(Utilities.Converters.EdmxConverter converter)
{
_edmxConverter = converter;
_compositeDisposable.Add(_edmxConverter.Output
.SubscribeOn(NewThreadScheduler.Default)
.ObserveOnDispatcher()
.Subscribe(s => Output = Output += s));
//_compositeDisposable.Add(_edmxConverter.Output.Subscribe(s => Output = Output += s));
}
Long-Running Task Function:
public Subject<string> Output { get; }
Output = new Subject<string>(); //In ctor
private void PrintReplacement(XAttribute attribute, string oldValue, string newValue, int level, Verbosity minVerbosity = Verbosity.Informational)
{
if (Verbosity < minVerbosity) return;
Output.OnNext($"{new string('\t', level)}{attribute.Name}: {oldValue} -> {newValue}{Environment.NewLine}");
}
Would it maybe help to wrap my Long-running Task function call inside an await Task.Run? I'm grasping at straws here. I don't have a very good working knowledge of .NET threading.
Well you are using subjects, so .SubscribeOn(NewThreadScheduler.Default) does nothing. (Standard old drum beating) Don't use subjects.
Your long running process should be a method call that returns an IObservable<T> (instead of having a class that exposes a property). The T should be the status updates you want to receive. When the task is done, then you OnComplete. If the task fails, you OnError.
Ideally the method that returns the IObservable using Observable.Create to deifne the work that will need to be done.
public IObservable<string> Convert()
{
return Observable.Create<string>(observer=>
{
//do stuff here.
//Call observer.OnNext with status messages
//When done call observer.OnCompleted()
});
}
As you dont show what your long running task is I cant help anymore with the implementation.

Why does this causes the application to hang [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
The code below is causing my WPF application to get hung (likely dead-locks). I have verified that DownloadStringAsTask method is executed on a separate (non-UI) thread. Interestingly if you uncomment the messagebox line (just before call to while (tasks.Any()), application works fine. Can anyone explain why do application hungs at first place and also how to resolve this issue?
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="9*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Frame x:Name="frame" Grid.Row="0" />
<StatusBar VerticalAlignment="Bottom" Grid.Row="1" >
<StatusBarItem>
<TextBlock Name="tbStatusBar" Text="Waiting for getting update" />
</StatusBarItem>
</StatusBar>
</Grid>
</Window>
public partial class MainWindow : Window
{
List<string> URLsToProcess = new List<string>
{
"http://www.microsoft.com",
"http://www.stackoverflow.com",
"http://www.google.com",
"http://www.apple.com",
"http://www.ebay.com",
"http://www.oracle.com",
"http://www.gmail.com",
"http://www.amazon.com",
"http://www.outlook.com",
"http://www.yahoo.com",
"http://www.amazon124.com",
"http://www.msn.com"
};
public MainWindow()
{
InitializeComponent();
ProcessURLs();
}
public void ProcessURLs()
{
var tasks = URLsToProcess.AsParallel().Select(uri => DownloadStringAsTask(new Uri(uri))).ToArray();
//MessageBox.Show("this is doing some magic");
while (tasks.Any())
{
try
{
int index = Task.WaitAny(tasks);
this.tbStatusBar.Text = string.Format("{0} has completed", tasks[index].AsyncState.ToString());
tasks = tasks.Where(t => t != tasks[index]).ToArray();
}
catch (Exception e)
{
foreach (var t in tasks.Where(t => t.Status == TaskStatus.Faulted))
this.tbStatusBar.Text = string.Format("{0} has completed", t.AsyncState.ToString());
tasks = tasks.Where(t => t.Status != TaskStatus.Faulted).ToArray();
}
}
}
private Task<string> DownloadStringAsTask(Uri address)
{
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>(address);
WebClient client = new WebClient();
client.DownloadStringCompleted += (sender, args) =>
{
if (args.Error != null)
tcs.SetException(args.Error);
else if (args.Cancelled)
tcs.SetCanceled();
else
tcs.SetResult(args.Result);
};
client.DownloadStringAsync(address);
return tcs.Task;
}
}
The biggest problem here is that your constructor does not return until all of the tasks have completed. Until the constructor returns, the window will not be shown, because the window messages related to drawing the window aren't going to be processed.
Note that you don't really have "deadlock" here per se. Instead, if you waited long enough (i.e. until all the tasks have completed), the window would actually be shown.
When you add the call to MessageBox.Show(), you give the UI thread a chance to process the window message queue. That is, the normal modal dialog includes a thread message pump which winds up handling those messages in the queue, including those related to showing your window. Note that even if you add the MessageBox.Show(), that won't result in the window being updated as your processing progresses. It just allows the window to be shown before you block the UI thread again.
One way to address this is to switch to the async/await pattern. For example:
public MainWindow()
{
InitializeComponent();
var _ = ProcessURLs();
}
public async Task ProcessURLs()
{
List<Task<string>> tasks = URLsToProcess.Select(uri => DownloadStringAsTask(new Uri(uri))).ToList();
while (tasks.Count > 0)
{
Task<string> task = await Task.WhenAny(tasks);
string messageText;
if (task.Status == TaskStatus.RanToCompletion)
{
messageText = string.Format("{0} has completed", task.AsyncState);
// TODO: do something with task.Result, i.e. the actual downloaded text
}
else
{
messageText = string.Format("{0} has completed with failure: {1}", task.AsyncState, task.Status);
}
this.tbStatusBar.Text = messageText;
tasks.Remove(task);
}
tbStatusBar.Text = "All tasks completed";
}
I've rewritten the ProcessURLs() method as an async method. This means that when the constructor calls it, it will run synchronously up to the first await statement, at which point it will yield and allow the current thread to continue normally.
When the call to Task.WhenAny() completes (i.e. any of the tasks complete), the runtime will resume execution of the ProcessURLs() method by invoking the continuation on the UI thread. This allows the method to access the UI objects (e.g. this.tbStatusBar.Text) normally, while occupying the UI thread only long enough to process the completion.
When the loop returns to the top and the Task.WhenAny() method is called again, the whole sequence is repeated (i.e. just the way a loop is supposed to work :) ).
Some other notes:
The var _ = bit in the constructor is there to suppress the compiler warning that would otherwise occur when the Task return value is ignored.
IMHO, it would be better to not initialize these operations in the constructor. The constructor is just generally a bad place to be doing significant work like this. Instead, I would (for example) override the OnActivated() method, making it async so you can use the await statement with the call to ProcessURLs() (i.e. a more idiomatic way to call an async method). This ensures the window is completely initialized and shown before you start doing any other processing.
In this particular example, starting the processing in the constructor is probably not really going to hurt anything, as long as you're using async/await, since the UI-related stuff isn't going to be able to be executed in any case until at least the constructor has returned. I just try to avoid doing this sort of thing in the constructor as a general rule.
I also modified the general handling of your task collection, to something that I feel is somewhat more suitable. It gets rid of the repeated reinitialization of the tasks collection, as well as takes advantage of the semantics of the WhenAny() method. I also removed the AsParallel(); given that the long-running part of the processing is handled asynchronously already, there did not seem to be any advantage in the attempt to parallelize the Select() itself.
The likely cause for the hang is that you are mixing sync and asnyc code and calling WaitAny. Stephen Cleary has post that is useful in understanding common issues with Tasks.
Best Practices in Asynchronous Programming
Here is a solution that simplifies your code and uses Parallel.ForEach
Code
public partial class WaitAnyWindow : Window {
private List<string> URLsToProcess = new List<string>
{
"http://www.microsoft.com",
"http://www.stackoverflow.com",
"http://www.google.com",
"http://www.apple.com",
"http://www.ebay.com",
"http://www.oracle.com",
"http://www.gmail.com",
"http://www.amazon.com",
"http://www.outlook.com",
"http://www.yahoo.com",
"http://www.amazon.com",
"http://www.msn.com"
};
public WaitAnyWindow02() {
InitializeComponent();
Parallel.ForEach(URLsToProcess, (x) => DownloadStringFromWebsite(x));
}
private bool DownloadStringFromWebsite(string website) {
WebClient client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
if (e.Error != null)
{
Dispatcher.BeginInvoke((Action)(() =>
{
this.tbStatusBar.Text = string.Format("{0} didn't complete because {1}", website, e.Error.Message);
}));
}
else
{
Dispatcher.BeginInvoke((Action)(() =>
{
this.tbStatusBar.Text = string.Format("{0} has completed", website);
}));
}
};
client.DownloadStringAsync(new Uri(website));
return true;
}
}

WPF, How do I force a textbox to update

I'm playing around with WPF. I am limited to the .Net framework 3.5. I want to update a text box with simple status text while I run some long method. No matter what I try, I cannot seem to get the text box to update until the long method has completed. I have tried threading / using the controls dispatcher etc. In the example below, I have reverted back to simply hiving off the long method to a thread but it still wont work. The TextStatus textbox never gets updated until after the long method (LoadDevices) has completed. Can someone tell me how to do this? Any help much appreciated.
private void UpdateButton_Click(object sender, RoutedEventArgs e)
{
UpdateStatus("Searching for devices, please wait . . .");
var t = new Thread(LoadDevices);
t.Start();
}
private void UpdateStatus(string status)
{
TextStatus.AppendText(status);
TextStatus.InvalidateVisual();
}
I think you are not providing enough code to figure out the problem. Still, fact is that your UI is blocked.
Try the following, maybe it helps you figure it out (not using Task since it's not available in .NET Framework 3.5). It tries to simulate your long running LoadDevices() method while keeping the UI responsive.
MainWindows.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="120"
Width="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition />
</Grid.RowDefinitions>
<Button Click="UpdateButtonClick" Grid.Row="0">Update</Button>
<TextBox Name="TextStatus" Text="" TextWrapping="Wrap" Grid.Row="1"></TextBox>
</Grid>
</Window>
MainWindows.xaml.cs
using System;
using System.Threading;
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void UpdateButtonClick(object sender, RoutedEventArgs e)
{
UpdateStatus("Searching for devices, please wait");
var thread = new Thread(LoadDevices);
thread.Start();
}
private void LoadDevices()
{
// Your long running "load devices" implementation goes here
for (int i = 0; i < 15; i++)
{
Dispatcher.BeginInvoke((Action) (() => UpdateStatus(".")));
Thread.Sleep(250);
}
Dispatcher.BeginInvoke((Action)(() => UpdateStatus(" done")));
}
private void UpdateStatus(string status)
{
TextStatus.AppendText(status);
}
}
}
But yeah, you should prefer MVVM, Data binding, Commands, etc. and try to avoid stuffing logic into codebehind.
If you haven't tried delegates, that may be what you are looking for although it seems you may of tried this already. Inside your LoadDevices thread method, you could delegate back to invoke UpdateStatus with whatever text you want while your long method is running.
The other case I see with the wording of your question is something local to the method Update-status is trying to change the text by a call to it. However, it cannot for some reason.
This may be compleatly irrelevant to WPF, but in Forms:
I'm assuming you have your loading thread somewhere else. I don't see you calling a doWork() or equivalent method in the thread though. If you want to update the status as your loading thread loads devices you could do:
private delegate void UpdateStatusDel(string text); //This at your declarations
UpdateStatusHandler = new UpdateStatusDel(UpdateStatus); //To initialize the delegate to / //point to your update textbox function
//say you have
string updateText = "Loading 10% done";
//Then, in your thread you could invoke
[locationOfHandeler].Invoke(UpdateStatusHandler, new object[] { updateText });
Try using the Task library. You will need to download this for .NET 3.5 : http://www.microsoft.com/en-us/download/details.aspx?id=24940
Task task = new Task(new Action(LoadDevices));
task.Start();
There are several ways to do this:
http://dotnetcodr.com/2014/01/01/5-ways-to-start-a-task-in-net-c/

BackgroundWorker and Asynchrony comparison

We can achieve the responsive UI using the BackgroundWorker. Here is the example.
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Thread test = new Thread(new ThreadStart(TestThread));
test.Start();
}
private void TestThread()
{
for (int i = 0; i <= 1000000000; i++)
{
Thread.Sleep(1000);
Dispatcher.Invoke(
new UpdateTextCallback(this.UpdateText),
new object[] { i.ToString() }
);
}
}
private void UpdateText(string message)
{
Tests.Add(message);
}
public delegate void UpdateTextCallback(string message);
private ObservableCollection<string> tests = new ObservableCollection<string>();
public ObservableCollection<string> Tests
{
get { return tests; }
set { tests = value; }
}
UI:
<StackPanel>
<Button Content="Start Animation" Click="Button_Click" />
<Button Content="Start work" Click="Button_Click_1" />
<Rectangle Name="rec1" Fill="Red" Height="50" Width="50"/>
<ListView ItemsSource="{Binding Tests}" ScrollViewer.CanContentScroll="True" />
</StackPanel>
Here i can start the animation and at the same time i can update the UI using the BackGroundWorker and Dispatcher.
The same thing i can achieve through asynchrony like this:
private async void GetTests(ObservableCollection<string> items)
{
for (int i = 0; i < 20; i++)
{
var s = await GetTestAsync(i);
items.Add(s);
}
}
async Task<string> GetTestAsync(int i)
{
await Task.Delay(2000);
return i.ToString() + " Call - " + System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
}
Q.1 is there any advantage of using Asynchrony over BackgroundWorker?
And what are the scenarios where i should decide to use any one of them and should avoid using the other.
Q.2 I want to understand the use of Async - Await in terms of WPF. Like what we can't do without it and now we can do it easily with it.
Please guide.
Q.1 is there any advantage of using Asynchrony over BackgroundWorker?
Sure - primarily, the code is much, much simpler. In this particular case you aren't doing anything complicated, but as soon as you start coordinating multiple tasks, having more complex control flow (loops etc), wanting to handle errors etc, it makes an enormous difference.
Additionally, in this case, it saves an extra thread - in your second call, everything is happening on the UI thread. In more realistic examples, you'd be likely to be waiting for web service calls etc, which definitely don't need to be tying up extra threads.
Q.2 I want to understand the use of Async - Await in terms of WPF. Like what we can't do without it and now we can do it easily with it.
In theory, everything you can do with async you could do before without it. In practice, the amount of boiler plate an incidental complexity in writing asynchronous code correctly and efficiently was an enormous barrier.
The async/await feature lets you write asynchronous code which looks like synchronous code, with familiar control flow etc. It means we can understand it, reason about it, and only worry about the inherent complexity that the asynchrony brings, instead of all the incidental complexity of writing callbacks etc.

Categories

Resources