mirror of https://github.com/AMT-Cheif/Stylet.git
Merge branch 'release/1.3.6'
This commit is contained in:
commit
5e97f9e1ea
|
@ -0,0 +1,2 @@
|
||||||
|
ko_fi: canton7
|
||||||
|
custom: ['https://www.paypal.com/donate?hosted_button_id=92FADFBYS42MU']
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
name: Report a bug
|
||||||
|
about: If you've definitely found something wrong, use this. Not sure? Open a discussion.
|
||||||
|
---
|
||||||
|
|
||||||
|
**Description**
|
||||||
|
A clear and concise description of what the bug is. Use screenshots as necessary.
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
Code to reproduce the bug, which someone else can run.
|
||||||
|
|
||||||
|
**Version Info**
|
||||||
|
- Stylet version: [e.g. 1.2.3]
|
||||||
|
- Runtime version: [e.g. 5.0.300]
|
||||||
|
|
||||||
|
**Additional Info**
|
||||||
|
Add any other context about the problem here.
|
|
@ -0,0 +1,5 @@
|
||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Open a Discussion
|
||||||
|
url: https://github.com/canton7/stylet/discussions/new
|
||||||
|
about: If you've got a question, suggestion, or something you're not sure about, please open a discussion.
|
|
@ -0,0 +1,9 @@
|
||||||
|
**Checklist**
|
||||||
|
|
||||||
|
Thanks for contributing! Before we start, there are a few things we need to check:
|
||||||
|
|
||||||
|
1. This Pull Request has a corresponding Issue.
|
||||||
|
2. You've discussed your intention to work on this feature/bug fix.
|
||||||
|
3. This feature branch is based on develop (**not** master). The bar above should say "base: develop".
|
||||||
|
|
||||||
|
Thanks!
|
|
@ -12,10 +12,10 @@ namespace Bootstrappers
|
||||||
{
|
{
|
||||||
private IContainer container;
|
private IContainer container;
|
||||||
|
|
||||||
private object _rootViewModel;
|
private TRootViewModel _rootViewModel;
|
||||||
protected virtual object RootViewModel
|
protected virtual TRootViewModel RootViewModel
|
||||||
{
|
{
|
||||||
get { return this._rootViewModel ?? (this._rootViewModel = this.GetInstance(typeof(TRootViewModel))); }
|
get { return this._rootViewModel ?? (this._rootViewModel = (TRootViewModel)this.GetInstance(typeof(TRootViewModel))); }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ConfigureBootstrapper()
|
protected override void ConfigureBootstrapper()
|
||||||
|
@ -43,7 +43,9 @@ namespace Bootstrappers
|
||||||
builder.RegisterType<WindowManager>().As<IWindowManager>().SingleInstance();
|
builder.RegisterType<WindowManager>().As<IWindowManager>().SingleInstance();
|
||||||
builder.RegisterType<EventAggregator>().As<IEventAggregator>().SingleInstance();
|
builder.RegisterType<EventAggregator>().As<IEventAggregator>().SingleInstance();
|
||||||
builder.RegisterType<MessageBoxViewModel>().As<IMessageBoxViewModel>().ExternallyOwned(); // Not singleton!
|
builder.RegisterType<MessageBoxViewModel>().As<IMessageBoxViewModel>().ExternallyOwned(); // Not singleton!
|
||||||
builder.RegisterAssemblyTypes(this.GetType().Assembly).ExternallyOwned();
|
|
||||||
|
// See https://github.com/canton7/Stylet/discussions/211
|
||||||
|
builder.RegisterAssemblyTypes(this.GetType().Assembly).Where(x => !x.Name.Contains("ProcessedByFody")).ExternallyOwned();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -9,8 +9,9 @@
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
<RootNamespace>Bootstrappers</RootNamespace>
|
<RootNamespace>Bootstrappers</RootNamespace>
|
||||||
<AssemblyName>Bootstrappers</AssemblyName>
|
<AssemblyName>Bootstrappers</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
@ -30,42 +31,7 @@
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Autofac, Version=4.2.1.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
|
|
||||||
<HintPath>packages\Autofac.4.2.1\lib\net45\Autofac.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Castle.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
|
|
||||||
<HintPath>packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Castle.Windsor">
|
|
||||||
<HintPath>packages\Castle.Windsor.3.3.0\lib\net45\Castle.Windsor.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Practices.Unity">
|
|
||||||
<HintPath>packages\Unity.3.5.1404.0\lib\net45\Microsoft.Practices.Unity.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Practices.Unity.Configuration">
|
|
||||||
<HintPath>packages\Unity.3.5.1404.0\lib\net45\Microsoft.Practices.Unity.Configuration.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Practices.Unity.RegistrationByConvention">
|
|
||||||
<HintPath>packages\Unity.3.5.1404.0\lib\net45\Microsoft.Practices.Unity.RegistrationByConvention.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Ninject">
|
|
||||||
<HintPath>packages\Ninject.3.2.2.0\lib\net45-full\Ninject.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
|
||||||
<HintPath>packages\NUnit.3.5.0\lib\net45\nunit.framework.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="PresentationFramework" />
|
<Reference Include="PresentationFramework" />
|
||||||
<Reference Include="StructureMap, Version=3.1.6.186, Culture=neutral, processorArchitecture=MSIL">
|
|
||||||
<HintPath>packages\structuremap.3.1.6.186\lib\net40\StructureMap.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="StructureMap.Net4, Version=3.1.6.186, Culture=neutral, processorArchitecture=MSIL">
|
|
||||||
<HintPath>packages\structuremap.3.1.6.186\lib\net40\StructureMap.Net4.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
@ -80,20 +46,19 @@
|
||||||
<Compile Include="NinjectBootstrapper.cs" />
|
<Compile Include="NinjectBootstrapper.cs" />
|
||||||
<Compile Include="NoIoCContainerBootstrapper.cs" />
|
<Compile Include="NoIoCContainerBootstrapper.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="MicrosoftDependencyInjectionBootstrapper.cs" />
|
||||||
<Compile Include="StructureMapBootstrapper.cs" />
|
<Compile Include="StructureMapBootstrapper.cs" />
|
||||||
<Compile Include="Tests\AutofacTests.cs" />
|
<Compile Include="Tests\AutofacTests.cs" />
|
||||||
<Compile Include="Tests\BootstrapperTests.cs" />
|
<Compile Include="Tests\BootstrapperTests.cs" />
|
||||||
<Compile Include="Tests\CastleWindsorTests.cs" />
|
<Compile Include="Tests\CastleWindsorTests.cs" />
|
||||||
<Compile Include="Tests\NinjectTests.cs" />
|
<Compile Include="Tests\NinjectTests.cs" />
|
||||||
<Compile Include="Tests\NoIoCContainerTests.cs" />
|
<Compile Include="Tests\NoIoCContainerTests.cs" />
|
||||||
|
<Compile Include="Tests\MicrosoftDependencyInjectionTests.cs" />
|
||||||
<Compile Include="Tests\StructureMapTests.cs" />
|
<Compile Include="Tests\StructureMapTests.cs" />
|
||||||
<Compile Include="Tests\StubType.cs" />
|
<Compile Include="Tests\StubType.cs" />
|
||||||
<Compile Include="Tests\UnityTests.cs" />
|
<Compile Include="Tests\UnityTests.cs" />
|
||||||
<Compile Include="UnityBootstrapper.cs" />
|
<Compile Include="UnityBootstrapper.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<None Include="packages.config" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -14,10 +14,10 @@ namespace Bootstrappers
|
||||||
{
|
{
|
||||||
private IWindsorContainer container;
|
private IWindsorContainer container;
|
||||||
|
|
||||||
private object _rootViewModel;
|
private TRootViewModel _rootViewModel;
|
||||||
protected virtual object RootViewModel
|
protected virtual TRootViewModel RootViewModel
|
||||||
{
|
{
|
||||||
get { return this._rootViewModel ?? (this._rootViewModel = this.GetInstance(typeof(TRootViewModel))); }
|
get { return this._rootViewModel ?? (this._rootViewModel = (TRootViewModel)this.GetInstance(typeof(TRootViewModel))); }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ConfigureBootstrapper()
|
protected override void ConfigureBootstrapper()
|
||||||
|
@ -39,7 +39,7 @@ namespace Bootstrappers
|
||||||
};
|
};
|
||||||
|
|
||||||
// Stylet does its own disposal of ViewModels: Castle Windsor shouldn't be doing the same
|
// Stylet does its own disposal of ViewModels: Castle Windsor shouldn't be doing the same
|
||||||
// Castle Windsor seems to be ver opinionated on this point, insisting that the container
|
// Castle Windsor seems to be very opinionated on this point, insisting that the container
|
||||||
// should be responsible for disposing all components. This is at odds with Stylet's approach
|
// should be responsible for disposing all components. This is at odds with Stylet's approach
|
||||||
// (and indeed common sense).
|
// (and indeed common sense).
|
||||||
#pragma warning disable CS0618 // Type or member is obsolete
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
using Autofac;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Stylet;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Bootstrappers
|
||||||
|
{
|
||||||
|
public class MicrosoftDependencyInjectionBootstrapper<TRootViewModel> : BootstrapperBase where TRootViewModel : class
|
||||||
|
{
|
||||||
|
private ServiceProvider serviceProvider;
|
||||||
|
|
||||||
|
private TRootViewModel _rootViewModel;
|
||||||
|
protected virtual TRootViewModel RootViewModel
|
||||||
|
{
|
||||||
|
get { return this._rootViewModel ?? (this._rootViewModel = (TRootViewModel)this.GetInstance(typeof(TRootViewModel))); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IServiceProvider ServiceProvider
|
||||||
|
{
|
||||||
|
get { return this.serviceProvider; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ConfigureBootstrapper()
|
||||||
|
{
|
||||||
|
var services = new ServiceCollection();
|
||||||
|
this.DefaultConfigureIoC(services);
|
||||||
|
this.ConfigureIoC(services);
|
||||||
|
this.serviceProvider = services.BuildServiceProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Carries out default configuration of the IoC container. Override if you don't want to do this
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void DefaultConfigureIoC(IServiceCollection services)
|
||||||
|
{
|
||||||
|
var viewManagerConfig = new ViewManagerConfig()
|
||||||
|
{
|
||||||
|
ViewFactory = this.GetInstance,
|
||||||
|
ViewAssemblies = new List<Assembly>() { this.GetType().Assembly }
|
||||||
|
};
|
||||||
|
|
||||||
|
services.AddSingleton<IViewManager>(new ViewManager(viewManagerConfig));
|
||||||
|
services.AddTransient<MessageBoxView>();
|
||||||
|
|
||||||
|
services.AddSingleton<IWindowManagerConfig>(this);
|
||||||
|
services.AddSingleton<IWindowManager, WindowManager>();
|
||||||
|
services.AddSingleton<IEventAggregator, EventAggregator>();
|
||||||
|
services.AddTransient<IMessageBoxViewModel, MessageBoxViewModel>(); // Not singleton!
|
||||||
|
// Also need a factory
|
||||||
|
services.AddSingleton<Func<IMessageBoxViewModel>>(() => new MessageBoxViewModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Override to add your own types to the IoC container.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void ConfigureIoC(IServiceCollection services) { }
|
||||||
|
|
||||||
|
public override object GetInstance(Type type)
|
||||||
|
{
|
||||||
|
return this.serviceProvider.GetRequiredService(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Launch()
|
||||||
|
{
|
||||||
|
base.DisplayRootView(this.RootViewModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
base.Dispose();
|
||||||
|
|
||||||
|
ScreenExtensions.TryDispose(this._rootViewModel);
|
||||||
|
if (this.serviceProvider != null)
|
||||||
|
this.serviceProvider.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,10 +11,10 @@ namespace Bootstrappers
|
||||||
{
|
{
|
||||||
private IKernel kernel;
|
private IKernel kernel;
|
||||||
|
|
||||||
private object _rootViewModel;
|
private TRootViewModel _rootViewModel;
|
||||||
protected virtual object RootViewModel
|
protected virtual TRootViewModel RootViewModel
|
||||||
{
|
{
|
||||||
get { return this._rootViewModel ?? (this._rootViewModel = this.GetInstance(typeof(TRootViewModel))); }
|
get { return this._rootViewModel ?? (this._rootViewModel = (TRootViewModel)this.GetInstance(typeof(TRootViewModel))); }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ConfigureBootstrapper()
|
protected override void ConfigureBootstrapper()
|
||||||
|
|
|
@ -12,10 +12,10 @@ namespace Bootstrappers
|
||||||
{
|
{
|
||||||
private IContainer container;
|
private IContainer container;
|
||||||
|
|
||||||
private object _rootViewModel;
|
private TRootViewModel _rootViewModel;
|
||||||
protected virtual object RootViewModel
|
protected virtual TRootViewModel RootViewModel
|
||||||
{
|
{
|
||||||
get { return this._rootViewModel ?? (this._rootViewModel = this.GetInstance(typeof(TRootViewModel))); }
|
get { return this._rootViewModel ?? (this._rootViewModel = (TRootViewModel)this.GetInstance(typeof(TRootViewModel))); }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ConfigureBootstrapper()
|
protected override void ConfigureBootstrapper()
|
||||||
|
|
|
@ -159,6 +159,9 @@ namespace Bootstrappers.Tests
|
||||||
[Test]
|
[Test]
|
||||||
public void DoesNotDisposeTransientInstances()
|
public void DoesNotDisposeTransientInstances()
|
||||||
{
|
{
|
||||||
|
if (!this.Autobinds)
|
||||||
|
Assert.Ignore("Autobinding not supported");
|
||||||
|
|
||||||
StubType.Reset();
|
StubType.Reset();
|
||||||
|
|
||||||
var vm = this.bootstrapper.GetInstance(typeof(StubType));
|
var vm = this.bootstrapper.GetInstance(typeof(StubType));
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
using Autofac;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bootstrappers.Tests
|
||||||
|
{
|
||||||
|
public class MyMicrosoftDependencyInjectionBootstrapper : MicrosoftDependencyInjectionBootstrapper<TestRootViewModel>, ITestBootstrapper
|
||||||
|
{
|
||||||
|
public List<string> ConfigureLog { get; set; }
|
||||||
|
|
||||||
|
public int DisposeCount { get; private set; }
|
||||||
|
|
||||||
|
public MyMicrosoftDependencyInjectionBootstrapper()
|
||||||
|
{
|
||||||
|
this.ConfigureLog = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Configure()
|
||||||
|
{
|
||||||
|
base.Configure();
|
||||||
|
this.ConfigureLog.Add("Configure");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DefaultConfigureIoC(IServiceCollection services)
|
||||||
|
{
|
||||||
|
base.DefaultConfigureIoC(services);
|
||||||
|
this.ConfigureLog.Add("DefaultConfigureIoC");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ConfigureIoC(IServiceCollection services)
|
||||||
|
{
|
||||||
|
base.ConfigureIoC(services);
|
||||||
|
this.ConfigureLog.Add("ConfigureIoC");
|
||||||
|
}
|
||||||
|
|
||||||
|
public new object GetInstance(Type type)
|
||||||
|
{
|
||||||
|
return base.GetInstance(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void ConfigureBootstrapper()
|
||||||
|
{
|
||||||
|
base.ConfigureBootstrapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
base.Dispose();
|
||||||
|
this.DisposeCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestFixture(Category = "ServiceCollection")]
|
||||||
|
public class MicrosoftDependencyInjectionTests : BootstrapperTests<MyMicrosoftDependencyInjectionBootstrapper>
|
||||||
|
{
|
||||||
|
public MicrosoftDependencyInjectionTests()
|
||||||
|
{
|
||||||
|
this.Autobinds = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override MyMicrosoftDependencyInjectionBootstrapper CreateBootstrapper()
|
||||||
|
{
|
||||||
|
return new MyMicrosoftDependencyInjectionBootstrapper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,10 +11,10 @@ namespace Bootstrappers
|
||||||
{
|
{
|
||||||
private IUnityContainer container;
|
private IUnityContainer container;
|
||||||
|
|
||||||
private object _rootViewModel;
|
private TRootViewModel _rootViewModel;
|
||||||
protected virtual object RootViewModel
|
protected virtual TRootViewModel RootViewModel
|
||||||
{
|
{
|
||||||
get { return this._rootViewModel ?? (this._rootViewModel = this.GetInstance(typeof(TRootViewModel))); }
|
get { return this._rootViewModel ?? (this._rootViewModel = (TRootViewModel)this.GetInstance(typeof(TRootViewModel))); }
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ConfigureBootstrapper()
|
protected override void ConfigureBootstrapper()
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<packages>
|
|
||||||
<package id="Autofac" version="4.2.1" targetFramework="net45" />
|
|
||||||
<package id="Castle.Core" version="3.3.3" targetFramework="net45" />
|
|
||||||
<package id="Castle.Windsor" version="3.3.0" targetFramework="net45" />
|
|
||||||
<package id="Ninject" version="3.2.2.0" targetFramework="net45" />
|
|
||||||
<package id="NUnit" version="3.5.0" targetFramework="net45" />
|
|
||||||
<package id="NUnit3TestAdapter" version="3.6.0" targetFramework="net45" />
|
|
||||||
<package id="structuremap" version="3.1.6.186" targetFramework="net45" />
|
|
||||||
<package id="Unity" version="3.5.1404.0" targetFramework="net45" />
|
|
||||||
</packages>
|
|
|
@ -1,6 +1,20 @@
|
||||||
Stylet Changelog
|
Stylet Changelog
|
||||||
================
|
================
|
||||||
|
|
||||||
|
v1.3.6
|
||||||
|
------
|
||||||
|
|
||||||
|
- If an Action returns a Task, await it in an `async void` method (#53)
|
||||||
|
- Allow Actions to have explicit targets (`{s:Action ..., Target=...}`) (#177)
|
||||||
|
- Allow Actions to invoke static methods (#177)
|
||||||
|
- Actions: if the target does not implement `INotifyPropertyChanged`, still try and evaluate guard properties (#214)
|
||||||
|
- Add an extra layer to the bootstrapper class hierarchy between `BootstrapperBase` and `Bootstrapper<T>`,
|
||||||
|
for people who don't have a root ViewModel
|
||||||
|
- Allow starting the Bootstrapper without an Application (#206)
|
||||||
|
- Expose SynchronousDispatcher and ApplicationDispatcher to assign to `Execute.Dispatcher` (#217)
|
||||||
|
- Improve the sample bootstrappers (fix Autofac, add Microsoft.Services.DependencyInjection)
|
||||||
|
- Improve samples
|
||||||
|
|
||||||
v1.3.5
|
v1.3.5
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
11
Rakefile
11
Rakefile
|
@ -19,21 +19,20 @@ directory COVERAGE_DIR
|
||||||
|
|
||||||
desc "Build the project using the current CONFIG (or Debug)"
|
desc "Build the project using the current CONFIG (or Debug)"
|
||||||
task :build do
|
task :build do
|
||||||
# https://github.com/novotnyllc/MSBuildSdkExtras/pull/249
|
sh 'dotnet', 'build', '-c', CONFIG, CSPROJ
|
||||||
sh 'dotnet', 'build', '-c', CONFIG, CSPROJ, '/nowarn:MSB4011'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Run unit tests using the current CONFIG (or Debug)"
|
desc "Run unit tests using the current CONFIG (or Debug)"
|
||||||
task :test do
|
task :test do
|
||||||
sh 'dotnet', 'test', '-c', CONFIG, UNIT_TESTS, '/nowarn:MSB4011'
|
sh 'dotnet', 'test', '-c', CONFIG, UNIT_TESTS
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Create NuGet package"
|
desc "Create NuGet package"
|
||||||
task :package do
|
task :package do
|
||||||
# Not sure why these have to be this way around, but they do
|
# Not sure why these have to be this way around, but they do
|
||||||
sh 'dotnet', 'pack', '--no-build', '-c', CONFIG, CSPROJ, "-p:NuSpecFile=../#{NUSPEC_START}", '/nowarn:MSB4011'
|
sh 'dotnet', 'pack', '--no-build', '-c', CONFIG, CSPROJ, "-p:NuSpecFile=../#{NUSPEC_START}"
|
||||||
sh 'dotnet', 'pack', '--no-build', '-c', CONFIG, CSPROJ, '-p:IncludeSymbols=true', '/nowarn:MSB4011'
|
sh 'dotnet', 'pack', '--no-build', '-c', CONFIG, CSPROJ, '-p:IncludeSymbols=true'
|
||||||
sh 'dotnet', 'pack', '-c', CONFIG, TEMPLATES_CSPROJ, '/nowarn:MSB4011'
|
sh 'dotnet', 'pack', '-c', CONFIG, TEMPLATES_CSPROJ
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Bump version number"
|
desc "Bump version number"
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|
||||||
<Grid DockPanel.Dock="Bottom">
|
<Grid DockPanel.Dock="Bottom">
|
||||||
<Button HorizontalAlignment="Left" Width="100" IsDefault="True" Command="{s:Action Close}">Save</Button>
|
<Button HorizontalAlignment="Left" Width="100" IsDefault="True" Command="{s:Action Save}">Save</Button>
|
||||||
<Button HorizontalAlignment="Right" Width="100" IsCancel="True">Cancel</Button>
|
<Button HorizontalAlignment="Right" Width="100" IsCancel="True">Cancel</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|
|
@ -15,5 +15,10 @@ namespace Stylet.Samples.HelloDialog
|
||||||
{
|
{
|
||||||
this.RequestClose(null);
|
this.RequestClose(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
this.RequestClose(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,9 @@ namespace Stylet.Samples.HelloDialog
|
||||||
this.NameString = "Click the button to show the dialog";
|
this.NameString = "Click the button to show the dialog";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowDialog()
|
public async System.Threading.Tasks.Task ShowDialog()
|
||||||
{
|
{
|
||||||
|
throw new Exception("KABLAMMO");
|
||||||
var dialogVm = this.dialogFactory.CreateDialog1();
|
var dialogVm = this.dialogFactory.CreateDialog1();
|
||||||
var result = this.windowManager.ShowDialog(dialogVm);
|
var result = this.windowManager.ShowDialog(dialogVm);
|
||||||
if (result.GetValueOrDefault())
|
if (result.GetValueOrDefault())
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,13 @@
|
||||||
|
<Application x:Class="Stylet.Samples.NavigationController.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="clr-namespace:Stylet.Samples.NavigationController"
|
||||||
|
xmlns:s="https://github.com/canton7/Stylet">
|
||||||
|
<Application.Resources>
|
||||||
|
<s:ApplicationLoader>
|
||||||
|
<s:ApplicationLoader.Bootstrapper>
|
||||||
|
<local:Bootstrapper />
|
||||||
|
</s:ApplicationLoader.Bootstrapper>
|
||||||
|
</s:ApplicationLoader>
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
|
@ -0,0 +1,17 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Configuration;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace Stylet.Samples.NavigationController
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for App.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using Stylet;
|
||||||
|
using StyletIoC;
|
||||||
|
using Stylet.Samples.NavigationController.Pages;
|
||||||
|
|
||||||
|
namespace Stylet.Samples.NavigationController
|
||||||
|
{
|
||||||
|
public class Bootstrapper : Bootstrapper<ShellViewModel>
|
||||||
|
{
|
||||||
|
protected override void ConfigureIoC(IStyletIoCBuilder builder)
|
||||||
|
{
|
||||||
|
builder.Bind<NavigationController>().And<INavigationController>().To<NavigationController>().InSingletonScope();
|
||||||
|
// https://github.com/canton7/Stylet/issues/24
|
||||||
|
builder.Bind<Func<Page1ViewModel>>().ToFactory<Func<Page1ViewModel>>(c => () => c.Get<Page1ViewModel>());
|
||||||
|
builder.Bind<Func<Page2ViewModel>>().ToFactory<Func<Page2ViewModel>>(c => () => c.Get<Page2ViewModel>());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnLaunch()
|
||||||
|
{
|
||||||
|
// There's a circular dependency, where ShellViewModel -> HeaderViewModel -> NavigationController -> ShellViewModel
|
||||||
|
// We break this by assigning the ShellViewModel to the NavigationController after constructing it
|
||||||
|
var navigationController = this.Container.Get<NavigationController>();
|
||||||
|
navigationController.Delegate = this.RootViewModel;
|
||||||
|
navigationController.NavigateToPage1();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
using Stylet.Samples.NavigationController.Pages;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Stylet.Samples.NavigationController
|
||||||
|
{
|
||||||
|
public interface INavigationController
|
||||||
|
{
|
||||||
|
void NavigateToPage1();
|
||||||
|
void NavigateToPage2(string initiator);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface INavigationControllerDelegate
|
||||||
|
{
|
||||||
|
void NavigateTo(IScreen screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NavigationController : INavigationController
|
||||||
|
{
|
||||||
|
private readonly Func<Page1ViewModel> page1ViewModelFactory;
|
||||||
|
private readonly Func<Page2ViewModel> page2ViewModelFactory;
|
||||||
|
|
||||||
|
public INavigationControllerDelegate Delegate { get; set; }
|
||||||
|
|
||||||
|
public NavigationController(Func<Page1ViewModel> page1ViewModelFactory, Func<Page2ViewModel> page2ViewModelFactory)
|
||||||
|
{
|
||||||
|
this.page1ViewModelFactory = page1ViewModelFactory ?? throw new ArgumentNullException(nameof(page1ViewModelFactory));
|
||||||
|
this.page2ViewModelFactory = page2ViewModelFactory ?? throw new ArgumentNullException(nameof(page2ViewModelFactory));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NavigateToPage1()
|
||||||
|
{
|
||||||
|
this.Delegate?.NavigateTo(this.page1ViewModelFactory());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NavigateToPage2(string initiator)
|
||||||
|
{
|
||||||
|
var vm = this.page2ViewModelFactory();
|
||||||
|
vm.Initiator = initiator;
|
||||||
|
this.Delegate?.NavigateTo(vm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<UserControl x:Class="Stylet.Samples.NavigationController.Pages.HeaderView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:Stylet.Samples.NavigationController.Pages"
|
||||||
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock>Go to: </TextBlock>
|
||||||
|
<Button Margin="5,0" Command="{s:Action NavigateToPage1}">Page 1</Button>
|
||||||
|
<Button Margin="5,0" Command="{s:Action NavigateToPage2}">Page 2</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,21 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Stylet.Samples.NavigationController.Pages
|
||||||
|
{
|
||||||
|
public class HeaderViewModel : Screen
|
||||||
|
{
|
||||||
|
private readonly INavigationController navigationController;
|
||||||
|
|
||||||
|
public HeaderViewModel(INavigationController navigationController)
|
||||||
|
{
|
||||||
|
this.navigationController = navigationController ?? throw new ArgumentNullException(nameof(navigationController));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NavigateToPage1() => this.navigationController.NavigateToPage1();
|
||||||
|
public void NavigateToPage2() => this.navigationController.NavigateToPage2("the Header");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<UserControl x:Class="Stylet.Samples.NavigationController.Pages.Page1View"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
xmlns:local="clr-namespace:Stylet.Samples.NavigationController.Pages"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
|
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock>This is page 1</TextBlock>
|
||||||
|
<Button Command="{s:Action NavigateToPage2}">Go to page 2</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Stylet.Samples.NavigationController.Pages
|
||||||
|
{
|
||||||
|
public class Page1ViewModel : Screen
|
||||||
|
{
|
||||||
|
private readonly INavigationController navigationController;
|
||||||
|
|
||||||
|
public Page1ViewModel(INavigationController navigationController)
|
||||||
|
{
|
||||||
|
this.navigationController = navigationController ?? throw new ArgumentNullException(nameof(navigationController));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NavigateToPage2() => this.navigationController.NavigateToPage2("Page 1");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
<UserControl x:Class="Stylet.Samples.NavigationController.Pages.Page2View"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
xmlns:local="clr-namespace:Stylet.Samples.NavigationController.Pages"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
|
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock>This is page 2</TextBlock>
|
||||||
|
<TextBlock Text="{Binding Initiator, StringFormat='You got here from {0}'}"/>
|
||||||
|
<Button Command="{s:Action NavigateToPage1}">Go to page 1</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Dynamic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Stylet.Samples.NavigationController.Pages
|
||||||
|
{
|
||||||
|
public class Page2ViewModel : Screen
|
||||||
|
{
|
||||||
|
private readonly INavigationController navigationController;
|
||||||
|
|
||||||
|
private string _initiator;
|
||||||
|
public string Initiator
|
||||||
|
{
|
||||||
|
get => this._initiator;
|
||||||
|
set => this.SetAndNotify(ref this._initiator, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Page2ViewModel(INavigationController navigationController)
|
||||||
|
{
|
||||||
|
this.navigationController = navigationController ?? throw new ArgumentNullException(nameof(navigationController));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NavigateToPage1() => this.navigationController.NavigateToPage1();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<Window x:Class="Stylet.Samples.NavigationController.Pages.ShellView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:Stylet.Samples.NavigationController.Pages"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="Navigation Controller sample" Height="450" Width="800"
|
||||||
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
d:DataContext="{d:DesignInstance local:ShellViewModel}">
|
||||||
|
<DockPanel>
|
||||||
|
<ContentControl DockPanel.Dock="Top" s:View.Model="{Binding HeaderViewModel}"/>
|
||||||
|
<ContentControl s:View.Model="{Binding ActiveItem}"/>
|
||||||
|
</DockPanel>
|
||||||
|
</Window>
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
using Stylet;
|
||||||
|
|
||||||
|
namespace Stylet.Samples.NavigationController.Pages
|
||||||
|
{
|
||||||
|
public class ShellViewModel : Conductor<IScreen>, INavigationControllerDelegate
|
||||||
|
{
|
||||||
|
public HeaderViewModel HeaderViewModel { get; }
|
||||||
|
|
||||||
|
public ShellViewModel(HeaderViewModel headerViewModel)
|
||||||
|
{
|
||||||
|
this.HeaderViewModel = headerViewModel ?? throw new ArgumentNullException(nameof(headerViewModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void NavigateTo(IScreen screen)
|
||||||
|
{
|
||||||
|
this.ActivateItem(screen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Resources;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
// 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("Stylet.Samples.NavigationController")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("Stylet.Samples.NavigationController")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2021")]
|
||||||
|
[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)]
|
||||||
|
|
||||||
|
//In order to begin building localizable applications, set
|
||||||
|
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||||
|
//inside a <PropertyGroup>. For example, if you are using US english
|
||||||
|
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||||
|
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||||
|
//the line below to match the UICulture setting in the project file.
|
||||||
|
|
||||||
|
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||||
|
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// or application resource dictionaries)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// app, or any theme specific resource dictionaries)
|
||||||
|
)]
|
||||||
|
|
||||||
|
|
||||||
|
// 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")]
|
70
Samples/Stylet.Samples.NavigationController/Properties/Resources.Designer.cs
generated
Normal file
70
Samples/Stylet.Samples.NavigationController/Properties/Resources.Designer.cs
generated
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
namespace Stylet.Samples.NavigationController.Properties
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources
|
||||||
|
{
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if ((resourceMan == null))
|
||||||
|
{
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Stylet.Samples.NavigationController.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
29
Samples/Stylet.Samples.NavigationController/Properties/Settings.Designer.cs
generated
Normal file
29
Samples/Stylet.Samples.NavigationController/Properties/Settings.Designer.cs
generated
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
namespace Stylet.Samples.NavigationController.Properties
|
||||||
|
{
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
|
||||||
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
|
||||||
|
{
|
||||||
|
|
||||||
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
|
public static Settings Default
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return defaultInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||||
|
<Profiles>
|
||||||
|
<Profile Name="(Default)" />
|
||||||
|
</Profiles>
|
||||||
|
<Settings />
|
||||||
|
</SettingsFile>
|
|
@ -0,0 +1,119 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" 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>{9DEE75AC-6BC1-4375-B6A0-44EAF39FF559}</ProjectGuid>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<RootNamespace>Stylet.Samples.NavigationController</RootNamespace>
|
||||||
|
<AssemblyName>Stylet.Samples.NavigationController</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<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' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<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.Data" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xaml">
|
||||||
|
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="WindowsBase" />
|
||||||
|
<Reference Include="PresentationCore" />
|
||||||
|
<Reference Include="PresentationFramework" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ApplicationDefinition Include="App.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</ApplicationDefinition>
|
||||||
|
<Compile Include="App.xaml.cs">
|
||||||
|
<DependentUpon>App.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Bootstrapper.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="NavigationController.cs" />
|
||||||
|
<Compile Include="Pages\HeaderViewModel.cs" />
|
||||||
|
<Compile Include="Pages\Page1ViewModel.cs" />
|
||||||
|
<Compile Include="Pages\Page2ViewModel.cs" />
|
||||||
|
<Compile Include="Pages\ShellViewModel.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Properties\Settings.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
</Compile>
|
||||||
|
<EmbeddedResource Include="Properties\Resources.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<None Include="Properties\Settings.settings">
|
||||||
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Include="Pages\HeaderView.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Pages\Page1View.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Pages\Page2View.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Pages\ShellView.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Stylet\Stylet.csproj">
|
||||||
|
<Project>{2435bd00-ac12-48b0-ad36-9bab2fdec3f5}</Project>
|
||||||
|
<Name>Stylet</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
|
@ -1,9 +1,9 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 14
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 14.0.23107.0
|
VisualStudioVersion = 16.0.30709.64
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stylet", "..\Stylet\Stylet.csproj", "{2435BD00-AC12-48B0-AD36-9BAB2FDEC3F5}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stylet", "..\Stylet\Stylet.csproj", "{2435BD00-AC12-48B0-AD36-9BAB2FDEC3F5}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stylet.Samples.Hello", "Stylet.Samples.Hello\Stylet.Samples.Hello.csproj", "{6C7FBB21-52AC-4333-A42A-9F5E9D048621}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stylet.Samples.Hello", "Stylet.Samples.Hello\Stylet.Samples.Hello.csproj", "{6C7FBB21-52AC-4333-A42A-9F5E9D048621}"
|
||||||
EndProject
|
EndProject
|
||||||
|
@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stylet.Samples.ModelValidat
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stylet.Samples.DesignMode", "Stylet.Samples.DesignMode\Stylet.Samples.DesignMode.csproj", "{D5225DA1-58ED-42AA-9589-A4F86E7667F7}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stylet.Samples.DesignMode", "Stylet.Samples.DesignMode\Stylet.Samples.DesignMode.csproj", "{D5225DA1-58ED-42AA-9589-A4F86E7667F7}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stylet.Samples.NavigationController", "Stylet.Samples.NavigationController\Stylet.Samples.NavigationController.csproj", "{9DEE75AC-6BC1-4375-B6A0-44EAF39FF559}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -63,8 +65,15 @@ Global
|
||||||
{D5225DA1-58ED-42AA-9589-A4F86E7667F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{D5225DA1-58ED-42AA-9589-A4F86E7667F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{D5225DA1-58ED-42AA-9589-A4F86E7667F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{D5225DA1-58ED-42AA-9589-A4F86E7667F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{D5225DA1-58ED-42AA-9589-A4F86E7667F7}.Release|Any CPU.Build.0 = Release|Any CPU
|
{D5225DA1-58ED-42AA-9589-A4F86E7667F7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{9DEE75AC-6BC1-4375-B6A0-44EAF39FF559}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9DEE75AC-6BC1-4375-B6A0-44EAF39FF559}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9DEE75AC-6BC1-4375-B6A0-44EAF39FF559}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9DEE75AC-6BC1-4375-B6A0-44EAF39FF559}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {A72165C7-7E4E-4336-88FF-BDCC3E300D54}
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -8,14 +8,12 @@ namespace Stylet
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Bootstrapper to be extended by any application which wants to use StyletIoC (the default)
|
/// Bootstrapper to be extended by any application which wants to use StyletIoC (the default)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If you don't have a root ViewModel, you might prefer to override <see cref="StyletIoCBootstrapperBase"/>
|
||||||
|
/// </remarks>
|
||||||
/// <typeparam name="TRootViewModel">Type of the root ViewModel. This will be instantiated and displayed</typeparam>
|
/// <typeparam name="TRootViewModel">Type of the root ViewModel. This will be instantiated and displayed</typeparam>
|
||||||
public abstract class Bootstrapper<TRootViewModel> : BootstrapperBase where TRootViewModel : class
|
public abstract class Bootstrapper<TRootViewModel> : StyletIoCBootstrapperBase where TRootViewModel : class
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the Bootstrapper's IoC container. This is created after ConfigureIoC has been run.
|
|
||||||
/// </summary>
|
|
||||||
protected IContainer Container { get; set; }
|
|
||||||
|
|
||||||
private TRootViewModel _rootViewModel;
|
private TRootViewModel _rootViewModel;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -26,64 +24,6 @@ namespace Stylet
|
||||||
get { return this._rootViewModel ?? (this._rootViewModel = this.Container.Get<TRootViewModel>()); }
|
get { return this._rootViewModel ?? (this._rootViewModel = this.Container.Get<TRootViewModel>()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Overridden from BootstrapperBase, this sets up the IoC container
|
|
||||||
/// </summary>
|
|
||||||
protected override sealed void ConfigureBootstrapper()
|
|
||||||
{
|
|
||||||
var builder = new StyletIoCBuilder();
|
|
||||||
builder.Assemblies = new List<Assembly>(new List<Assembly>() { this.GetType().Assembly });
|
|
||||||
|
|
||||||
// Call DefaultConfigureIoC *after* ConfigureIoIC, so that they can customize builder.Assemblies
|
|
||||||
this.ConfigureIoC(builder);
|
|
||||||
this.DefaultConfigureIoC(builder);
|
|
||||||
|
|
||||||
this.Container = builder.BuildContainer();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Carries out default configuration of StyletIoC. Override if you don't want to do this
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">StyletIoC builder to use to configure the container</param>
|
|
||||||
protected virtual void DefaultConfigureIoC(StyletIoCBuilder builder)
|
|
||||||
{
|
|
||||||
// Mark these as weak-bindings, so the user can replace them if they want
|
|
||||||
var viewManagerConfig = new ViewManagerConfig()
|
|
||||||
{
|
|
||||||
ViewFactory = this.GetInstance,
|
|
||||||
ViewAssemblies = new List<Assembly>() { this.GetType().Assembly }
|
|
||||||
};
|
|
||||||
builder.Bind<ViewManagerConfig>().ToInstance(viewManagerConfig).AsWeakBinding();
|
|
||||||
|
|
||||||
// Bind it to both IViewManager and to itself, so that people can get it with Container.Get<ViewManager>()
|
|
||||||
builder.Bind<IViewManager>().And<ViewManager>().To<ViewManager>().InSingletonScope().AsWeakBinding();
|
|
||||||
|
|
||||||
builder.Bind<IWindowManagerConfig>().ToInstance(this).DisposeWithContainer(false).AsWeakBinding();
|
|
||||||
builder.Bind<IWindowManager>().To<WindowManager>().InSingletonScope().AsWeakBinding();
|
|
||||||
builder.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope().AsWeakBinding();
|
|
||||||
builder.Bind<IMessageBoxViewModel>().To<MessageBoxViewModel>().AsWeakBinding();
|
|
||||||
// Stylet's assembly isn't added to the container, so add this explicitly
|
|
||||||
builder.Bind<MessageBoxView>().ToSelf();
|
|
||||||
|
|
||||||
builder.Autobind();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Override to add your own types to the IoC container.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="builder">StyletIoC builder to use to configure the container</param>
|
|
||||||
protected virtual void ConfigureIoC(IStyletIoCBuilder builder) { }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Given a type, use the IoC container to fetch an instance of it
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">Type to fetch</param>
|
|
||||||
/// <returns>Fetched instance</returns>
|
|
||||||
public override object GetInstance(Type type)
|
|
||||||
{
|
|
||||||
return this.Container.Get(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when the application is launched. Displays the root view.
|
/// Called when the application is launched. Displays the root view.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -97,12 +37,11 @@ namespace Stylet
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override void Dispose()
|
public override void Dispose()
|
||||||
{
|
{
|
||||||
// Dispose the container last
|
|
||||||
base.Dispose();
|
|
||||||
// Don't create the root ViewModel if it doesn't already exist...
|
// Don't create the root ViewModel if it doesn't already exist...
|
||||||
ScreenExtensions.TryDispose(this._rootViewModel);
|
ScreenExtensions.TryDispose(this._rootViewModel);
|
||||||
if (this.Container != null)
|
|
||||||
this.Container.Dispose();
|
// Dispose the container last
|
||||||
|
base.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,13 @@ namespace Stylet
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called by the ApplicationLoader when this bootstrapper is loaded
|
/// Called by the ApplicationLoader when this bootstrapper is loaded
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If you're constructing the bootstrapper yourself, call this manully and pass in the Application
|
||||||
|
/// (probably <see cref="Application.Current"/>). Stylet will start when <see cref="Application.Startup"/>
|
||||||
|
/// is fired. If no Application is available, do not call this but instead call <see cref="Start(string[])"/>.
|
||||||
|
/// (In this case, note that the <see cref="Execute"/> methods will all dispatch synchronously, unless you
|
||||||
|
/// set <see cref="Execute.Dispatcher"/> yourself).
|
||||||
|
/// </remarks>
|
||||||
/// <param name="application">Application within which Stylet is running</param>
|
/// <param name="application">Application within which Stylet is running</param>
|
||||||
public void Setup(Application application)
|
public void Setup(Application application)
|
||||||
{
|
{
|
||||||
|
@ -43,7 +50,7 @@ namespace Stylet
|
||||||
this.Application = application;
|
this.Application = application;
|
||||||
|
|
||||||
// Use the current application's dispatcher for Execute
|
// Use the current application's dispatcher for Execute
|
||||||
Execute.Dispatcher = new DispatcherWrapper(this.Application.Dispatcher);
|
Execute.Dispatcher = new ApplicationDispatcher(this.Application.Dispatcher);
|
||||||
|
|
||||||
this.Application.Startup += (o, e) => this.Start(e.Args);
|
this.Application.Startup += (o, e) => this.Start(e.Args);
|
||||||
// Make life nice for the app - they can handle these by overriding Bootstrapper methods, rather than adding event handlers
|
// Make life nice for the app - they can handle these by overriding Bootstrapper methods, rather than adding event handlers
|
||||||
|
@ -64,6 +71,10 @@ namespace Stylet
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called on Application.Startup, this does everything necessary to start the application
|
/// Called on Application.Startup, this does everything necessary to start the application
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If you're constructing the bootstrapper yourself, and aren't able to call <see cref="Setup(Application)"/>,
|
||||||
|
/// (e.g. because an Application isn't available), you must call this yourself.
|
||||||
|
/// </remarks>
|
||||||
/// <param name="args">Command-line arguments used to start this executable</param>
|
/// <param name="args">Command-line arguments used to start this executable</param>
|
||||||
public virtual void Start(string[] args)
|
public virtual void Start(string[] args)
|
||||||
{
|
{
|
||||||
|
@ -73,9 +84,8 @@ namespace Stylet
|
||||||
|
|
||||||
this.ConfigureBootstrapper();
|
this.ConfigureBootstrapper();
|
||||||
|
|
||||||
// Cater for the unit tests, which can't sensibly stub Application
|
// We allow starting without an application
|
||||||
if (this.Application != null)
|
this.Application?.Resources.Add(View.ViewManagerResourceKey, this.GetInstance(typeof(IViewManager)));
|
||||||
this.Application.Resources.Add(View.ViewManagerResourceKey, this.GetInstance(typeof(IViewManager)));
|
|
||||||
|
|
||||||
this.Configure();
|
this.Configure();
|
||||||
this.Launch();
|
this.Launch();
|
||||||
|
@ -107,7 +117,7 @@ namespace Stylet
|
||||||
/// <returns>The currently-displayed window, or null</returns>
|
/// <returns>The currently-displayed window, or null</returns>
|
||||||
public virtual Window GetActiveWindow()
|
public virtual Window GetActiveWindow()
|
||||||
{
|
{
|
||||||
return this.Application.Windows.OfType<Window>().FirstOrDefault(x => x.IsActive) ?? this.Application.MainWindow;
|
return this.Application?.Windows.OfType<Window>().FirstOrDefault(x => x.IsActive) ?? this.Application?.MainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -16,11 +16,13 @@ namespace Stylet
|
||||||
/// Gets or sets Execute's dispatcher
|
/// Gets or sets Execute's dispatcher
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Should be set to the UI thread's Dispatcher. This is normally done by the Bootstrapper.
|
/// Should be set a <see cref="ApplicationDispatcher"/> wrapping the current application's dispatcher, which is
|
||||||
|
/// normally done by the Bootstrapper. Can also be set to <see cref="SynchronousDispatcher.Instance"/>, or a
|
||||||
|
/// custom <see cref="IDispatcher"/> implementation.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public static IDispatcher Dispatcher
|
public static IDispatcher Dispatcher
|
||||||
{
|
{
|
||||||
get { return _dispatcher ?? (_dispatcher = new SynchronousDispatcher()); }
|
get { return _dispatcher ?? SynchronousDispatcher.Instance; }
|
||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
|
|
||||||
namespace Stylet
|
namespace Stylet
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generalised dispatcher, which can post and send
|
/// Generalised dispatcher, which can post and send.
|
||||||
|
/// Used by <see cref="Execute"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IDispatcher
|
public interface IDispatcher
|
||||||
{
|
{
|
||||||
|
@ -26,43 +28,75 @@ namespace Stylet
|
||||||
bool IsCurrent { get; }
|
bool IsCurrent { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class DispatcherWrapper : IDispatcher
|
/// <summary>
|
||||||
|
/// <see cref="IDispatcher"/> implementation which can dispatch using <see cref="Dispatcher"/>
|
||||||
|
/// </summary>
|
||||||
|
public class ApplicationDispatcher : IDispatcher
|
||||||
{
|
{
|
||||||
private readonly Dispatcher dispatcher;
|
private readonly Dispatcher dispatcher;
|
||||||
|
|
||||||
public DispatcherWrapper(Dispatcher dispatcher)
|
/// <summary>
|
||||||
|
/// Initialises a new instance of the <see cref="ApplicationDispatcher"/> class with the given <see cref="Dispatcher"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dispatcher"><see cref="Dispatcher"/> to use, normally Application.Current.Dispatcher</param>
|
||||||
|
public ApplicationDispatcher(Dispatcher dispatcher)
|
||||||
{
|
{
|
||||||
this.dispatcher = dispatcher;
|
this.dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialises a new instance of the <see cref="ApplicationDispatcher"/> class with the given <see cref="Application"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="application"><see cref="Application"/> to use, normally Application</param>
|
||||||
|
public ApplicationDispatcher(Application application)
|
||||||
|
: this(application?.Dispatcher ?? throw new ArgumentNullException(nameof(application)))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public void Post(Action action)
|
public void Post(Action action)
|
||||||
{
|
{
|
||||||
this.dispatcher.BeginInvoke(action);
|
this.dispatcher.BeginInvoke(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public void Send(Action action)
|
public void Send(Action action)
|
||||||
{
|
{
|
||||||
this.dispatcher.Invoke(action);
|
this.dispatcher.Invoke(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public bool IsCurrent
|
public bool IsCurrent
|
||||||
{
|
{
|
||||||
get { return this.dispatcher.CheckAccess(); }
|
get { return this.dispatcher.CheckAccess(); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class SynchronousDispatcher : IDispatcher
|
/// <summary>
|
||||||
|
/// <see cref="IDispatcher"/> implementation whcih dispatches synchronously.
|
||||||
|
/// Usually used for unit testing.
|
||||||
|
/// </summary>
|
||||||
|
public class SynchronousDispatcher : IDispatcher
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the singleton instance of <see cref="SynchronousDispatcher"/>
|
||||||
|
/// </summary>
|
||||||
|
public static SynchronousDispatcher Instance { get; } = new SynchronousDispatcher();
|
||||||
|
private SynchronousDispatcher() { }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public void Post(Action action)
|
public void Post(Action action)
|
||||||
{
|
{
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public void Send(Action action)
|
public void Send(Action action)
|
||||||
{
|
{
|
||||||
action();
|
action();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
public bool IsCurrent
|
public bool IsCurrent
|
||||||
{
|
{
|
||||||
get { return true; }
|
get { return true; }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="MSBuild.Sdk.Extras/2.1.2">
|
<Project Sdk="MSBuild.Sdk.Extras/3.0.23">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
|
@ -23,16 +23,12 @@
|
||||||
|
|
||||||
<!-- Just embed all sources in the PDB: snupkg files don't support bare .cs files, and SourceLink is annoying -->
|
<!-- Just embed all sources in the PDB: snupkg files don't support bare .cs files, and SourceLink is annoying -->
|
||||||
<!-- We set IncludeSymbols in the Rakefile, because we don't want it to apply to Stylet.Start -->
|
<!-- We set IncludeSymbols in the Rakefile, because we don't want it to apply to Stylet.Start -->
|
||||||
|
<!-- Note that stack traces don't work on < net471, but snupkg only supports portable, so nothing we can do -->
|
||||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||||
<EmbedAllSources>true</EmbedAllSources>
|
<EmbedAllSources>true</EmbedAllSources>
|
||||||
<DebugType>portable</DebugType>
|
<DebugType>portable</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net45' ">
|
|
||||||
<!-- Stack traces on < net471 don't work with portable -->
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' != 'net45'">
|
<ItemGroup Condition="'$(TargetFramework)' != 'net45'">
|
||||||
<PackageReference Include="System.Drawing.Common" Version="4.6.0" />
|
<PackageReference Include="System.Drawing.Common" Version="4.6.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
using StyletIoC;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Stylet
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Bootstrapper to be extended by any application which wants to use StyletIoC, but doesn't have a root ViewModel
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// You would normally use <see cref="Bootstrapper{TRootViewModel}"/>, which lets you specify the root ViewModel
|
||||||
|
/// to display. If you don't want to show a window on startup, override <see cref="BootstrapperBase.Launch"/>
|
||||||
|
/// but don't call <see cref="BootstrapperBase.DisplayRootView(object)"/>.
|
||||||
|
/// </remarks>
|
||||||
|
public abstract class StyletIoCBootstrapperBase : BootstrapperBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the Bootstrapper's IoC container. This is created after ConfigureIoC has been run.
|
||||||
|
/// </summary>
|
||||||
|
protected IContainer Container { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overridden from BootstrapperBase, this sets up the IoC container
|
||||||
|
/// </summary>
|
||||||
|
protected override sealed void ConfigureBootstrapper()
|
||||||
|
{
|
||||||
|
var builder = new StyletIoCBuilder();
|
||||||
|
builder.Assemblies = new List<Assembly>(new List<Assembly>() { this.GetType().Assembly });
|
||||||
|
|
||||||
|
// Call DefaultConfigureIoC *after* ConfigureIoIC, so that they can customize builder.Assemblies
|
||||||
|
this.ConfigureIoC(builder);
|
||||||
|
this.DefaultConfigureIoC(builder);
|
||||||
|
|
||||||
|
this.Container = builder.BuildContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Carries out default configuration of StyletIoC. Override if you don't want to do this
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">StyletIoC builder to use to configure the container</param>
|
||||||
|
protected virtual void DefaultConfigureIoC(StyletIoCBuilder builder)
|
||||||
|
{
|
||||||
|
// Mark these as weak-bindings, so the user can replace them if they want
|
||||||
|
var viewManagerConfig = new ViewManagerConfig()
|
||||||
|
{
|
||||||
|
ViewFactory = this.GetInstance,
|
||||||
|
ViewAssemblies = new List<Assembly>() { this.GetType().Assembly }
|
||||||
|
};
|
||||||
|
builder.Bind<ViewManagerConfig>().ToInstance(viewManagerConfig).AsWeakBinding();
|
||||||
|
|
||||||
|
// Bind it to both IViewManager and to itself, so that people can get it with Container.Get<ViewManager>()
|
||||||
|
builder.Bind<IViewManager>().And<ViewManager>().To<ViewManager>().InSingletonScope().AsWeakBinding();
|
||||||
|
|
||||||
|
builder.Bind<IWindowManagerConfig>().ToInstance(this).DisposeWithContainer(false).AsWeakBinding();
|
||||||
|
builder.Bind<IWindowManager>().To<WindowManager>().InSingletonScope().AsWeakBinding();
|
||||||
|
builder.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope().AsWeakBinding();
|
||||||
|
builder.Bind<IMessageBoxViewModel>().To<MessageBoxViewModel>().AsWeakBinding();
|
||||||
|
// Stylet's assembly isn't added to the container, so add this explicitly
|
||||||
|
builder.Bind<MessageBoxView>().ToSelf();
|
||||||
|
|
||||||
|
builder.Autobind();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Override to add your own types to the IoC container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">StyletIoC builder to use to configure the container</param>
|
||||||
|
protected virtual void ConfigureIoC(IStyletIoCBuilder builder) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Given a type, use the IoC container to fetch an instance of it
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">Type to fetch</param>
|
||||||
|
/// <returns>Fetched instance</returns>
|
||||||
|
public override object GetInstance(Type type)
|
||||||
|
{
|
||||||
|
return this.Container.Get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
||||||
|
/// </summary>
|
||||||
|
public override void Dispose()
|
||||||
|
{
|
||||||
|
base.Dispose();
|
||||||
|
|
||||||
|
// Dispose the container last
|
||||||
|
if (this.Container != null)
|
||||||
|
this.Container.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,9 @@ using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.ExceptionServices;
|
using System.Runtime.ExceptionServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
@ -42,11 +44,12 @@ namespace Stylet.Xaml
|
||||||
protected readonly ActionUnavailableBehaviour ActionNonExistentBehaviour;
|
protected readonly ActionUnavailableBehaviour ActionNonExistentBehaviour;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the object on which methods will be invokced
|
/// Gets the object on which methods will be invoked
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object Target
|
public object Target
|
||||||
{
|
{
|
||||||
get { return this.GetValue(targetProperty); }
|
get { return this.GetValue(targetProperty); }
|
||||||
|
private set { this.SetValue(targetProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly DependencyProperty targetProperty =
|
private static readonly DependencyProperty targetProperty =
|
||||||
|
@ -56,7 +59,7 @@ namespace Stylet.Xaml
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialises a new instance of the <see cref="ActionBase"/> class
|
/// Initialises a new instance of the <see cref="ActionBase"/> class to use <see cref="View.ActionTargetProperty"/> to get the target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="subject">View to grab the View.ActionTarget from</param>
|
/// <param name="subject">View to grab the View.ActionTarget from</param>
|
||||||
/// <param name="backupSubject">Backup subject to use if no ActionTarget could be retrieved from the subject</param>
|
/// <param name="backupSubject">Backup subject to use if no ActionTarget could be retrieved from the subject</param>
|
||||||
|
@ -65,12 +68,9 @@ namespace Stylet.Xaml
|
||||||
/// <param name="actionNonExistentBehaviour">Behaviour for if the action doesn't exist on the View.ActionTarget</param>
|
/// <param name="actionNonExistentBehaviour">Behaviour for if the action doesn't exist on the View.ActionTarget</param>
|
||||||
/// <param name="logger">Logger to use</param>
|
/// <param name="logger">Logger to use</param>
|
||||||
public ActionBase(DependencyObject subject, DependencyObject backupSubject, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour, ILogger logger)
|
public ActionBase(DependencyObject subject, DependencyObject backupSubject, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour, ILogger logger)
|
||||||
|
: this(methodName, targetNullBehaviour, actionNonExistentBehaviour, logger)
|
||||||
{
|
{
|
||||||
this.Subject = subject;
|
this.Subject = subject;
|
||||||
this.MethodName = methodName;
|
|
||||||
this.TargetNullBehaviour = targetNullBehaviour;
|
|
||||||
this.ActionNonExistentBehaviour = actionNonExistentBehaviour;
|
|
||||||
this.logger = logger;
|
|
||||||
|
|
||||||
// If a 'backupSubject' was given, bind both that and 'subject' to this.Target (with a converter which picks the first
|
// If a 'backupSubject' was given, bind both that and 'subject' to this.Target (with a converter which picks the first
|
||||||
// one that isn't View.InitialActionTarget). If it wasn't given, just bind 'subject'.
|
// one that isn't View.InitialActionTarget). If it wasn't given, just bind 'subject'.
|
||||||
|
@ -101,6 +101,31 @@ namespace Stylet.Xaml
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialises a new instance of the <see cref="ActionBase"/> class to use an explicit target
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">Target to find the method on</param>
|
||||||
|
/// <param name="methodName">Method name. the MyMethod in Buttom Command="{s:Action MyMethod}".</param>
|
||||||
|
/// <param name="targetNullBehaviour">Behaviour for it the relevant View.ActionTarget is null</param>
|
||||||
|
/// <param name="actionNonExistentBehaviour">Behaviour for if the action doesn't exist on the View.ActionTarget</param>
|
||||||
|
/// <param name="logger">Logger to use</param>
|
||||||
|
public ActionBase(object target, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour, ILogger logger)
|
||||||
|
: this(methodName, targetNullBehaviour, actionNonExistentBehaviour, logger)
|
||||||
|
{
|
||||||
|
if (target == null)
|
||||||
|
throw new ArgumentNullException(nameof(target));
|
||||||
|
|
||||||
|
this.Target = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ActionBase(string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour, ILogger logger)
|
||||||
|
{
|
||||||
|
this.MethodName = methodName ?? throw new ArgumentNullException(nameof(methodName));
|
||||||
|
this.TargetNullBehaviour = targetNullBehaviour;
|
||||||
|
this.ActionNonExistentBehaviour = actionNonExistentBehaviour;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateActionTarget(object oldTarget, object newTarget)
|
private void UpdateActionTarget(object oldTarget, object newTarget)
|
||||||
{
|
{
|
||||||
MethodInfo targetMethodInfo = null;
|
MethodInfo targetMethodInfo = null;
|
||||||
|
@ -128,13 +153,22 @@ namespace Stylet.Xaml
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var newTargetType = newTarget.GetType();
|
BindingFlags bindingFlags;
|
||||||
|
if (newTarget is Type newTargetType)
|
||||||
|
{
|
||||||
|
bindingFlags = BindingFlags.Public | BindingFlags.Static;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newTargetType = newTarget.GetType();
|
||||||
|
bindingFlags = BindingFlags.Public | BindingFlags.Instance;
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
targetMethodInfo = newTargetType.GetMethod(this.MethodName);
|
targetMethodInfo = newTargetType.GetMethod(this.MethodName, bindingFlags);
|
||||||
|
|
||||||
if (targetMethodInfo == null)
|
if (targetMethodInfo == null)
|
||||||
this.logger.Warn("Unable to find method {0} on {1}", this.MethodName, newTargetType.Name);
|
this.logger.Warn("Unable to find{0} method {1} on {2}", newTarget is Type ? " static" : "", this.MethodName, newTargetType.Name);
|
||||||
else
|
else
|
||||||
this.AssertTargetMethodInfo(targetMethodInfo, newTargetType);
|
this.AssertTargetMethodInfo(targetMethodInfo, newTargetType);
|
||||||
}
|
}
|
||||||
|
@ -156,19 +190,19 @@ namespace Stylet.Xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="targetMethodInfo">MethodInfo of method on new target</param>
|
/// <param name="targetMethodInfo">MethodInfo of method on new target</param>
|
||||||
/// <param name="newTargetType">Type of new target</param>
|
/// <param name="newTargetType">Type of new target</param>
|
||||||
protected internal abstract void AssertTargetMethodInfo(MethodInfo targetMethodInfo, Type newTargetType);
|
private protected abstract void AssertTargetMethodInfo(MethodInfo targetMethodInfo, Type newTargetType);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked when a new target is set, after all other action has been taken
|
/// Invoked when a new target is set, after all other action has been taken
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="oldTarget">Previous target</param>
|
/// <param name="oldTarget">Previous target</param>
|
||||||
/// <param name="newTarget">New target</param>
|
/// <param name="newTarget">New target</param>
|
||||||
protected internal virtual void OnTargetChanged(object oldTarget, object newTarget) { }
|
private protected virtual void OnTargetChanged(object oldTarget, object newTarget) { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Assert that the target is not View.InitialActionTarget
|
/// Assert that the target is not View.InitialActionTarget
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected internal void AssertTargetSet()
|
private protected void AssertTargetSet()
|
||||||
{
|
{
|
||||||
// If we've made it this far and the target is still the default, then something's wrong
|
// If we've made it this far and the target is still the default, then something's wrong
|
||||||
// Make sure they know
|
// Make sure they know
|
||||||
|
@ -183,7 +217,7 @@ namespace Stylet.Xaml
|
||||||
|
|
||||||
if (this.TargetMethodInfo == null && this.ActionNonExistentBehaviour == ActionUnavailableBehaviour.Throw)
|
if (this.TargetMethodInfo == null && this.ActionNonExistentBehaviour == ActionUnavailableBehaviour.Throw)
|
||||||
{
|
{
|
||||||
var ex = new ActionNotFoundException(String.Format("Unable to find method {0} on target {1}", this.MethodName, this.Target.GetType().Name));
|
var ex = new ActionNotFoundException(String.Format("Unable to find method {0} on {1}", this.MethodName, this.TargetName()));
|
||||||
this.logger.Error(ex);
|
this.logger.Error(ex);
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
@ -193,22 +227,37 @@ namespace Stylet.Xaml
|
||||||
/// Invoke the target method with the given parameters
|
/// Invoke the target method with the given parameters
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="parameters">Parameters to pass to the target method</param>
|
/// <param name="parameters">Parameters to pass to the target method</param>
|
||||||
protected internal void InvokeTargetMethod(object[] parameters)
|
private protected void InvokeTargetMethod(object[] parameters)
|
||||||
{
|
{
|
||||||
this.logger.Info("Invoking method {0} on target {1} with parameters ({2})", this.MethodName, this.Target, parameters == null ? "none" : String.Join(", ", parameters));
|
this.logger.Info("Invoking method {0} on {1} with parameters ({2})", this.MethodName, this.TargetName(), parameters == null ? "none" : String.Join(", ", parameters));
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.TargetMethodInfo.Invoke(this.Target, parameters);
|
var target = this.TargetMethodInfo.IsStatic ? null : this.Target;
|
||||||
|
var result = this.TargetMethodInfo.Invoke(target, parameters);
|
||||||
|
// Be nice and make sure that any exceptions get rethrown
|
||||||
|
if (result is Task task)
|
||||||
|
{
|
||||||
|
AwaitTask(task);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (TargetInvocationException e)
|
catch (TargetInvocationException e)
|
||||||
{
|
{
|
||||||
// Be nice and unwrap this for them
|
// Be nice and unwrap this for them
|
||||||
// They want a stack track for their VM method, not us
|
// They want a stack track for their VM method, not us
|
||||||
this.logger.Error(e.InnerException, String.Format("Failed to invoke method {0} on target {1} with parameters ({2})", this.MethodName, this.Target, parameters == null ? "none" : String.Join(", ", parameters)));
|
this.logger.Error(e.InnerException, String.Format("Failed to invoke method {0} on {1} with parameters ({2})", this.MethodName, this.TargetName(), parameters == null ? "none" : String.Join(", ", parameters)));
|
||||||
// http://stackoverflow.com/a/17091351/1086121
|
// http://stackoverflow.com/a/17091351/1086121
|
||||||
ExceptionDispatchInfo.Capture(e.InnerException).Throw();
|
ExceptionDispatchInfo.Capture(e.InnerException).Throw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async void AwaitTask(Task t) => await t;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string TargetName()
|
||||||
|
{
|
||||||
|
return this.Target is Type t
|
||||||
|
? $"static target {t.Name}"
|
||||||
|
: $"target {this.Target.GetType().Name}";
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MultiBindingToActionTargetConverter : IMultiValueConverter
|
private class MultiBindingToActionTargetConverter : IMultiValueConverter
|
||||||
|
|
|
@ -44,6 +44,11 @@ namespace Stylet.Xaml
|
||||||
[ConstructorArgument("method")]
|
[ConstructorArgument("method")]
|
||||||
public string Method { get; set; }
|
public string Method { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a target to override that set with View.ActionTarget
|
||||||
|
/// </summary>
|
||||||
|
public object Target { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the behaviour if the View.ActionTarget is nulil
|
/// Gets or sets the behaviour if the View.ActionTarget is nulil
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -101,15 +106,13 @@ namespace Stylet.Xaml
|
||||||
throw new InvalidOperationException("Method has not been set");
|
throw new InvalidOperationException("Method has not been set");
|
||||||
|
|
||||||
var valueService = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
|
var valueService = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
|
||||||
var rootObjectProvider = (IRootObjectProvider)serviceProvider.GetService(typeof(IRootObjectProvider));
|
|
||||||
var rootObject = rootObjectProvider?.RootObject as DependencyObject;
|
|
||||||
|
|
||||||
switch (valueService.TargetObject)
|
switch (valueService.TargetObject)
|
||||||
{
|
{
|
||||||
case DependencyObject targetObject:
|
case DependencyObject targetObject:
|
||||||
return this.HandleDependencyObject(valueService, targetObject, rootObject);
|
return this.HandleDependencyObject(serviceProvider, valueService, targetObject);
|
||||||
case CommandBinding commandBinding:
|
case CommandBinding commandBinding:
|
||||||
return this.HandleCommandBinding(rootObject, ((EventInfo)valueService.TargetProperty).EventHandlerType);
|
return this.CreateEventAction(serviceProvider, null, ((EventInfo)valueService.TargetProperty).EventHandlerType, isCommandBinding: true);
|
||||||
default:
|
default:
|
||||||
// Seems this is the case when we're in a template. We'll get called again properly in a second.
|
// Seems this is the case when we're in a template. We'll get called again properly in a second.
|
||||||
// http://social.msdn.microsoft.com/Forums/vstudio/en-US/a9ead3d5-a4e4-4f9c-b507-b7a7d530c6a9/gaining-access-to-target-object-instead-of-shareddp-in-custom-markupextensions-providevalue-method?forum=wpf
|
// http://social.msdn.microsoft.com/Forums/vstudio/en-US/a9ead3d5-a4e4-4f9c-b507-b7a7d530c6a9/gaining-access-to-target-object-instead-of-shareddp-in-custom-markupextensions-providevalue-method?forum=wpf
|
||||||
|
@ -117,25 +120,21 @@ namespace Stylet.Xaml
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private object HandleDependencyObject(IProvideValueTarget valueService, DependencyObject targetObject, DependencyObject rootObject)
|
private object HandleDependencyObject(IServiceProvider serviceProvider, IProvideValueTarget valueService, DependencyObject targetObject)
|
||||||
{
|
{
|
||||||
switch (valueService.TargetProperty)
|
switch (valueService.TargetProperty)
|
||||||
{
|
{
|
||||||
case DependencyProperty dependencyProperty when dependencyProperty.PropertyType == typeof(ICommand):
|
case DependencyProperty dependencyProperty when dependencyProperty.PropertyType == typeof(ICommand):
|
||||||
// If they're in design mode and haven't set View.ActionTarget, default to looking sensible
|
// If they're in design mode and haven't set View.ActionTarget, default to looking sensible
|
||||||
return new CommandAction(targetObject, rootObject, this.Method, this.CommandNullTargetBehaviour, this.CommandActionNotFoundBehaviour);
|
return this.CreateCommandAction(serviceProvider, targetObject);
|
||||||
case EventInfo eventInfo:
|
case EventInfo eventInfo:
|
||||||
{
|
return this.CreateEventAction(serviceProvider, targetObject, eventInfo.EventHandlerType);
|
||||||
var ec = new EventAction(targetObject, rootObject, eventInfo.EventHandlerType, this.Method, this.EventNullTargetBehaviour, this.EventActionNotFoundBehaviour);
|
|
||||||
return ec.GetDelegate();
|
|
||||||
}
|
|
||||||
case MethodInfo methodInfo: // For attached events
|
case MethodInfo methodInfo: // For attached events
|
||||||
{
|
{
|
||||||
var parameters = methodInfo.GetParameters();
|
var parameters = methodInfo.GetParameters();
|
||||||
if (parameters.Length == 2 && typeof(Delegate).IsAssignableFrom(parameters[1].ParameterType))
|
if (parameters.Length == 2 && typeof(Delegate).IsAssignableFrom(parameters[1].ParameterType))
|
||||||
{
|
{
|
||||||
var ec = new EventAction(targetObject, rootObject, parameters[1].ParameterType, this.Method, this.EventNullTargetBehaviour, this.EventActionNotFoundBehaviour);
|
return this.CreateEventAction(serviceProvider, targetObject, parameters[1].ParameterType);
|
||||||
return ec.GetDelegate();
|
|
||||||
}
|
}
|
||||||
throw new ArgumentException("Action used with an attached event (or something similar) which didn't follow the normal pattern");
|
throw new ArgumentException("Action used with an attached event (or something similar) which didn't follow the normal pattern");
|
||||||
}
|
}
|
||||||
|
@ -144,12 +143,43 @@ namespace Stylet.Xaml
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private object HandleCommandBinding(DependencyObject rootObject, Type propertyType)
|
private ICommand CreateCommandAction(IServiceProvider serviceProvider, DependencyObject targetObject)
|
||||||
|
{
|
||||||
|
if (this.Target == null)
|
||||||
|
{
|
||||||
|
var rootObjectProvider = (IRootObjectProvider)serviceProvider.GetService(typeof(IRootObjectProvider));
|
||||||
|
var rootObject = rootObjectProvider?.RootObject as DependencyObject;
|
||||||
|
return new CommandAction(targetObject, rootObject, this.Method, this.CommandNullTargetBehaviour, this.CommandActionNotFoundBehaviour);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return new CommandAction(this.Target, this.Method, this.CommandNullTargetBehaviour, this.CommandActionNotFoundBehaviour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Delegate CreateEventAction(IServiceProvider serviceProvider, DependencyObject targetObject, Type eventType, bool isCommandBinding = false)
|
||||||
|
{
|
||||||
|
EventAction ec;
|
||||||
|
if (this.Target == null)
|
||||||
|
{
|
||||||
|
var rootObjectProvider = (IRootObjectProvider)serviceProvider.GetService(typeof(IRootObjectProvider));
|
||||||
|
var rootObject = rootObjectProvider?.RootObject as DependencyObject;
|
||||||
|
if (isCommandBinding)
|
||||||
{
|
{
|
||||||
if (rootObject == null)
|
if (rootObject == null)
|
||||||
throw new InvalidOperationException("Action may only be used with CommandBinding from a XAML view (unable to retrieve IRootObjectProvider.RootObject)");
|
throw new InvalidOperationException("Action may only be used with CommandBinding from a XAML view (unable to retrieve IRootObjectProvider.RootObject)");
|
||||||
|
ec = new EventAction(rootObject, null, eventType, this.Method, this.EventNullTargetBehaviour, this.EventActionNotFoundBehaviour);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ec = new EventAction(targetObject, rootObject, eventType, this.Method, this.EventNullTargetBehaviour, this.EventActionNotFoundBehaviour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ec = new EventAction(this.Target, eventType, this.Method, this.EventNullTargetBehaviour, this.EventActionNotFoundBehaviour);
|
||||||
|
}
|
||||||
|
|
||||||
var ec = new EventAction(rootObject, null, propertyType, this.Method, this.EventNullTargetBehaviour, this.EventActionNotFoundBehaviour);
|
|
||||||
return ec.GetDelegate();
|
return ec.GetDelegate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace Stylet.Xaml
|
||||||
private Func<bool> guardPropertyGetter;
|
private Func<bool> guardPropertyGetter;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialises a new instance of the <see cref="CommandAction"/> class
|
/// Initialises a new instance of the <see cref="CommandAction"/> class to use <see cref="View.ActionTargetProperty"/> to get the target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="subject">View to grab the View.ActionTarget from</param>
|
/// <param name="subject">View to grab the View.ActionTarget from</param>
|
||||||
/// <param name="backupSubject">Backup subject to use if no ActionTarget could be retrieved from the subject</param>
|
/// <param name="backupSubject">Backup subject to use if no ActionTarget could be retrieved from the subject</param>
|
||||||
|
@ -37,6 +37,17 @@ namespace Stylet.Xaml
|
||||||
: base(subject, backupSubject, methodName, targetNullBehaviour, actionNonExistentBehaviour, logger)
|
: base(subject, backupSubject, methodName, targetNullBehaviour, actionNonExistentBehaviour, logger)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialises a new instance of the <see cref="CommandAction"/> class to use an explicit target
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">Target to find the method on</param>
|
||||||
|
/// <param name="methodName">Method name. the MyMethod in Buttom Command="{s:Action MyMethod}".</param>
|
||||||
|
/// <param name="targetNullBehaviour">Behaviour for it the relevant View.ActionTarget is null</param>
|
||||||
|
/// <param name="actionNonExistentBehaviour">Behaviour for if the action doesn't exist on the View.ActionTarget</param>
|
||||||
|
public CommandAction(object target, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour)
|
||||||
|
: base(target, methodName, targetNullBehaviour, actionNonExistentBehaviour, logger)
|
||||||
|
{ }
|
||||||
|
|
||||||
private string GuardName
|
private string GuardName
|
||||||
{
|
{
|
||||||
get { return "Can" + this.MethodName; }
|
get { return "Can" + this.MethodName; }
|
||||||
|
@ -47,7 +58,7 @@ namespace Stylet.Xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="targetMethodInfo">MethodInfo of method on new target</param>
|
/// <param name="targetMethodInfo">MethodInfo of method on new target</param>
|
||||||
/// <param name="newTargetType">Type of new target</param>
|
/// <param name="newTargetType">Type of new target</param>
|
||||||
protected internal override void AssertTargetMethodInfo(MethodInfo targetMethodInfo, Type newTargetType)
|
private protected override void AssertTargetMethodInfo(MethodInfo targetMethodInfo, Type newTargetType)
|
||||||
{
|
{
|
||||||
var methodParameters = targetMethodInfo.GetParameters();
|
var methodParameters = targetMethodInfo.GetParameters();
|
||||||
if (methodParameters.Length > 1)
|
if (methodParameters.Length > 1)
|
||||||
|
@ -63,18 +74,13 @@ namespace Stylet.Xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="oldTarget">Previous target</param>
|
/// <param name="oldTarget">Previous target</param>
|
||||||
/// <param name="newTarget">New target</param>
|
/// <param name="newTarget">New target</param>
|
||||||
protected internal override void OnTargetChanged(object oldTarget, object newTarget)
|
private protected override void OnTargetChanged(object oldTarget, object newTarget)
|
||||||
{
|
{
|
||||||
var oldInpc = oldTarget as INotifyPropertyChanged;
|
if (oldTarget is INotifyPropertyChanged oldInpc)
|
||||||
if (oldInpc != null)
|
|
||||||
PropertyChangedEventManager.RemoveHandler(oldInpc, this.PropertyChangedHandler, this.GuardName);
|
PropertyChangedEventManager.RemoveHandler(oldInpc, this.PropertyChangedHandler, this.GuardName);
|
||||||
|
|
||||||
this.guardPropertyGetter = null;
|
this.guardPropertyGetter = null;
|
||||||
|
var guardPropertyInfo = newTarget?.GetType().GetProperty(this.GuardName);
|
||||||
var inpc = newTarget as INotifyPropertyChanged;
|
|
||||||
if (inpc != null)
|
|
||||||
{
|
|
||||||
var guardPropertyInfo = newTarget.GetType().GetProperty(this.GuardName);
|
|
||||||
if (guardPropertyInfo != null)
|
if (guardPropertyInfo != null)
|
||||||
{
|
{
|
||||||
if (guardPropertyInfo.PropertyType == typeof(bool))
|
if (guardPropertyInfo.PropertyType == typeof(bool))
|
||||||
|
@ -90,7 +96,11 @@ namespace Stylet.Xaml
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.guardPropertyGetter != null)
|
if (this.guardPropertyGetter != null)
|
||||||
|
{
|
||||||
|
if (newTarget is INotifyPropertyChanged inpc)
|
||||||
PropertyChangedEventManager.AddHandler(inpc, this.PropertyChangedHandler, this.GuardName);
|
PropertyChangedEventManager.AddHandler(inpc, this.PropertyChangedHandler, this.GuardName);
|
||||||
|
else
|
||||||
|
logger.Warn("Found guard property {0} for action {1} on target {2}, but the target doesn't implement INotifyPropertyChanged, so changes won't be observed", this.GuardName, this.MethodName, newTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.UpdateCanExecute();
|
this.UpdateCanExecute();
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace Stylet.Xaml
|
||||||
private readonly Type eventHandlerType;
|
private readonly Type eventHandlerType;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialises a new instance of the <see cref="EventAction"/> class
|
/// Initialises a new instance of the <see cref="EventAction"/> classto use <see cref="View.ActionTargetProperty"/> to get the target
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="subject">View whose View.ActionTarget we watch</param>
|
/// <param name="subject">View whose View.ActionTarget we watch</param>
|
||||||
/// <param name="backupSubject">Backup subject to use if no ActionTarget could be retrieved from the subject</param>
|
/// <param name="backupSubject">Backup subject to use if no ActionTarget could be retrieved from the subject</param>
|
||||||
|
@ -33,13 +33,32 @@ namespace Stylet.Xaml
|
||||||
/// <param name="actionNonExistentBehaviour">Behaviour for if the action doesn't exist on the View.ActionTarget</param>
|
/// <param name="actionNonExistentBehaviour">Behaviour for if the action doesn't exist on the View.ActionTarget</param>
|
||||||
public EventAction(DependencyObject subject, DependencyObject backupSubject, Type eventHandlerType, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour)
|
public EventAction(DependencyObject subject, DependencyObject backupSubject, Type eventHandlerType, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour)
|
||||||
: base(subject, backupSubject, methodName, targetNullBehaviour, actionNonExistentBehaviour, logger)
|
: base(subject, backupSubject, methodName, targetNullBehaviour, actionNonExistentBehaviour, logger)
|
||||||
|
{
|
||||||
|
AssertBehaviours(targetNullBehaviour, actionNonExistentBehaviour);
|
||||||
|
this.eventHandlerType = eventHandlerType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialises a new instance of the <see cref="EventAction"/> class to use an explicit target
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target">Target to find the method on</param>
|
||||||
|
/// <param name="eventHandlerType">Type of event handler we're returning a delegate for</param>
|
||||||
|
/// <param name="methodName">The MyMethod in {s:Action MyMethod}, this is what we call when the event's fired</param>
|
||||||
|
/// <param name="targetNullBehaviour">Behaviour for it the relevant View.ActionTarget is null</param>
|
||||||
|
/// <param name="actionNonExistentBehaviour">Behaviour for if the action doesn't exist on the View.ActionTarget</param>
|
||||||
|
public EventAction(object target, Type eventHandlerType, string methodName, ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour)
|
||||||
|
: base(target, methodName, targetNullBehaviour, actionNonExistentBehaviour, logger)
|
||||||
|
{
|
||||||
|
AssertBehaviours(targetNullBehaviour, actionNonExistentBehaviour);
|
||||||
|
this.eventHandlerType = eventHandlerType;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void AssertBehaviours(ActionUnavailableBehaviour targetNullBehaviour, ActionUnavailableBehaviour actionNonExistentBehaviour)
|
||||||
{
|
{
|
||||||
if (targetNullBehaviour == ActionUnavailableBehaviour.Disable)
|
if (targetNullBehaviour == ActionUnavailableBehaviour.Disable)
|
||||||
throw new ArgumentException("Setting NullTarget = Disable is unsupported when used on an Event");
|
throw new ArgumentException("Setting NullTarget = Disable is unsupported when used on an Event");
|
||||||
if (actionNonExistentBehaviour == ActionUnavailableBehaviour.Disable)
|
if (actionNonExistentBehaviour == ActionUnavailableBehaviour.Disable)
|
||||||
throw new ArgumentException("Setting ActionNotFound = Disable is unsupported when used on an Event");
|
throw new ArgumentException("Setting ActionNotFound = Disable is unsupported when used on an Event");
|
||||||
|
|
||||||
this.eventHandlerType = eventHandlerType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -47,14 +66,14 @@ namespace Stylet.Xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="targetMethodInfo">MethodInfo of method on new target</param>
|
/// <param name="targetMethodInfo">MethodInfo of method on new target</param>
|
||||||
/// <param name="newTargetType">Type of new target</param>
|
/// <param name="newTargetType">Type of new target</param>
|
||||||
protected internal override void AssertTargetMethodInfo(MethodInfo targetMethodInfo, Type newTargetType)
|
private protected override void AssertTargetMethodInfo(MethodInfo targetMethodInfo, Type newTargetType)
|
||||||
{
|
{
|
||||||
var methodParameters = targetMethodInfo.GetParameters();
|
var methodParameters = targetMethodInfo.GetParameters();
|
||||||
if (!(methodParameters.Length == 0 ||
|
if (!(methodParameters.Length == 0 ||
|
||||||
(methodParameters.Length == 1 && (typeof(EventArgs).IsAssignableFrom(methodParameters[0].ParameterType) || methodParameters[0].ParameterType == typeof(DependencyPropertyChangedEventArgs))) ||
|
(methodParameters.Length == 1 && (typeof(EventArgs).IsAssignableFrom(methodParameters[0].ParameterType) || methodParameters[0].ParameterType == typeof(DependencyPropertyChangedEventArgs))) ||
|
||||||
(methodParameters.Length == 2 && (typeof(EventArgs).IsAssignableFrom(methodParameters[1].ParameterType) || methodParameters[1].ParameterType == typeof(DependencyPropertyChangedEventArgs)))))
|
(methodParameters.Length == 2 && (typeof(EventArgs).IsAssignableFrom(methodParameters[1].ParameterType) || methodParameters[1].ParameterType == typeof(DependencyPropertyChangedEventArgs)))))
|
||||||
{
|
{
|
||||||
var e = new ActionSignatureInvalidException(String.Format("Method {0} on {1} must have the signatures void Method(), void Method(EventArgsOrSubClass e), or void Method(object sender, EventArgsOrSubClass e)", this.MethodName, newTargetType.Name));
|
var e = new ActionSignatureInvalidException(String.Format("Method {0} on {1} must have the signatures Method(), Method(EventArgsOrSubClass e), or Method(object sender, EventArgsOrSubClass e)", this.MethodName, newTargetType.Name));
|
||||||
logger.Error(e);
|
logger.Error(e);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,6 +126,19 @@ namespace StyletUnitTests
|
||||||
|
|
||||||
Assert.Throws<InvalidOperationException>(() => this.actionExtension.ProvideValue(this.serviceProvider.Object));
|
Assert.Throws<InvalidOperationException>(() => this.actionExtension.ProvideValue(this.serviceProvider.Object));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void OverridesTargetIfSetCommand()
|
||||||
|
{
|
||||||
|
var target = new object();
|
||||||
|
this.actionExtension.Target = target;
|
||||||
|
|
||||||
|
this.provideValueTarget.Setup(x => x.TargetProperty).Returns(Button.CommandProperty);
|
||||||
|
var cmd = (CommandAction)this.actionExtension.ProvideValue(this.serviceProvider.Object);
|
||||||
|
Assert.AreSame(target, cmd.Target);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Can't really test Target on EventAction. Oh well.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using Stylet;
|
using Stylet;
|
||||||
using Stylet.Xaml;
|
using Stylet.Xaml;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace StyletUnitTests
|
namespace StyletUnitTests
|
||||||
|
@ -23,8 +24,11 @@ namespace StyletUnitTests
|
||||||
get { return this._canDoSomethingWithGuard; }
|
get { return this._canDoSomethingWithGuard; }
|
||||||
set { SetAndNotify(ref this._canDoSomethingWithGuard, value); }
|
set { SetAndNotify(ref this._canDoSomethingWithGuard, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool DoSomethingWithGuardCalled;
|
||||||
public void DoSomethingWithGuard()
|
public void DoSomethingWithGuard()
|
||||||
{
|
{
|
||||||
|
this.DoSomethingWithGuardCalled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object DoSomethingArgument;
|
public object DoSomethingArgument;
|
||||||
|
@ -62,6 +66,18 @@ namespace StyletUnitTests
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TargetWithoutInpc
|
||||||
|
{
|
||||||
|
public bool CanDoSomething => false;
|
||||||
|
public void DoSomething() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StaticTarget
|
||||||
|
{
|
||||||
|
public static bool DidSomething;
|
||||||
|
public static void DoSomething() => DidSomething = true;
|
||||||
|
}
|
||||||
|
|
||||||
private DependencyObject subject;
|
private DependencyObject subject;
|
||||||
private Target target;
|
private Target target;
|
||||||
|
|
||||||
|
@ -71,6 +87,7 @@ namespace StyletUnitTests
|
||||||
this.target = new Target();
|
this.target = new Target();
|
||||||
this.subject = new DependencyObject();
|
this.subject = new DependencyObject();
|
||||||
View.SetActionTarget(this.subject, this.target);
|
View.SetActionTarget(this.subject, this.target);
|
||||||
|
StaticTarget.DidSomething = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -171,6 +188,18 @@ namespace StyletUnitTests
|
||||||
Assert.True(eventRaised);
|
Assert.True(eventRaised);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void FetchesGuardPropertyWhenTargetDoesNotImplementInpc()
|
||||||
|
{
|
||||||
|
var target = new TargetWithoutInpc();
|
||||||
|
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
|
||||||
|
bool eventRaised = false;
|
||||||
|
cmd.CanExecuteChanged += (o, e) => eventRaised = true;
|
||||||
|
View.SetActionTarget(this.subject, target);
|
||||||
|
Assert.True(eventRaised);
|
||||||
|
Assert.False(cmd.CanExecute(null));
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void RaisesEventWhenTargetChanges()
|
public void RaisesEventWhenTargetChanges()
|
||||||
{
|
{
|
||||||
|
@ -297,5 +326,29 @@ namespace StyletUnitTests
|
||||||
cmd.Execute(null);
|
cmd.Execute(null);
|
||||||
Assert.IsTrue(this.target.DoSomethingCalled);
|
Assert.IsTrue(this.target.DoSomethingCalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SupportsStaticTargets()
|
||||||
|
{
|
||||||
|
var cmd = new CommandAction(this.subject, null, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
|
||||||
|
View.SetActionTarget(this.subject, typeof(StaticTarget));
|
||||||
|
|
||||||
|
Assert.True(cmd.CanExecute(null));
|
||||||
|
cmd.Execute(null);
|
||||||
|
Assert.True(StaticTarget.DidSomething);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UsesExplicitTarget()
|
||||||
|
{
|
||||||
|
var cmd = new CommandAction(this.target, "DoSomethingWithGuard", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
|
||||||
|
|
||||||
|
Assert.False(cmd.CanExecute(null));
|
||||||
|
this.target.CanDoSomethingWithGuard = true;
|
||||||
|
Assert.True(cmd.CanExecute(null));
|
||||||
|
|
||||||
|
cmd.Execute(null);
|
||||||
|
Assert.True(this.target.DoSomethingWithGuardCalled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,12 @@ namespace StyletUnitTests
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class StaticTarget
|
||||||
|
{
|
||||||
|
public static bool DidSomething;
|
||||||
|
public static void DoSomething() => DidSomething = true;
|
||||||
|
}
|
||||||
|
|
||||||
private DependencyObject subject;
|
private DependencyObject subject;
|
||||||
private Target target;
|
private Target target;
|
||||||
private EventInfo eventInfo;
|
private EventInfo eventInfo;
|
||||||
|
@ -87,6 +93,7 @@ namespace StyletUnitTests
|
||||||
this.eventInfo = typeof(Subject).GetEvent("SimpleEventHandler");
|
this.eventInfo = typeof(Subject).GetEvent("SimpleEventHandler");
|
||||||
this.dependencyChangedEventInfo = typeof(Subject).GetEvent("DependencyChangedEventHandler");
|
this.dependencyChangedEventInfo = typeof(Subject).GetEvent("DependencyChangedEventHandler");
|
||||||
View.SetActionTarget(this.subject, this.target);
|
View.SetActionTarget(this.subject, this.target);
|
||||||
|
StaticTarget.DidSomething = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -269,13 +276,31 @@ namespace StyletUnitTests
|
||||||
{
|
{
|
||||||
var view = new DependencyObject();
|
var view = new DependencyObject();
|
||||||
var backupView = new DependencyObject();
|
var backupView = new DependencyObject();
|
||||||
var cmd = new CommandAction(view, backupView, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
|
var cmd = new EventAction(view, backupView, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
|
||||||
|
|
||||||
View.SetActionTarget(backupView, this.target);
|
View.SetActionTarget(backupView, this.target);
|
||||||
view.SetValue(FrameworkElement.DataContextProperty, this.target);
|
view.SetValue(FrameworkElement.DataContextProperty, this.target);
|
||||||
|
|
||||||
cmd.Execute(null);
|
cmd.GetDelegate().DynamicInvoke(null, null);
|
||||||
Assert.IsTrue(this.target.DoSomethingCalled);
|
Assert.IsTrue(this.target.DoSomethingCalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SupportsStaticTargets()
|
||||||
|
{
|
||||||
|
var cmd = new EventAction(this.subject, null, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
|
||||||
|
View.SetActionTarget(this.subject, typeof(StaticTarget));
|
||||||
|
|
||||||
|
cmd.GetDelegate().DynamicInvoke(null, null);
|
||||||
|
Assert.True(StaticTarget.DidSomething);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UsesExplicitTarget()
|
||||||
|
{
|
||||||
|
var cmd = new EventAction(this.target, this.eventInfo.EventHandlerType, "DoSomething", ActionUnavailableBehaviour.Throw, ActionUnavailableBehaviour.Throw);
|
||||||
|
cmd.GetDelegate().DynamicInvoke(null, null);
|
||||||
|
Assert.True(this.target.DoSomethingCalled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="MSBuild.Sdk.Extras/2.1.2">
|
<Project Sdk="MSBuild.Sdk.Extras/3.0.23">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net5.0-windows</TargetFrameworks>
|
<TargetFrameworks>net472;net5.0-windows</TargetFrameworks>
|
||||||
|
|
||||||
<UseWpf>true</UseWpf>
|
<UseWpf>true</UseWpf>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
|
Loading…
Reference in New Issue