Invoke the restore wait dialog on the UI thread

This commit is contained in:
juste 2014-02-26 12:31:06 -08:00
Родитель 89abb5f2a3
Коммит ef404b5159
4 изменённых файлов: 58 добавлений и 19 удалений

Просмотреть файл

@ -8,6 +8,9 @@ using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using EnvDTE;
using Microsoft.VisualStudio.Project;
using Microsoft.VisualStudio.Project.Designers;
@ -133,15 +136,17 @@ namespace NuGet.VisualStudio
_waitDialogFactory.CreateInstance(out waitDialog);
try
{
waitDialog.StartWaitDialog(
VsResources.DialogTitle,
VsResources.PackageRestoreWaitMessage,
String.Empty,
varStatusBmpAnim: null,
szStatusBarText: null,
iDelayToShowDialog: 0,
fIsCancelable: false,
fShowMarqueeProgress: true);
// Start the wait dialog on the UI thread
InvokeOnUIThread(() =>
waitDialog.StartWaitDialog(
VsResources.DialogTitle,
VsResources.PackageRestoreWaitMessage,
String.Empty,
varStatusBmpAnim: null,
szStatusBarText: null,
iDelayToShowDialog: 0,
fIsCancelable: false,
fShowMarqueeProgress: true));
if (fromActivation)
{
@ -159,7 +164,8 @@ namespace NuGet.VisualStudio
finally
{
int canceled;
waitDialog.EndWaitDialog(out canceled);
InvokeOnUIThread(() => waitDialog.EndWaitDialog(out canceled));
}
if (fromActivation)
@ -283,7 +289,7 @@ namespace NuGet.VisualStudio
return;
}
if (!VsVersionHelper.IsVisualStudio2010 &&
if (!VsVersionHelper.IsVisualStudio2010 &&
(project.IsJavaScriptProject() || project.IsNativeProject()))
{
if (VsVersionHelper.IsVisualStudio2012)
@ -350,7 +356,7 @@ namespace NuGet.VisualStudio
buildProject.FullPath,
PathUtility.EnsureTrailingSlash(_solutionManager.SolutionDirectory));
relativeSolutionPath = PathUtility.EnsureTrailingSlash(relativeSolutionPath);
var solutionDirProperty = buildProject.Xml.AddProperty(solutiondir, relativeSolutionPath);
solutionDirProperty.Condition =
String.Format(
@ -381,7 +387,7 @@ namespace NuGet.VisualStudio
{
// download NuGet.Build and NuGet.CommandLine packages into the .nuget folder,
// using the active package source first and fall back to other enabled package sources.
IPackageRepository repository = CreatePackageRestoreRepository();
IPackageRepository repository = CreatePackageRestoreRepository();
var installPackages = new string[] { NuGetBuildPackageName, NuGetCommandLinePackageName };
foreach (var packageId in installPackages)
@ -608,5 +614,20 @@ namespace NuGet.VisualStudio
return new PackageReference[0];
}
/// <summary>
/// Invokes the action on the UI thread if one exists.
/// </summary>
private void InvokeOnUIThread(Action action)
{
if (Application.Current != null)
{
Application.Current.Dispatcher.Invoke(action);
}
else
{
action();
}
}
}
}

Просмотреть файл

@ -20,14 +20,22 @@ namespace NuGet.VisualStudio12
#if VS12
/// <summary>
/// Performs an action inside a VS internal writer lock. This method runs synchronously but uses several different
/// threads to avoid deadlocks with the project system.
/// Performs an action inside a VS internal writer lock. If called from the UI thread this method will
/// run async to avoid deadlocks.
/// </summary>
public static void DoWorkInWriterLock(Project project, IVsHierarchy hierarchy, Action<MsBuildProject> action)
{
// peform this work on a new thread to avoid moving our current thread
// Perform this work on a new thread to avoid moving our current thread, and so it can be done async if needed.
var task = Task.Run(() => DoWorkInWriterLockInternal(project, hierarchy, action));
task.Wait();
// Check if we are running on the UI thread. If we are we cannot risk blocking and holding the lock.
// Ideally all calls involving the lock should be done on a background thread from the start to
// keep the call as synchronous as possible within NuGet.
if (!Microsoft.VisualStudio.Shell.ThreadHelper.CheckAccess())
{
// If we are on a background thread we can safely run synchronously.
task.Wait();
}
}
private static async Task DoWorkInWriterLockInternal(Project project, IVsHierarchy hierarchy, Action<MsBuildProject> action)

Просмотреть файл

@ -209,7 +209,17 @@ namespace NuGet.Tools
// the <Import> element added.
if (PackageRestoreManager.IsCurrentSolutionEnabledForRestore)
{
PackageRestoreManager.EnableCurrentSolutionForRestore(fromActivation: false);
if (VsVersionHelper.IsVisualStudio2013)
{
// Run on a background thread in VS2013 to avoid CPS hangs. The modal loading dialog will block
// until this completes.
ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
PackageRestoreManager.EnableCurrentSolutionForRestore(fromActivation: false)));
}
else
{
PackageRestoreManager.EnableCurrentSolutionForRestore(fromActivation: false);
}
}
// when NuGet loads, if the current solution has some package

Просмотреть файл

@ -63,7 +63,7 @@ function Test-EnablePackageRestoreModifyProjectThatInstallNewPackages
Assert-AreEqual "true" (Get-MsBuildPropertyValue $p "RestorePackages")
}
function Test-EnablePackageRestoreOnCpsProjects
function NoTest-EnablePackageRestoreOnCpsProjects
{
if ($dte.Version -eq "10.0")
{