visual studio drawing adornment with lazy update - c#

I'm making an Visual Studio adornment extension. I want to update adornments if there is no user input at least 2 seconds. So i constructed a worker and tried to remove and add adornment but VS says it can't be updated because non-ui thread had called it. So I waited without thread then my editor goes really laggy (because the ui thread waits)
I want to know if there is a way to update adornments with lazy update.
Drawing adornment is done by calling AddAdornment(), and i can't find how to invoke ui thread to draw.
Below is my code
internal async void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
{
Print("OnLayoutChanged Called");
task = Task.Factory.StartNew(() =>
{
Print("task Started");
if (e.NewSnapshot != e.OldSnapshot)
{
parseStopwatch.Restart();
shouldParse = true;
}
ParseWork(e);
});
await task;
}
private async void ParseWork(object param)
{
var e = (TextViewLayoutChangedEventArgs)param;
if (e == null)
{
shouldParse = false;
parseStopwatch.Stop();
CsharpRegionParser.ParseCs(this.view.TextSnapshot);
DrawRegionBox();
return;
}
while (shouldParse)
{
Task.Delay(10);
if ((shouldParse && parseStopwatch.ElapsedMilliseconds > 2000) || parseStopwatch.ElapsedMilliseconds > 5000)
{
break;
}
}
shouldParse = false;
parseStopwatch.Stop();
CsharpRegionParser.ParseCs(this.view.TextSnapshot);
DrawRequest(e);
return;
}

I'm not sure why you were down-voted, particularly because this is an interesting problem when dealing with extensions.
So, to your first problem: Visual Studio has the same requirements as WPF (with some added complications due to its COM dependency). You can't update a UI element when you're not on the Main (UI) thread. Unfortunately, if you dive right in and approach it using the strategies you'd use for WPF, you'll experience a whole other world of problems (deadlocks, mostly).
First things first, brush up on how to handle switching from background to UI threads in Visual Studio extension land. I found Asynchronous and Multithreaded programming within VS using JoinableTaskFactory to be helpful in explaining.
I had to do something similar with an expensive parsing operation. It was pretty straight forward.
My parser executes as part of an IViewModelTagger instance and uses the following sequence (roughly):
It subscribes to the ITextBuffer.ChangedLowPriority event with an async void event handler.
Immediately on fire, it cancels any parsing operation in progress via a CancellationToken.Cancel() call. The cancellation token is passed into everything that supports it (in Roslyn, it's supported everywhere you would want it to be).
It begins the parsing operation, but before starting it, I have a Task.Delay(200, m_cancellationToken) call. I 200ms based on my typing speed and the fact that Roslyn's operations have CancellationToken overloads for anything expensive (my parsing work is pretty light-weight, too). YMMV.
I work with WPF components that require the UI thread quite a bit and they're intermingled within the IViewModelTagger and the IWpfTextViewListener. They're lightweight enough that I could have skipped async'ing them, but on very large classes they can hang the UI.
To handle this, I did the following:
On the TextViewLayoutChanged, I subscribe with an async void event handler.
I Task.Run() the expensive operations first, preventing the UI from being blocked.
When I do the final creation of the WPF UI elements and add them as adornments finalization (along with a couple of operations within the SDK that require it), I await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync() to get the UI thread.
I mentioned "other SDK operations", that's important. There are several things you cannot do within the SDK on anything but the Main thread (memory is failing me now, but parts of the TextView in particular will fail, and not consistently, if they're accessed on background threads).
There are more options for executing the work off of the UI thread (Ordinary Task.Run works, as well as ThreadHelper.JoinableTaskFactory.Run). The Andrew Arnott post linked earlier in my answer explains all of the choices. You'll want to understand that fully since there are reasons to use some over others depending on the task.
Hope that helps!

Task.Delay as used in your code returns a task that completes when you delay. If you call it like that and ignore the result, it didn't do what you thought it did. What you probably meant to is instead of calling Task.Factory.StartNew as you did, you want:
var cancellationTokenSource = new CancellationTokenSource();
Task.Delay(2000, cancellationTokenSource.Token).ContinueWith(() => DoWork(), cancellationTokenSource.Token, TaskScheduler.Current).
This says effectively "kick off a timer that'll wait 2 seconds, and then once it completes run the DoWork method on the UI thread. If more typing happens, then you can call cancellationTokenSource.Cancel() and just run again.
Also, I do have to ask about your type "CSharpRegionParser". If you need region information and you're on Visual Studio 2015, then you can get the syntax tree from Roslyn and you should be watching workspace change events rather than hooking LayoutChanged. You're also best off then structuring your system as a tagger/adornment manager pair as it might be clearer to write...it's not clear to me why you'd do parsing logic in LayoutChanged since LayoutChanged is something that happens during visual layout, including scrolling, resizing, etc.

Related

How to block a method while an asyncronous method is running without causing deadlocks in the UI thread

I have several async methods that need to synchronize back to the main ui thread.
async Task MyAsyncMethod() {
await DoSomeThingAsync().ConfigureAwait(true);
DoSomethingInTheGui();
}
now i need to call them from a syncronous event handler that is triggered from the gui thread, and the event handler cannot complete until the async method is done. so MyAsyncMethod().Wait() is not an option, neither is some kind of fire-and-forget solution.
This approach using Nito.AsyncEx seemed promising, but it still deadlocks: https://stackoverflow.com/a/9343733/249456
The only solution i've found seems like a hack to me:
public void RunInGui(Func<Task> action)
{
var window = new Window();
window.Loaded += (sender, args) => action()
.ContinueWith(p => {
window.Dispatcher.Invoke(() =>
{
window.Close();
});
});
window.ShowDialog();
}
Is there a way to get the same effect (block the calling method, allow syncronization back to the gui thread) without creating a new window?
Note: I am aware that refactoring would probably be the best option, but that is a massive undertaking we have to do over longer time. Also worth mentioning that this is a plugin for Autodesk Inventor. The api has several quirks, and all API calls (even non-ui related) have to be executed from the main/ui thread.
Also worth mentioning is that we keep a reference to the main threads dispatcher and use MainThreadDispatcher.InvokeAsync(() => ... ) all around the codebase.
The only solution i've found seems like a hack to me
All sync-over-async solutions are hacks. I enumerate the most common ones in my article on brownfield async. It's important to note that no solution exists for arbitrary code. Every solution either deadlocks or throws in some situation.
One of the easier hacks is to block on a thread pool thread:
Task.Run(() => action()).Wait();
However, if your action() requires a UI context, then that won't work.
The next step is to attempt using a single-threaded context. This is the approach taken by my AsyncContext type:
AsyncContext.Run(() => action());
This would deadlock if action is waiting for the UI thread's message queue to be pumped. Since this deadlocks but Window works, this appears to be the case.
Dropping further down a level, you could use nested pumping. Please note that nested pumping opens up a whole world of hurt due to unexpected reentrancy. There's some code on GitHub that shows how to do nested pumping on WPF. However, I highly recommend that you refactor your code rather than embrace reentrancy.

How would I use Background Worker to get my GUI to respond?

I made a short program which has just a button. When the button is pressed, functionA is executed, which also uses functionB and functionC. Inside functionA is a loop which executes functionB and functionC X amount of times. At the end of each loop, the progressbar gets incremented by 1. At the beginning of functionA, before the loop, there's a webservice which pulls data from a website, and passes that onto B and C for processing (data file manipulation and saving to disk).
My problem is that everything works fine, but while functionA is still running, the GUI is stuck, so I can't close/minimize/drag the window around, I have to wait until A is done. I researched and they say I should use BackgroundWorker, but as being a new programmer, I've no idea on how to use it. Can someone give me a simple way to use it?
The progressbar loads fine, but it's just that while the function is running, the whole window is frozen, and I want it so I can move the window around, etc while the program is running, instead of waiting until the function is complete.
Thank you!
Call your function asynchronously like the following and it will not freeze the UI.
private async void BeginProcessingAsync(Data d)
{
//Execute the long running task asynchronously
await Task.Run(() => functionA(d));
//Anything after the await line will be executed only after the task is finished.
anotherFunction(d); // if you have one..
}
To run your task, simply call BeginProcessingAsync(d);. Also, please note: If you're using newer versions of .NET, you might have to use await Task.Factory.StartNew(() => functionA(d)); instead of the above
Overall, you'll want to make sure your GUI doesn't get updated from another thread. Instead, the messages should go to a threadsafe location. For instance, you could have the thread building into something like a database and have the GUI using a timer to look for updated data flags.
There is a question with a lot more detail using delegates here.
Marc's answer was the simplest and best, in my opinion:
///...blah blah updating files
string newText = "abc"; // running on worker thread
this.Invoke((MethodInvoker)delegate {
someLabel.Text = newText; // runs on UI thread
});
///...blah blah more updating files
From Dotnet Perls:
A Background Worker makes threads easy to implement in Windows
Forms. Intensive tasks need to be done on another thread so the UI
does not freeze. It is necessary to post messages and update the user
interface when the task is done.
Also, from MSDN, look at Task-based Asynchronous Pattern (TAP) if you're using C# 5.
The Task-based Asynchronous Pattern (TAP) is based on the
System.Threading.Tasks.Task and System.Threading.Tasks.Task
types in the System.Threading.Tasks namespace, which are used to
represent arbitrary asynchronous operations. TAP is the recommended
asynchronous design pattern for new development.

Why Does My Asynchronous Code Run Synchronously When Debugging?

I am trying to implement a method called ReadAllLinesAsync using the async feature. I have produced the following code:
private static async Task<IEnumerable<string>> FileReadAllLinesAsync(string path)
{
using (var reader = new StreamReader(path))
{
while ((await reader.ReadLineAsync()) != null)
{
}
}
return null;
}
private static void Main()
{
Button buttonLoad = new Button { Text = "Load File" };
buttonLoad.Click += async delegate
{
await FileReadAllLinesAsync("test.txt"); //100mb file!
MessageBox.Show("Complete!");
};
Form mainForm = new Form();
mainForm.Controls.Add(buttonLoad);
Application.Run(mainForm);
}
I expect the listed code to run asynchronously and as a matter of fact, it does! But only when I run the code without the Visual Studio Debugger.
When I run the code with the Visual Studio Debugger attached, the code runs synchronously, blocking the main thread causing the UI to hang.
I have attempted and succeeded to reproduce the problem on three machines. Each test was conducted on a 64bit machine (either Windows 8 or Windows 7) using Visual Studio 2012.
I would like to know why this problem is occuring and how to solve it (as running without the debugger will likely hinder development).
The problem is that you are calling await reader.ReadLineAsync() in a tight loop that does nothing - except return execution to the UI thread after each await before starting all over again. Your UI thread is free to process windows events ONLY while ReadLineAsync() tries to read a line.
To fix this, you can change the call to await reader.ReadLineAsync().ConfigureAwait(false).
await waits for the completion of an asynchronous call and returns execution to the Syncrhonization context that called await in the first place. In a desktop application, this is the UI thread. This is a good thing because it allows you to update the UI directly but can cause blocking if you process the results of the asynchronous call right after the await.
You can change this behavior by specifying ConfigureAwait(false) in which case execution continues in a different thread, not the original Synchronization context.
Your original code would block even if it wasn't just a tight loop, as any code in the loop that processed the data would still execute in the UI thread. To process the data asynchronously without adding ConfigureAwait, you should process the data in a taks created using eg. Task.Factory.StartNew and await that task.
The following code will not block because processing is done in a different thread, allowing the UI thread to process events:
while ((line= await reader.ReadLineAsync()) != null)
{
await Task.Factory.StartNew(ln =>
{
var lower = (ln as string).ToLowerInvariant();
Console.WriteLine(lower);
},line);
}
I'm seeing the same problem as you to an extent - but only to an extent. For me, the UI is very jerky in the debugger, and occasionally jerky not in the debugger. (My file consists of lots of lines of 10 characters, by the way - the shape of the data will change behaviour here.) Often in the debugger it's good to start with, then bad for a long time, then it sometimes recovers.
I suspect the problem may simply be that your disk is too fast and your lines are too short. I know that sounds crazy, so let me explain...
When you use an await expression, that will only go through the "attach a continuation" path if it needs to. If the results are present already, the code just extracts the value and continues in the same thread.
That means, if ReadLineAsync always returns a task which is completed by the time it returns, you'll effectively see synchronous behaviour. It's entirely possible that ReadLineAsync looks at what data it's already got buffered, and tries to synchronously find a line within it to start with. The operating system may well then read more data from the disk so that it's ready for your application to use... which means that the UI thread never gets a chance to pump its normal messages, so the UI freezes.
I had expected that running the same code over a network would "fix" the problem, but it didn't seem to. (It changes exactly how the jerkiness is shown, mind you.) However, using:
await Task.Delay(1);
Does unfreeze the UI. (Task.Yield doesn't though, which again confuses me a lot. I suspect that may be a matter of prioritization between the continuation and other UI events.)
Now as for why you're only seeing this in the debugger - that still confuses me. Perhaps it's something to do with how interrupts are processed in the debugger, changing the timing subtly.
These are only guesses, but they're at least somewhat educated ones.
EDIT: Okay, I've worked out a way to indicate that it's at least partly to do with that. Change your method like this:
private static async Task<IEnumerable<string>>
FileReadAllLinesAsync(string path, Label label)
{
int completeCount = 0;
int incompleteCount = 0;
using (var reader = new StreamReader(path))
{
while (true)
{
var task = reader.ReadLineAsync();
if (task.IsCompleted)
{
completeCount++;
}
else
{
incompleteCount++;
}
if (await task == null)
{
break;
}
label.Text = string.Format("{0} / {1}",
completeCount,
incompleteCount);
}
}
return null;
}
... and create and add a suitable label to the UI. On my machine, both in debug and non-debug, I see far more "complete" hits than "incomplete" - oddly enough, the ratio of complete to incomplete is 84:1 consistently, both under the debugger and not. So it's only after reading about one in 85 lines that the UI can get a chance to update. You should try the same on your machine.
As another test, I added a counter incrementing in the label.Paint event - in the debugger it only executed 1/10th as many times as not in the debugger, for the same number of lines.
Visual Studio isn't actually executing the asynchronous callback synchronously. However, your code is structured in such a manner that it is "flooding" the UI thread with messages that you may not need to execute on a UI thread. Specifically, when FileReadAllLinesAsync resumes execution in the body of the while loop, it does so on the SynchronizationContext that was captured on the await line in the same method. What this means is for every line in your file, a message is posted back to the UI thread to execute 1 copy of the body of that while loop.
You can resolve this issue by using ConfigureAwait(false) carefully.
In FileReadAllLinesAsync, the body of the while loop is not sensitive to which thread it runs on, so you can use the following instead:
while ((await reader.ReadLineAsync().ConfigureAwait(false)) != null)
In Main, suppose you do want the MessageBox.Show line to execute on the UI thread (perhaps you also have a buttonLoad.Enabled = true statement there). You can (and will!) still get this behavior without any changes to Main, since you did not use ConfigureAwait(false) there.
I suspect the delays you observe in the debugger are due to .NET's slower performance in managed/unmanaged code while a debugger is attached, so dispatching each of those millions of messages to the UI thread is up to 100x slower when you have the debugger attached. Rather than try to speed up that dispatching by disabling features, I suspect item #1 above will resolve the bulk of your problems immediately.
From Task-based Asynchronous Pattern in Microsoft Download Center :
For performance reasons, if a task has already completed by the time
the task is awaited, control will not be yielded, and the function
will instead continue executing.
And
In some cases, the amount of work required to complete the operation
is less than the amount of work it would take to launch the operation
asynchronously (e.g. reading from a stream where the read can be
satisfied by data already buffered in memory). In such cases, the
operation may complete synchronously, returning a Task that has
already been completed.
So my last answer was incorrect (short-timing asynchronous operation is synchronous for performance reasons).

What's a good way to implement a "stop/cancel" button to stop a thread (that ins't a background worker)

I've got a WPF application that does a lot of talking to a remote server, so to keep the UI nice and responsive I put those operations in a second thread. There are a few possible, though unlikely, instances where that thread would just hang, blocking forever. Is there a simple way for me to implement a "cancel" button that doesn't involve calling thread.Abort()? I see a lot of people advise against using that, and I don't want to leave any unreleased resources. Perhaps a way to force the thread to throw an exception?
I specify in the title that this isn't a background worker because the program doesn't use those. It's already coded up with plain old threads.
I absolutely agree with comments that you need to fix what's broken, because that's the real issue, but if you can't at the moment, and need to continue operating. If you are on .Net 4.0, use the Task library. You can create a task and pass it an action that will execute on a different thread. The key is that you can pass a cancellation token to that task.
http://msdn.microsoft.com/en-us/library/dd997396.aspx
if you fire the same action over and over, you can also check the task status and do something about that.
//this is just a sample
if (myTask != null) //meaning it's still exe'ing your action
{
if (myTask.Status == TaskStatus.Faulted) //there's some kind of a problem with exe'ing it
myTask = null; // could reset to run the action again
else
return; //let the task finish
}
myTask = Task.Factory.StartNew (() =>
{
ExecuteUMyAction ();
});

Is BackgroundWorker the only way to keep a WCF/WPF application responsive?

Client/server desktop application using C#, WCF, WPF. Since pretty much every action is going to require a trip to the server (list/create/save/delete/etc), every action has the potential to freeze the entire UI. Here's an example of a naive implementation with a call to service.GetAll() which could take a "long" time (more than a few hundred milliseconds):
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
vm.Users.Clear();
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
}
(Aside: I'd love to know why List has AddRange and ObservableCollection doesn't.)
BackgroundWorker to the rescue:
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
var worker = new BackgroundWorker();
worker.DoWork += (s, e) =>
{
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = false; });
e.Result = service.GetAllUsers();
};
worker.RunWorkerCompleted += (s, e) =>
{
vm.Users.Clear();
foreach (var user in (List<UserDto>)e.Result)
vm.Users.Add(user);
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = true; });
};
worker.RunWorkerAsync();
}
(Aside: code above has been simplified, but that's the gist of it.)
The code using BackgroundWorker works exactly how I want it to. The app remains responsive at all times, and the button is disabled for the duration of the call. However, this means adding 15 lines to every possible action the user might make.
Say it ain't so.
No, BackgroundWorker is not the only way, but it's one way. Any other way will allso include some form of asynchronous construct with the need to use Dispatch.BeginInvoke to update the UI. You could for instance use the ThreadPool:
ThreadPool.QueueUserWorkItem(state => {
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = false; });
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
Dispatcher.BeginInvoke((Action)delegate() { btnRefresh.IsEnabled = true; });
});
If this is a recurring pattern (a button will trigger some action that should be performed asynchronously, with the button being disabled during the process) you can wrap this into a method:
private void PerformAsync(Action action, Control triggeringControl)
{
ThreadPool.QueueUserWorkItem(state => {
Dispatcher.BeginInvoke((Action)delegate() { triggeringControl.IsEnabled = false; });
action();
Dispatcher.BeginInvoke((Action)delegate() { triggeringControl.IsEnabled = true; });
});
}
...and call it:
PerformAsync(() =>
{
foreach (var user in service.GetAllUsers())
vm.Users.Add(user);
}, btnRefresh);
As an option to using the ThreadPool, you should also perhaps look into the Task Parallel Library.
When doing this you should pay attention to how you handle UI state. For instance of you have more than one control which triggers the same action, make sure that all of them are disabled during the action.
Note: these are just quick ideas. The code has not been tested so it may contain errors. It's more to be regarded as discussion material than finished solutions.
WCF provides the ability to make all service calls asynchronously. When you create the service reference in your project, the add service reference dialog box has an "Advanced..." button. Clicking that you will see the option for "Generate Asynchronous operations". If you click that check-box then every operation will be generated in both a synchronous and asynchronous manner.
For example, if i have an operation "DoSomething()" then after checking this box i will get code generated for calling DoSomething() and DoSomethingAsync().
You will also get a Service.DoSomethingCompleted event that you can use to define a callback handler when the service call returns.
This is the method we used to make service calls without locking the UI.
Here is a rather complicated example provided by Microsoft on how to do this: http://msdn.microsoft.com/en-us/library/ms730059.aspx
It is not the only way. I recommend Task (or one of the higher-level abstractions for Task, such as Parallel or PLINQ).
I have a review of various approaches to asynchronous background operations on my blog.
The current state of things does require some boilerplate code, regardless of which approach you choose. The async CTP shows where things are going - towards a much, much cleaner syntax for asynchronous operations. (Note that - at the time of writing - the async CTP is incompatible with VS SP1).
Well, BackgroundWorker is not the only option you have but in order to accomplish what you want you still need to use multiple threads or asynchronous operations in order to not block while you wait for the long-running operations to finish.
And, because WPF requires that all code accessing the UI run on the same thread you do have to do some context switching when you call or access data or code on the UI thread. The way to ensure a call will run on the UI thread in WPF is to use the Dispatcher class.
Another simple way of keeping the UI responsive is to queue work item on a thread in the Thread Pool which is done using the ThreadPool class.
// assuming the the following code resides in a WPF control
// hence "this" is a reference to a WPF control which has a Dispatcher
System.Threading.ThreadPool.QueueUserWorkItem((WaitCallback)delegate{
// put long-running code here
// get the result
// now use the Dispatcher to invoke code back on the UI thread
this.Dispatcher.Invoke(DispatcherPriority.Normal,
(Action)delegate(){
// this code would be scheduled to run on the UI
});
});
As always, there's more than one way to skin the cat but be aware that each technique has advantages and disadvantages. For instance the method outlines above could be useful because it doesn't have that much code overhead but it may not be the most efficient way in may cases.
Other options are available including using the BeginXXX - EndXXX methods of the classes you're using if they provide any (such as the SqlCommand class has BeginExecuteReader EndExecuteReader). Or, using the XXXAsync methods if the classes have that. For instance the System.Net.Sokets.Socket class has ReceiveAsync and SendAsync.
No this is not the only option. This question is more about how are you designing your application.
You can take a look at Windows Composite Applicaiton Framework (Prism), which provides features like EventAggregator which can help you publish application wide events out and subscribe it at multiple locations within your app and take actions based on that.
Also as far as being worried about having too many lines of code, you may want to layer your application architecture in such a way that you can refactor and reuse as much code as possible. This way you have these background workers handling all your service responses in one layer while you can leave your UI layer detached from it.
No it's not the only way, but it is one of the simpler ones (at least compared to setting up your own thread, or pushing a task to a thread pool thread and arranging an event on completion).
You might be able to simplify a little bit by writing a static method somewhere that takes two parameters, the callback functions, and handles the rest for you, that way you won't have to write all the same boiler plate every time you need to make an async call.
No, certaily not.
You can create a raw Thread and execute time taking code in it and then dispatch the code to the UI Thread to access/update any UI controls.More info on Disptacher here.
Refer to this for a great information about Threads in c#.

Categories