I'm getting started with Visual Studio Extensions and would like to write status messages to the output window during certain milestones of my task to report it's progress.
I'm using a command to trigger the task from a context menu. Here is a mocked up example of it's Execute method:
private void Execute(object sender, EventArgs e)
{
ThreadHelper.ThrowIfNotOnUIThread();
var paneGuid = Guid.NewGuid();
var outputWindow = (IVsOutputWindow)Package.GetGlobalService(typeof(SVsOutputWindow));
outputWindow.CreatePane(ref paneGuid, "My Window", 1, 1);
outputWindow.GetPane(ref paneGuid, out var outputPane);
outputPane.Activate();
outputPane.OutputString("Starting...\n");
Thread.Sleep(2000);
outputPane.OutputString("1...\n");
Thread.Sleep(2000);
outputPane.OutputString("2...\n");
Thread.Sleep(2000);
outputPane.OutputString("3...\n");
Thread.Sleep(2000);
outputPane.OutputString("Finished");
}
Rather than showing the output as it is written, the output window is shown after the Execute method has finished.
How do I get it to show straight away and to write messages periodically?
UPDATE: SOLUTION
As suggested below by JHBonarius the solution is to move the logic into an async task and to call the UI thread to write to the output window as required:
private void Execute(object sender, EventArgs e)
{
ThreadHelper.JoinableTaskFactory.RunAsync(async () =>
{
var paneGuid = Guid.NewGuid();
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
var outputWindow = (IVsOutputWindow)Package.GetGlobalService(typeof(SVsOutputWindow));
outputWindow.CreatePane(ref paneGuid, "My Window", 1, 1);
outputWindow.GetPane(ref paneGuid, out var outputPane);
outputPane.Activate();
outputPane.OutputString("Starting...\n");
await TaskScheduler.Default;
// Call to some async task
await Task.Delay(2000);
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
outputPane.OutputString("1...\n");
await TaskScheduler.Default;
// Call to some async task
await Task.Delay(2000);
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
outputPane.OutputString("2...\n");
await TaskScheduler.Default;
// Call to some async task
await Task.Delay(2000);
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
outputPane.OutputString("3...\n");
await TaskScheduler.Default;
// Call to some async task
await Task.Delay(2000);
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
outputPane.OutputString("Finished");
await TaskScheduler.Default;
});
}
Thanks, Jay
You are on the UI thread and don't return control (but instead lock the thread with sleep). Thus the UI cannot render. You might want to rewrite this to separate methods or an async method.