зеркало из https://github.com/github/VisualStudio.git
Refactoring, navigation and lifetime of mef
Extract interfaces of mef exports to separate dll to decouple things a bit. Only load reactive things when requesting UI dialogs, TeamExplorer items should not load any reactive stuff. Introduce ExportFactory to dispose of IDisposable mef components properly. Start fleshing out team explorer implementation.
This commit is contained in:
Родитель
6b235e8327
Коммит
a107c79d66
|
@ -45,6 +45,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{7B6C5F8D
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{8A7DA2E7-262B-4581-807A-1C45CE79CDFD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GitHub.Exports", "src\GitHub.Exports\GitHub.Exports.csproj", "{9AEA02DB-02B5-409C-B0CA-115D05331A6B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -83,6 +85,10 @@ Global
|
|||
{4A84E568-CA86-4510-8CD0-90D3EF9B65F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4A84E568-CA86-4510-8CD0-90D3EF9B65F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4A84E568-CA86-4510-8CD0-90D3EF9B65F9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9AEA02DB-02B5-409C-B0CA-115D05331A6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9AEA02DB-02B5-409C-B0CA-115D05331A6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9AEA02DB-02B5-409C-B0CA-115D05331A6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9AEA02DB-02B5-409C-B0CA-115D05331A6B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
namespace GitHub.Authentication
|
||||
using GitHub.Exports;
|
||||
|
||||
namespace GitHub.Authentication
|
||||
{
|
||||
public enum AuthenticationResult
|
||||
{
|
||||
CredentialFailure,
|
||||
VerificationFailure,
|
||||
Success
|
||||
}
|
||||
|
||||
public static class AuthenticationResultExtensions
|
||||
{
|
||||
|
|
|
@ -163,6 +163,10 @@
|
|||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\GitHub.Exports\GitHub.Exports.csproj">
|
||||
<Project>{9aea02db-02b5-409c-b0ca-115d05331a6b}</Project>
|
||||
<Name>GitHub.Exports</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\GitHub.Extensions.Reactive\GitHub.Extensions.Reactive.csproj">
|
||||
<Project>{6559e128-8b40-49a5-85a8-05565ed0c7e3}</Project>
|
||||
<Name>GitHub.Extensions.Reactive</Name>
|
||||
|
|
|
@ -7,6 +7,7 @@ using Akavache;
|
|||
using GitHub.Authentication;
|
||||
using NullGuard;
|
||||
using ReactiveUI;
|
||||
using GitHub.Exports;
|
||||
|
||||
namespace GitHub.Models
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Reactive;
|
|||
using GitHub.Authentication;
|
||||
using GitHub.Helpers;
|
||||
using ReactiveUI;
|
||||
using GitHub.Exports;
|
||||
|
||||
namespace GitHub.Models
|
||||
{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using GitHub.Authentication;
|
||||
using ReactiveUI;
|
||||
using GitHub.Exports;
|
||||
|
||||
namespace GitHub.Models
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Reactive;
|
|||
using System.Reactive.Linq;
|
||||
using GitHub.Authentication;
|
||||
using ReactiveUI;
|
||||
using GitHub.Exports;
|
||||
|
||||
namespace GitHub.Models
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@ using NLog;
|
|||
using Octokit;
|
||||
using ReactiveUI;
|
||||
using Authorization = Octokit.Authorization;
|
||||
using GitHub.Exports;
|
||||
|
||||
namespace GitHub.Models
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ using Akavache;
|
|||
using GitHub.Authentication;
|
||||
using GitHub.Extensions.Reactive;
|
||||
using ReactiveUI;
|
||||
using GitHub.Exports;
|
||||
|
||||
namespace GitHub.Models
|
||||
{
|
||||
|
|
|
@ -12,32 +12,142 @@ using GitHub.Info;
|
|||
using GitHub.Models;
|
||||
using GitHub.Services;
|
||||
using GitHub.Validation;
|
||||
using GitHub.Exports;
|
||||
using NullGuard;
|
||||
using ReactiveUI;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace GitHub.ViewModels
|
||||
{
|
||||
[SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable")]
|
||||
[Export(typeof(LoginControlViewModel))]
|
||||
[Export(typeof(ILoginDialog))]
|
||||
[PartCreationPolicy(CreationPolicy.NonShared)]
|
||||
public class LoginControlViewModel : ReactiveValidatableObject, IDisposable
|
||||
public class LoginControlViewModel : ReactiveValidatableObject, ILoginDialog, IDisposable
|
||||
{
|
||||
string enterpriseUrl;
|
||||
readonly ObservableAsPropertyHelper<bool> isLoggingInToEnterprise;
|
||||
readonly ObservableAsPropertyHelper<bool> isLoginInProgress;
|
||||
readonly Subject<AuthenticationResult> authenticationResults;
|
||||
readonly ObservableAsPropertyHelper<string> loginButtonText;
|
||||
bool loginFailed;
|
||||
string loginFailedText;
|
||||
readonly ObservableAsPropertyHelper<LoginMode> loginMode;
|
||||
readonly ObservableAsPropertyHelper<LoginTarget> loginTarget;
|
||||
readonly ObservableAsPropertyHelper<VisualState> visualState;
|
||||
string password;
|
||||
string usernameOrEmail;
|
||||
Uri enterpriseHostBaseUrl;
|
||||
readonly Lazy<IEnterpriseProbe> lazyEnterpriseProbe;
|
||||
const string notEnterpriseServerError = "Not an Enterprise server. Please enter an Enterprise URL";
|
||||
|
||||
public ReactiveCommand<AuthenticationResult> LoginCommand { get; private set; }
|
||||
public ICommand LoginCmd { get { return LoginCommand; } }
|
||||
public ReactiveCommand<object> CancelCommand { get; private set; }
|
||||
public ICommand CancelCmd { get { return CancelCommand; } }
|
||||
public IObservable<object> CancelEvt { get { return CancelCommand; } }
|
||||
|
||||
public ReactiveCommand<object> ForgotPasswordCommand { get; private set; }
|
||||
public ReactiveCommand<object> ShowDotComLoginCommand { get; set; }
|
||||
public ReactiveCommand<object> ShowEnterpriseLoginCommand { get; set; }
|
||||
public ReactiveCommand<object> SignupCommand { get; private set; }
|
||||
public ReactiveCommand<object> LearnMoreCommand { get; private set; }
|
||||
|
||||
string enterpriseUrl;
|
||||
[ValidateIf("IsLoggingInToEnterprise")]
|
||||
[Required(ErrorMessage = "Please enter an Enterprise URL")]
|
||||
[AllowNull]
|
||||
public string EnterpriseUrl
|
||||
{
|
||||
get { return enterpriseUrl; }
|
||||
set { this.RaiseAndSetIfChanged(ref enterpriseUrl, value); }
|
||||
}
|
||||
|
||||
readonly ObservableAsPropertyHelper<bool> isLoggingInToEnterprise;
|
||||
public bool IsLoggingInToEnterprise
|
||||
{
|
||||
get { return isLoggingInToEnterprise.Value; }
|
||||
}
|
||||
|
||||
readonly ObservableAsPropertyHelper<bool> isLoginInProgress;
|
||||
public bool IsLoginInProgress
|
||||
{
|
||||
get { return isLoginInProgress.Value; }
|
||||
}
|
||||
|
||||
readonly ObservableAsPropertyHelper<string> loginButtonText;
|
||||
public string LoginButtonText
|
||||
{
|
||||
get { return loginButtonText.Value; }
|
||||
}
|
||||
|
||||
bool loginFailed;
|
||||
public bool LoginFailed
|
||||
{
|
||||
get { return loginFailed; }
|
||||
set { this.RaiseAndSetIfChanged(ref loginFailed, value); }
|
||||
}
|
||||
|
||||
string loginFailedText;
|
||||
public string LoginFailedText
|
||||
{
|
||||
get { return loginFailedText; }
|
||||
private set { this.RaiseAndSetIfChanged(ref loginFailedText, value); }
|
||||
}
|
||||
|
||||
readonly ObservableAsPropertyHelper<LoginMode> loginMode;
|
||||
public LoginMode LoginMode
|
||||
{
|
||||
get { return loginMode.Value; }
|
||||
}
|
||||
|
||||
public string LoginPrefix { get; set; }
|
||||
|
||||
readonly ObservableAsPropertyHelper<LoginTarget> loginTarget;
|
||||
public LoginTarget LoginTarget
|
||||
{
|
||||
get { return loginTarget.Value; }
|
||||
}
|
||||
|
||||
readonly ObservableAsPropertyHelper<VisualState> visualState;
|
||||
public VisualState VisualState
|
||||
{
|
||||
get { return visualState.Value; }
|
||||
}
|
||||
|
||||
string password;
|
||||
[AllowNull]
|
||||
public string Password
|
||||
{
|
||||
[return: AllowNull]
|
||||
get
|
||||
{ return password; }
|
||||
set { this.RaiseAndSetIfChanged(ref password, value); }
|
||||
}
|
||||
|
||||
readonly ObservableAsPropertyHelper<Uri> forgotPasswordUrl;
|
||||
public Uri ForgotPasswordUrl
|
||||
{
|
||||
get { return forgotPasswordUrl.Value; }
|
||||
}
|
||||
|
||||
Uri enterpriseHostBaseUrl;
|
||||
Uri EnterpriseHostBaseUrl
|
||||
{
|
||||
get { return enterpriseHostBaseUrl; }
|
||||
set { this.RaiseAndSetIfChanged(ref enterpriseHostBaseUrl, value); }
|
||||
}
|
||||
|
||||
// HACKETY HACK!
|
||||
// Because #Bind() doesn't yet set up validation, we must use XAML bindings for username and password.
|
||||
// But, because our SecurePasswordBox manipulates base.Text, it doesn't work with XAML binding.
|
||||
// (It binds the password mask, not the password.)
|
||||
// So, this property is a "black hole" to point the XAML binding to so validation works.
|
||||
// And the actual password is bound to #Password via #Bind(). Ugly? Yep.
|
||||
[Required(ErrorMessage = "Please enter your password")]
|
||||
public string PasswordNoOp { get; set; }
|
||||
|
||||
protected IRepositoryHosts RepositoryHosts { get; private set; }
|
||||
|
||||
string usernameOrEmail;
|
||||
[Required(ErrorMessage = "Please enter your username or email address")]
|
||||
[AllowNull]
|
||||
public string UsernameOrEmail
|
||||
{
|
||||
[return: AllowNull]
|
||||
get
|
||||
{ return usernameOrEmail; }
|
||||
set { this.RaiseAndSetIfChanged(ref usernameOrEmail, value); }
|
||||
}
|
||||
|
||||
readonly Subject<AuthenticationResult> authenticationResults;
|
||||
public IObservable<AuthenticationResult> AuthenticationResults { get { return authenticationResults; } }
|
||||
|
||||
[SuppressMessage("Microsoft.Maintainability", "CA1505:AvoidUnmaintainableCode", Justification = "It's Rx baby")]
|
||||
[ImportingConstructor]
|
||||
|
@ -141,113 +251,6 @@ namespace GitHub.ViewModels
|
|||
ForgotPasswordCommand.Subscribe(_ => browser.OpenUrl(ForgotPasswordUrl));
|
||||
}
|
||||
|
||||
public ReactiveCommand<object> CancelCommand { get; private set; }
|
||||
|
||||
[ValidateIf("IsLoggingInToEnterprise")]
|
||||
[Required(ErrorMessage = "Please enter an Enterprise URL")]
|
||||
[AllowNull]
|
||||
public string EnterpriseUrl
|
||||
{
|
||||
get { return enterpriseUrl; }
|
||||
set { this.RaiseAndSetIfChanged(ref enterpriseUrl, value); }
|
||||
}
|
||||
|
||||
public ReactiveCommand<object> ForgotPasswordCommand { get; private set; }
|
||||
|
||||
public bool IsLoggingInToEnterprise
|
||||
{
|
||||
get { return isLoggingInToEnterprise.Value; }
|
||||
}
|
||||
|
||||
public bool IsLoginInProgress
|
||||
{
|
||||
get { return isLoginInProgress.Value; }
|
||||
}
|
||||
|
||||
public IObservable<AuthenticationResult> AuthenticationResults { get { return authenticationResults; } }
|
||||
|
||||
public string LoginButtonText
|
||||
{
|
||||
get { return loginButtonText.Value; }
|
||||
}
|
||||
|
||||
public ReactiveCommand<AuthenticationResult> LoginCommand { get; private set; }
|
||||
|
||||
public bool LoginFailed
|
||||
{
|
||||
get { return loginFailed; }
|
||||
set { this.RaiseAndSetIfChanged(ref loginFailed, value); }
|
||||
}
|
||||
|
||||
public string LoginFailedText
|
||||
{
|
||||
get { return loginFailedText; }
|
||||
private set { this.RaiseAndSetIfChanged(ref loginFailedText, value); }
|
||||
}
|
||||
|
||||
public LoginMode LoginMode
|
||||
{
|
||||
get { return loginMode.Value; }
|
||||
}
|
||||
|
||||
public string LoginPrefix { get; set; }
|
||||
|
||||
public LoginTarget LoginTarget
|
||||
{
|
||||
get { return loginTarget.Value; }
|
||||
}
|
||||
|
||||
public VisualState VisualState
|
||||
{
|
||||
get { return visualState.Value; }
|
||||
}
|
||||
|
||||
[AllowNull]
|
||||
public string Password
|
||||
{
|
||||
[return: AllowNull]
|
||||
get { return password; }
|
||||
set { this.RaiseAndSetIfChanged(ref password, value); }
|
||||
}
|
||||
|
||||
public Uri ForgotPasswordUrl
|
||||
{
|
||||
get { return forgotPasswordUrl.Value; }
|
||||
}
|
||||
|
||||
Uri EnterpriseHostBaseUrl
|
||||
{
|
||||
get { return enterpriseHostBaseUrl; }
|
||||
set { this.RaiseAndSetIfChanged(ref enterpriseHostBaseUrl, value); }
|
||||
}
|
||||
|
||||
// HACKETY HACK!
|
||||
// Because #Bind() doesn't yet set up validation, we must use XAML bindings for username and password.
|
||||
// But, because our SecurePasswordBox manipulates base.Text, it doesn't work with XAML binding.
|
||||
// (It binds the password mask, not the password.)
|
||||
// So, this property is a "black hole" to point the XAML binding to so validation works.
|
||||
// And the actual password is bound to #Password via #Bind(). Ugly? Yep.
|
||||
[Required(ErrorMessage = "Please enter your password")]
|
||||
public string PasswordNoOp { get; set; }
|
||||
|
||||
protected IRepositoryHosts RepositoryHosts { get; private set; }
|
||||
|
||||
public ReactiveCommand<object> ShowDotComLoginCommand { get; set; }
|
||||
|
||||
public ReactiveCommand<object> ShowEnterpriseLoginCommand { get; set; }
|
||||
|
||||
public ReactiveCommand<object> SignupCommand { get; private set; }
|
||||
|
||||
public ReactiveCommand<object> LearnMoreCommand { get; private set; }
|
||||
|
||||
[Required(ErrorMessage = "Please enter your username or email address")]
|
||||
[AllowNull]
|
||||
public string UsernameOrEmail
|
||||
{
|
||||
[return: AllowNull]
|
||||
get { return usernameOrEmail; }
|
||||
set { this.RaiseAndSetIfChanged(ref usernameOrEmail, value); }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
|
@ -8,12 +8,13 @@ using GitHub.Validation;
|
|||
using NullGuard;
|
||||
using Octokit;
|
||||
using ReactiveUI;
|
||||
using GitHub.Exports;
|
||||
|
||||
namespace GitHub.ViewModels
|
||||
{
|
||||
[Export(typeof(TwoFactorDialogViewModel))]
|
||||
[Export(typeof(ITwoFactorDialog))]
|
||||
[PartCreationPolicy(CreationPolicy.Shared)]
|
||||
public class TwoFactorDialogViewModel : ReactiveValidatableObject
|
||||
public class TwoFactorDialogViewModel : ReactiveValidatableObject, ITwoFactorDialog
|
||||
{
|
||||
bool isAuthenticationCodeSent;
|
||||
string authenticationCode;
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GitHub.Exports
|
||||
{
|
||||
public enum AuthenticationResult
|
||||
{
|
||||
CredentialFailure,
|
||||
VerificationFailure,
|
||||
Success
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{9AEA02DB-02B5-409C-B0CA-115D05331A6B}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>GitHub.Exports</RootNamespace>
|
||||
<AssemblyName>GitHub.Exports</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.Composition" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AuthenticationResult.cs" />
|
||||
<Compile Include="ICloneDialog.cs" />
|
||||
<Compile Include="ILoginDialog.cs" />
|
||||
<Compile Include="ITwoFactorDialog.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GitHub.Exports
|
||||
{
|
||||
public interface ICloneDialog
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace GitHub.Exports
|
||||
{
|
||||
public interface ILoginDialog
|
||||
{
|
||||
string UsernameOrEmail { get; set; }
|
||||
string Password { get; set; }
|
||||
ICommand LoginCmd { get; }
|
||||
ICommand CancelCmd { get; }
|
||||
IObservable<object> CancelEvt { get; }
|
||||
IObservable<AuthenticationResult> AuthenticationResults { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GitHub.Exports
|
||||
{
|
||||
public interface ITwoFactorDialog
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("GitHub.Exports")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("GitHub.Exports")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2015")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("9aea02db-02b5-409c-b0ca-115d05331a6b")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,75 @@
|
|||
using GitHub.VisualStudio.Services;
|
||||
using Microsoft.VisualStudio.ComponentModelHost;
|
||||
using Microsoft.VisualStudio.Shell;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GitHub.VisualStudio
|
||||
{
|
||||
public abstract class PackageBase : Package
|
||||
{
|
||||
IServiceProvider serviceProvider;
|
||||
protected IServiceProvider ServiceProvider
|
||||
{
|
||||
get { return serviceProvider; }
|
||||
set
|
||||
{
|
||||
serviceProvider = value;
|
||||
}
|
||||
}
|
||||
|
||||
public PackageBase()
|
||||
{
|
||||
ServiceProvider = this;
|
||||
}
|
||||
|
||||
public PackageBase(IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
protected void AddTopLevelMenuItem(
|
||||
uint packageCommandId,
|
||||
EventHandler eventHandler)
|
||||
{
|
||||
var menuCommandService = GetService(typeof(IMenuCommandService)) as IMenuCommandService;
|
||||
var menuCommandId = new CommandID(GuidList.guidGitHubCmdSet, (int)packageCommandId);
|
||||
var menuItem = new MenuCommand(eventHandler, menuCommandId);
|
||||
menuCommandService.AddCommand(menuItem);
|
||||
}
|
||||
|
||||
public T GetService<T>()
|
||||
{
|
||||
Debug.Assert(this.serviceProvider != null, "GetService<T> called before service provider is set");
|
||||
if (serviceProvider == null)
|
||||
return default(T);
|
||||
return (T)serviceProvider.GetService(typeof(T));
|
||||
}
|
||||
|
||||
public Ret GetService<T, Ret>() where Ret : class
|
||||
{
|
||||
return GetService<T>() as Ret;
|
||||
}
|
||||
|
||||
public T GetExportedValue<T>()
|
||||
{
|
||||
var componentModel = (IComponentModel)GetService<SComponentModel>();
|
||||
if (componentModel == null)
|
||||
return default(T);
|
||||
var exportProvider = componentModel.DefaultExportProvider;
|
||||
return exportProvider.GetExportedValue<T>();
|
||||
}
|
||||
|
||||
protected void EnsureUIProvider()
|
||||
{
|
||||
var ui = GetExportedValue<UIProvider>();
|
||||
ui.EnsureProvider(GetService<SComponentModel, IComponentModel>().DefaultExportProvider);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
using Microsoft.TeamFoundation.Client;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GitHub.VisualStudio.Base
|
||||
{
|
||||
public abstract class TeamExplorerBase : IDisposable, INotifyPropertyChanged
|
||||
{
|
||||
bool subscribed = false;
|
||||
|
||||
IServiceProvider serviceProvider;
|
||||
protected IServiceProvider ServiceProvider
|
||||
{
|
||||
get { return serviceProvider; }
|
||||
set
|
||||
{
|
||||
if (serviceProvider != null)
|
||||
UnsubscribeContextChanges();
|
||||
serviceProvider = value;
|
||||
if (serviceProvider != null)
|
||||
SubscribeContextChanges();
|
||||
}
|
||||
}
|
||||
|
||||
protected ITeamFoundationContext CurrentContext
|
||||
{
|
||||
get
|
||||
{
|
||||
var manager = GetService<ITeamFoundationContextManager>();
|
||||
if (manager != null)
|
||||
return manager.CurrentContext;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void SubscribeContextChanges()
|
||||
{
|
||||
Debug.Assert(serviceProvider != null, "ServiceProvider must be set before subscribing to context changes");
|
||||
if (serviceProvider == null || subscribed)
|
||||
return;
|
||||
|
||||
var manager = GetService<ITeamFoundationContextManager>();
|
||||
if (manager != null)
|
||||
{
|
||||
manager.ContextChanged += ContextChanged;
|
||||
subscribed = true;
|
||||
}
|
||||
}
|
||||
|
||||
void UnsubscribeContextChanges()
|
||||
{
|
||||
var manager = GetService<ITeamFoundationContextManager>();
|
||||
if (manager != null)
|
||||
{
|
||||
manager.ContextChanged -= ContextChanged;
|
||||
subscribed = false;
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
protected void RaisePropertyChanged(string propertyName)
|
||||
{
|
||||
if (PropertyChanged != null)
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
UnsubscribeContextChanges();
|
||||
}
|
||||
|
||||
public T GetService<T>()
|
||||
{
|
||||
Debug.Assert(this.serviceProvider != null, "GetService<T> called before service provider is set");
|
||||
if (serviceProvider == null)
|
||||
return default(T);
|
||||
return (T)serviceProvider.GetService(typeof(T));
|
||||
}
|
||||
|
||||
public Ret GetService<T, Ret>() where Ret : class
|
||||
{
|
||||
return GetService<T>() as Ret;
|
||||
}
|
||||
|
||||
|
||||
protected virtual void ContextChanged(object sender, ContextChangedEventArgs e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
|
@ -33,9 +33,10 @@
|
|||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||
<CodeAnalysisRuleSet>..\..\script\GitHubVS.ruleset</CodeAnalysisRuleSet>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<CodeAnalysisIgnoreGeneratedCode>false</CodeAnalysisIgnoreGeneratedCode>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
|
@ -52,6 +53,30 @@
|
|||
<HintPath>..\..\packages\EditorUtils2013.1.4.1.1\lib\net40\EditorUtils2013.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.TeamFoundation.Client, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\Microsoft.TeamFoundation.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.TeamFoundation.Common, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\Microsoft.TeamFoundation.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.TeamFoundation.Controls, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\Microsoft.TeamFoundation.Controls.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.TeamFoundation.VersionControl.Client, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\Microsoft.TeamFoundation.VersionControl.Client.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.TeamFoundation.VersionControl.Common, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\Microsoft.TeamFoundation.VersionControl.Common.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.TeamFoundation.VersionControl.Controls, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\..\..\..\..\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\Microsoft.TeamFoundation.VersionControl.Controls.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.VisualStudio.ComponentModelHost, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||
<Reference Include="Microsoft.VisualStudio.CoreUtility, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||
<Reference Include="Microsoft.VisualStudio.Language.Intellisense, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
|
||||
|
@ -161,7 +186,10 @@
|
|||
<Compile Include="..\..\script\SolutionInfo.cs">
|
||||
<Link>Properties\SolutionInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Base\TeamExplorerBase.cs" />
|
||||
<Compile Include="Helpers\ExportFactoryProvider.cs" />
|
||||
<Compile Include="Guids.cs" />
|
||||
<Compile Include="Base\PackageBase.cs" />
|
||||
<Compile Include="Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
|
@ -171,6 +199,7 @@
|
|||
<Compile Include="GitHubPackage.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="PkgCmdID.cs" />
|
||||
<Compile Include="Services\UIProvider.cs" />
|
||||
<Compile Include="UI\DrawingExtensions.cs" />
|
||||
<Compile Include="UI\Views\Controls\LoginControl.xaml.cs">
|
||||
<DependentUpon>LoginControl.xaml</DependentUpon>
|
||||
|
@ -245,6 +274,12 @@
|
|||
<Project>{1a1da411-8d1f-4578-80a6-04576bea2dc5}</Project>
|
||||
<Name>GitHub.App</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\GitHub.Exports\GitHub.Exports.csproj">
|
||||
<Project>{9aea02db-02b5-409c-b0ca-115d05331a6b}</Project>
|
||||
<Name>GitHub.Exports</Name>
|
||||
<IncludeOutputGroupsInVSIX>BuiltProjectOutputGroup%3bBuiltProjectOutputGroupDependencies%3bGetCopyToOutputDirectoryItems%3bSatelliteDllsProjectOutputGroup%3b</IncludeOutputGroupsInVSIX>
|
||||
<IncludeOutputGroupsInVSIXLocalOnly>DebugSymbolsProjectOutputGroup%3b</IncludeOutputGroupsInVSIXLocalOnly>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\GitHub.Extensions.Reactive\GitHub.Extensions.Reactive.csproj">
|
||||
<Project>{6559e128-8b40-49a5-85a8-05565ed0c7e3}</Project>
|
||||
<Name>GitHub.Extensions.Reactive</Name>
|
||||
|
|
|
@ -20,6 +20,8 @@ using Microsoft.VisualStudio.ComponentModelHost;
|
|||
using Microsoft.VisualStudio.Shell;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
using GitHub.Exports;
|
||||
using GitHub.VisualStudio.Services;
|
||||
|
||||
namespace GitHub.VisualStudio
|
||||
{
|
||||
|
@ -43,33 +45,15 @@ namespace GitHub.VisualStudio
|
|||
[ProvideMenuResource("Menus.ctmenu", 1)]
|
||||
[Guid(GuidList.guidGitHubPkgString)]
|
||||
[ProvideBindingPath]
|
||||
public class GitHubPackage : Package
|
||||
public class GitHubPackage : PackageBase
|
||||
{
|
||||
readonly IServiceProvider serviceProvider;
|
||||
|
||||
// Set of assemblies we need to load early.
|
||||
static readonly IEnumerable<string> earlyLoadAssemblies = new[] {
|
||||
"Rothko.dll",
|
||||
"GitHub.App.dll",
|
||||
"GitHub.UI.Reactive.dll",
|
||||
"GitHub.UI.dll"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor of the package.
|
||||
/// Inside this method you can place any initialization code that does not require
|
||||
/// any Visual Studio service because at this point the package object is created but
|
||||
/// not sited yet inside Visual Studio environment. The place to do all the other
|
||||
/// initialization is the Initialize method.
|
||||
/// </summary>
|
||||
public GitHubPackage()
|
||||
{
|
||||
serviceProvider = this;
|
||||
}
|
||||
|
||||
public GitHubPackage(IServiceProvider serviceProvider)
|
||||
: base(serviceProvider)
|
||||
{
|
||||
this.serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -82,42 +66,16 @@ namespace GitHub.VisualStudio
|
|||
Debug.WriteLine("Entering Initialize() of: {0}", ToString());
|
||||
base.Initialize();
|
||||
|
||||
ModeDetector.OverrideModeDetector(new AppModeDetector());
|
||||
RxApp.MainThreadScheduler = new DispatcherScheduler(Application.Current.Dispatcher);
|
||||
|
||||
var dir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
Debug.Assert(dir != null, "The Assembly location can't be null");
|
||||
foreach (var v in earlyLoadAssemblies)
|
||||
{
|
||||
Assembly.LoadFile(Path.Combine(dir, v));
|
||||
}
|
||||
|
||||
// Set the Export Provider
|
||||
var mefServiceProvider = GetExportedValue<IServiceProvider>() as MefServiceProvider;
|
||||
Debug.Assert(mefServiceProvider != null, "Service Provider can't be imported");
|
||||
var componentModel = (IComponentModel)(serviceProvider.GetService(typeof(SComponentModel)));
|
||||
mefServiceProvider.ExportProvider = componentModel.DefaultExportProvider;
|
||||
|
||||
|
||||
// Add our command handlers for menu (commands must exist in the .vsct file)
|
||||
var mcs = serviceProvider.GetService(typeof(IMenuCommandService)) as IMenuCommandService;
|
||||
if (mcs != null)
|
||||
{
|
||||
// Login Command Menu Item
|
||||
AddTopLevelMenuItem(mcs, PkgCmdIDList.loginCommand, OnLoginCommand);
|
||||
// Login Command Menu Item
|
||||
|
||||
// Create Issue Command Menu Item
|
||||
AddTopLevelMenuItem(mcs, PkgCmdIDList.createIssueCommand, OnCreateIssueCommand);
|
||||
}
|
||||
}
|
||||
AddTopLevelMenuItem(PkgCmdIDList.loginCommand, OnLoginCommand);
|
||||
|
||||
static void AddTopLevelMenuItem(
|
||||
IMenuCommandService menuCommandService,
|
||||
uint packageCommandId,
|
||||
EventHandler eventHandler)
|
||||
{
|
||||
var menuCommandId = new CommandID(GuidList.guidGitHubCmdSet, (int)packageCommandId);
|
||||
var menuItem = new MenuCommand(eventHandler, menuCommandId);
|
||||
menuCommandService.AddCommand(menuItem);
|
||||
// Create Issue Command Menu Item
|
||||
AddTopLevelMenuItem(PkgCmdIDList.createIssueCommand, OnCreateIssueCommand);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -125,7 +83,7 @@ namespace GitHub.VisualStudio
|
|||
/// See the Initialize method to see how the menu item is associated to this function using
|
||||
/// the OleMenuCommandService service and the MenuCommand class.
|
||||
/// </summary>
|
||||
static void OnCreateIssueCommand(object sender, EventArgs e)
|
||||
void OnCreateIssueCommand(object sender, EventArgs e)
|
||||
{
|
||||
var createIssueDialog = new CreateIssueDialog();
|
||||
createIssueDialog.ShowModal();
|
||||
|
@ -133,41 +91,38 @@ namespace GitHub.VisualStudio
|
|||
|
||||
void OnLoginCommand(object sender, EventArgs e)
|
||||
{
|
||||
var loginControlViewModel = GetExportedValue<LoginControlViewModel>();
|
||||
EnsureUIProvider();
|
||||
/*
|
||||
var mefServiceProvider = GetExportedValue<IServiceProvider>() as MefServiceProvider;
|
||||
Debug.Assert(mefServiceProvider != null, "Service Provider can't be imported");
|
||||
var componentModel = GetService<SComponentModel>() as IComponentModel;
|
||||
if (componentModel != null)
|
||||
mefServiceProvider.ExportProvider = componentModel.DefaultExportProvider;
|
||||
*/
|
||||
|
||||
//var r = GetExportedValue<ILoginDialog>();
|
||||
var factory = GetExportedValue<ExportFactoryProvider>().LoginViewModelFactory;
|
||||
var disposable = factory.CreateExport();
|
||||
var loginControlViewModel = disposable.Value;
|
||||
|
||||
var loginIssueDialog = new LoginCommandDialog(loginControlViewModel);
|
||||
loginIssueDialog.Closed += (o,ev) => disposable.Dispose();
|
||||
loginControlViewModel.CancelEvt.Subscribe(x => loginIssueDialog.Close());
|
||||
|
||||
loginIssueDialog.Show();
|
||||
|
||||
loginControlViewModel.AuthenticationResults.Subscribe(result =>
|
||||
{
|
||||
if (result == AuthenticationResult.Success)
|
||||
loginIssueDialog.Hide();
|
||||
{
|
||||
loginIssueDialog.Close();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
T GetExportedValue<T>()
|
||||
{
|
||||
var componentModel = (IComponentModel)(serviceProvider.GetService(typeof(SComponentModel)));
|
||||
var exportProvider = componentModel.DefaultExportProvider;
|
||||
return exportProvider.GetExportedValue<T>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Export(typeof(IServiceProvider))]
|
||||
[PartCreationPolicy(CreationPolicy.Shared)]
|
||||
public class MefServiceProvider : IServiceProvider
|
||||
{
|
||||
public ExportProvider ExportProvider { get; set; }
|
||||
|
||||
public object GetService(Type serviceType)
|
||||
{
|
||||
string contract = AttributedModelServices.GetContractName(serviceType);
|
||||
var instance = ExportProvider.GetExportedValues<object>(contract).FirstOrDefault();
|
||||
|
||||
if (instance != null)
|
||||
return instance;
|
||||
|
||||
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture,
|
||||
"Could not locate any instances of contract {0}.", contract));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace GitHub.Exports
|
||||
{
|
||||
[Export]
|
||||
public class ExportFactoryProvider
|
||||
{
|
||||
|
||||
[ImportingConstructor]
|
||||
public ExportFactoryProvider(ICompositionService cc)
|
||||
{
|
||||
cc.SatisfyImportsOnce(this);
|
||||
}
|
||||
|
||||
[Import(AllowRecomposition =true)]
|
||||
public ExportFactory<ILoginDialog> LoginViewModelFactory { get; set; }
|
||||
/*
|
||||
[Import(AllowRecomposition = true)]
|
||||
public ExportFactory<ITwoFactorDialog> TwoFactorViewModelFactory { get; set; }
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
using GitHub.Infrastructure;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.ComponentModel.Composition.Hosting;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace GitHub.VisualStudio.Services
|
||||
{
|
||||
[Export]
|
||||
[PartCreationPolicy(CreationPolicy.Shared)]
|
||||
public class UIProvider
|
||||
{
|
||||
[Import(typeof(IServiceProvider))]
|
||||
public MefServiceProvider ServiceProvider { get; set; }
|
||||
|
||||
public UIProvider()
|
||||
{
|
||||
ModeDetector.OverrideModeDetector(new AppModeDetector());
|
||||
RxApp.MainThreadScheduler = new DispatcherScheduler(Application.Current.Dispatcher);
|
||||
}
|
||||
|
||||
public void EnsureProvider(ExportProvider provider)
|
||||
{
|
||||
if (ServiceProvider.ExportProvider == null)
|
||||
ServiceProvider.ExportProvider = provider;
|
||||
}
|
||||
}
|
||||
|
||||
[Export(typeof(IServiceProvider))]
|
||||
[PartCreationPolicy(CreationPolicy.Shared)]
|
||||
public class MefServiceProvider : IServiceProvider
|
||||
{
|
||||
public ExportProvider ExportProvider { get; set; }
|
||||
|
||||
public object GetService(Type serviceType)
|
||||
{
|
||||
string contract = AttributedModelServices.GetContractName(serviceType);
|
||||
var instance = ExportProvider.GetExportedValues<object>(contract).FirstOrDefault();
|
||||
|
||||
if (instance != null)
|
||||
return instance;
|
||||
|
||||
throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture,
|
||||
"Could not locate any instances of contract {0}.", contract));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,45 +2,46 @@
|
|||
using GitHub.ViewModels;
|
||||
using NullGuard;
|
||||
using ReactiveUI;
|
||||
using GitHub.Exports;
|
||||
|
||||
namespace GitHub.VisualStudio.UI.Views.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for LoginControl.xaml
|
||||
/// </summary>
|
||||
public partial class LoginControl : IViewFor<LoginControlViewModel>
|
||||
public partial class LoginControl : IViewFor<ILoginDialog>
|
||||
{
|
||||
public LoginControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
DataContextChanged += (s, e) => ViewModel = (LoginControlViewModel)e.NewValue;
|
||||
DataContextChanged += (s, e) => ViewModel = (ILoginDialog)e.NewValue;
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
d(this.Bind(ViewModel, vm => vm.UsernameOrEmail, v => v.usernameOrEmailTextBox.Text));
|
||||
d(this.Bind(ViewModel, vm => vm.Password, v => v.passwordTextBox.Text));
|
||||
d(this.BindCommand(ViewModel, vm => vm.LoginCommand, v => v.loginButton));
|
||||
d(this.BindCommand(ViewModel, vm => vm.CancelCommand, v => v.cancelButton));
|
||||
d(this.BindCommand(ViewModel, vm => vm.LoginCmd, v => v.loginButton));
|
||||
d(this.BindCommand(ViewModel, vm => vm.CancelCmd, v => v.cancelButton));
|
||||
});
|
||||
|
||||
VisualStateManager.GoToState(this, "DotCom", true);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(
|
||||
"ViewModel", typeof(LoginControlViewModel), typeof(LoginControl), new PropertyMetadata(null));
|
||||
"ViewModel", typeof(ILoginDialog), typeof(LoginControl), new PropertyMetadata(null));
|
||||
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get { return ViewModel; }
|
||||
set { ViewModel = (LoginControlViewModel)value; }
|
||||
set { ViewModel = (ILoginDialog)value; }
|
||||
}
|
||||
|
||||
public LoginControlViewModel ViewModel
|
||||
public ILoginDialog ViewModel
|
||||
{
|
||||
[return: AllowNull]
|
||||
get { return (LoginControlViewModel)GetValue(ViewModelProperty); }
|
||||
get { return (ILoginDialog)GetValue(ViewModelProperty); }
|
||||
set { SetValue(ViewModelProperty, value); }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using GitHub.ViewModels;
|
||||
using GitHub.Exports;
|
||||
using Microsoft.VisualStudio.PlatformUI;
|
||||
|
||||
namespace GitHub.VisualStudio.UI.Views
|
||||
|
@ -8,7 +8,7 @@ namespace GitHub.VisualStudio.UI.Views
|
|||
/// </summary>
|
||||
public partial class LoginCommandDialog : DialogWindow
|
||||
{
|
||||
public LoginCommandDialog(LoginControlViewModel loginControlViewModel)
|
||||
public LoginCommandDialog(ILoginDialog loginControlViewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
|
|
|
@ -20,5 +20,6 @@
|
|||
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%|" />
|
||||
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="GitHub.App" Path="|GitHub.App|" />
|
||||
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="Rothko" Path="|Rothko|" />
|
||||
<Asset Type="Microsoft.VisualStudio.MefComponent" d:Source="Project" d:ProjectName="GitHub.Exports" Path="|GitHub.Exports|" />
|
||||
</Assets>
|
||||
</PackageManifest>
|
||||
|
|
Загрузка…
Ссылка в новой задаче