I am working on a small Visual Studio 2012 Add-in. The Add-in sets the reference path for all projects in the open solution. I am accomplishing this through a simple UI. Once the user enters their desired reference path string, a second window pops up that reports progress to the user.
For some reason,
proj.Properties.Item("ReferencePath").Value = referencePaths
takes a very long time to execute, so the UI is unresponsive. After learning this, I moved this item into an async method thinking that it would solve my problem.
The UI is still unresponsive and I cannot figure out why. Although I can drag the window around, and click the cancel button, these actions don't register until the above code completes (drag the window and it doesn't move until it goes on to the next operation). I have spent several hours reading C# textbooks and searching this site. Help is very appreciated! Also, feel free to comment on any other part of my code that could be improved.
Thanks!
public partial class FormWorking : Form
{
CancellationTokenSource CancellationSource;
public FormWorking()
{
InitializeComponent();
CancellationSource = new CancellationTokenSource();
}
//progess is a Label object used to report progress.
public string ProgressText
{
get { return progress.Text; }
private set
{
progress.Text = value;
if (progress.Width > this.Width - 2 * progress.Location.X)
{
this.Width = progress.Width + 2 * progress.Location.X;
}
}
}
//cancel event handler
private void Cancel_Click(object sender, EventArgs e)
{
CancellationSource.Cancel();
}
//entry method for processing. Adds paths to a solution in VS
public void AddPaths(string referencePaths, Solution sln)
{
RecursiveAddPathsAsync(
referencePaths,
sln,
new Progress<string>((Text) => ProgressText = Text)
);
}
//recursive helper method
async private void RecursiveAddPathsAsync(string referencePaths, Solution sln,
IProgress<string> progressReporter)
{
try
{
foreach (Project proj in sln.Projects)
{
await RecurisveAddPathsAsync(referencePaths, proj, progressReporter, CancellationSource.Token);
}
}
catch (OperationCanceledException) { }
}
//recursive method for project trees
async private Task RecurisveAddPathsAsync(string referencePaths, Project proj,
IProgress<string> progressReporter, CancellationToken cancelToken)
{
cancelToken.ThrowIfCancellationRequested();
progressReporter.Report(proj.FullName);
if (proj.FileName.EndsWith("csproj"))
{
try
{
//time consuming operation
//the UI is unresponsive here!
await Task.Run(
() => proj.Properties.Item("ReferencePath").Value = referencePaths
, cancelToken);
}
catch (Exception ex)
{
if (ex is OperationCanceledException)
throw;
}
}
else
{
//recursion
if (proj.ProjectItems != null)
foreach (ProjectItem pi in proj.ProjectItems)
if (pi.SubProject != null)
await RecurisveAddPathsAsync(referencePaths, pi.SubProject,
progressReporter, cancelToken);
}
}
}