Skip to content

Commit

Permalink
Add Avalonia Support (#1025)
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisPulman authored Jul 24, 2023
1 parent 7f31c43 commit 45e67e2
Show file tree
Hide file tree
Showing 50 changed files with 2,234 additions and 105 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ Splat currently supports:
<a href="https://github.com/rlittlesii">Rodney Littles II</a>
<p>Texas, USA</p>
</td>
</tr>
<tr>
<td align="center" valign="top">
<img width="100" height="100" src="https://github.com/dpvreony.png?s=150">
<br>
Expand Down
1 change: 1 addition & 0 deletions src/Directory.build.props
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<AnalysisLevel>latest</AnalysisLevel>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<ImplicitUsings>true</ImplicitUsings>
<LangVersion>latest</LangVersion>

<!-- disable sourcelink on mono, to workaround https://github.com/dotnet/sourcelink/issues/155 -->
<EnableSourceLink Condition=" '$(OS)' != 'Windows_NT' AND '$(MSBuildRuntimeType)' != 'Core' ">false</EnableSourceLink>
Expand Down
61 changes: 61 additions & 0 deletions src/ReactiveUI.Avalonia.Autofac/AvaloniaMixins.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) 2021 .NET Foundation and Contributors. All rights reserved.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using Autofac;
using ReactiveUI;
using Splat;
using Splat.Autofac;

namespace Avalonia.ReactiveUI.Splat
{
/// <summary>
/// Avalonia Mixins.
/// </summary>
public static class AvaloniaMixins
{
/// <summary>
/// Uses the splat with dry ioc.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="containerConfig">The configure.</param>
/// <param name="withResolver">The get resolver.</param>
/// <returns>
/// An App Builder.
/// </returns>
/// <exception cref="System.ArgumentNullException">builder.</exception>
public static AppBuilder UseReactiveUIWithAutofac(this AppBuilder builder, Action<ContainerBuilder> containerConfig, Action<AutofacDependencyResolver>? withResolver = null) =>
builder switch
{
null => throw new ArgumentNullException(nameof(builder)),
_ => builder.UseReactiveUI().AfterPlatformServicesSetup(_ =>
{
if (Locator.CurrentMutable is null)
{
return;
}

if (containerConfig is null)
{
throw new ArgumentNullException(nameof(containerConfig));
}

var builder = new ContainerBuilder();
var autofacResolver = new AutofacDependencyResolver(builder);
Locator.SetLocator(autofacResolver);
builder.RegisterInstance(autofacResolver);
autofacResolver.InitializeReactiveUI();
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
containerConfig(builder);
var container = builder.Build();
autofacResolver.SetLifetimeScope(container);

if (withResolver is not null)
{
withResolver(autofacResolver);
}
})
};
}
}
19 changes: 19 additions & 0 deletions src/ReactiveUI.Avalonia.Autofac/ReactiveUI.Avalonia.Autofac.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0;net7.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\ReactiveUI.Avalonia\*.cs" LinkBase="Avalonia" />
<Compile Include="..\Splat.Autofac\AutofacDependencyResolver.cs" Link="AutofacDependencyResolver.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.0" />
<PackageReference Include="ReactiveUI" Version="19.4.1" />
<PackageReference Include="Autofac" Version="7.*" />
<ProjectReference Include="..\Splat\Splat.csproj" />
</ItemGroup>
</Project>
48 changes: 48 additions & 0 deletions src/ReactiveUI.Avalonia.DryIoc/AvaloniaMixins.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) 2021 .NET Foundation and Contributors. All rights reserved.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using DryIoc;
using ReactiveUI;
using Splat;
using Splat.DryIoc;

namespace Avalonia.ReactiveUI.Splat
{
/// <summary>
/// Avalonia Mixins.
/// </summary>
public static class AvaloniaMixins
{
/// <summary>
/// Uses the splat with dry ioc.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="containerConfig">The configure.</param>
/// <returns>An App Builder.</returns>
public static AppBuilder UseReactiveUIWithDryIoc(this AppBuilder builder, Action<Container> containerConfig) =>
builder switch
{
null => throw new ArgumentNullException(nameof(builder)),
_ => builder.UseReactiveUI().AfterPlatformServicesSetup(_ =>
{
if (Locator.CurrentMutable is null)
{
return;
}

if (containerConfig is null)
{
throw new ArgumentNullException(nameof(containerConfig));
}

var container = new Container();
Locator.CurrentMutable.RegisterConstant(container, typeof(Container));
Locator.SetLocator(new DryIocDependencyResolver(container));
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
containerConfig(container);
})
};
}
}
20 changes: 20 additions & 0 deletions src/ReactiveUI.Avalonia.DryIoc/ReactiveUI.Avalonia.DryIoc.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>netstandard2.0;net6.0;net7.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<Compile Include="..\ReactiveUI.Avalonia\*.cs" LinkBase="Avalonia" />
<Compile Include="..\Splat.DryIoc\DryIocDependencyResolver.cs" Link="DryIocDependencyResolver.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.0" />
<PackageReference Include="ReactiveUI" Version="19.4.1" />
<PackageReference Include="DryIoc.Dll" Version="5.4.1" />
<ProjectReference Include="..\Splat\Splat.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Avalonia;
using Avalonia.ReactiveUI;
using Avalonia.ReactiveUI.Splat;
using DryIoc;
using ReactiveUIDemo;
using Splat;
using Splat.DryIoc;

namespace ReactiveUI.Avalonia.DryIoc1.Tests
{
public class AvaloniaUIThreadTestsDryIoc
{
#if DRYIOC1
[Fact]
public void Test1()
{
DryIocDependencyResolver? container = default;
DryIocDependencyResolver? resolver = default;
AppBuilder.Configure<App>()
.UsePlatformDetect()
.UseReactiveUIWithDIContainer<DryIocDependencyResolver>(() => new(), con => container = con, res => resolver = res)
.LogToTrace()
.SetupWithoutStarting();
Assert.IsType<AvaloniaScheduler>(RxApp.MainThreadScheduler);
Assert.NotNull(container);
Assert.NotNull(resolver);
Assert.IsType<DryIocDependencyResolver>(Locator.Current);
}
#endif
#if DRYIOC2
[Fact]
public void Test2()
{
Container? container = default;
AppBuilder.Configure<App>()
.UsePlatformDetect()
.UseReactiveUIWithDryIoc(con => container = con)
.LogToTrace()
.SetupWithoutStarting();
Assert.IsType<AvaloniaScheduler>(RxApp.MainThreadScheduler);
Assert.NotNull(container);
Assert.IsType<DryIocDependencyResolver>(Locator.Current);
}
#endif
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<NoWarn>$(NoWarn);1591;CA1707;SA1600;SA1601;SA1633;CA2000</NoWarn>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<DefineConstants>$(DefineConstants);DRYIOC1</DefineConstants>
</PropertyGroup>

<ItemGroup>
<AvaloniaXaml Include="..\ReactiveUI.Avalonia.Tests\Mocks\App.axaml" Link="Mocks\App.axaml">
<SubType>Designer</SubType>
</AvaloniaXaml>
<AvaloniaXaml Include="..\ReactiveUI.Avalonia.Tests\Mocks\MainWindow.axaml" Link="Mocks\MainWindow.axaml">
<SubType>Designer</SubType>
</AvaloniaXaml>
<AvaloniaXaml Include="..\ReactiveUI.Avalonia.Tests\Mocks\Views\BarView.axaml" Link="Mocks\Views\BarView.axaml">
<SubType>Designer</SubType>
</AvaloniaXaml>
<AvaloniaXaml Include="..\ReactiveUI.Avalonia.Tests\Mocks\Views\FooView.axaml" Link="Mocks\Views\FooView.axaml">
<SubType>Designer</SubType>
</AvaloniaXaml>
</ItemGroup>

<ItemGroup>
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\App.axaml.cs" Link="Mocks\App.axaml.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\MainWindow.axaml.cs" Link="Mocks\MainWindow.axaml.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\ViewModels\BarViewModel.cs" Link="Mocks\ViewModels\BarViewModel.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\ViewModels\FooViewModel.cs" Link="Mocks\ViewModels\FooViewModel.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\ViewModels\MainWindowViewModel.cs" Link="Mocks\ViewModels\MainWindowViewModel.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\ViewModels\RoutedViewHostPageViewModel.cs" Link="Mocks\ViewModels\RoutedViewHostPageViewModel.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\Views\BarView.axaml.cs" Link="Mocks\Views\BarView.axaml.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\Views\FooView.axaml.cs" Link="Mocks\Views\FooView.axaml.cs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ReactiveUI.Avalonia.DryIoc\ReactiveUI.Avalonia.DryIoc.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Avalonia.Desktop" Version="11.0.0" />
<PackageReference Include="Avalonia.Headless.XUnit" Version="11.0.0" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net7.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<NoWarn>$(NoWarn);1591;CA1707;SA1600;SA1601;SA1633;CA2000</NoWarn>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<DefineConstants>$(DefineConstants);DRYIOC2</DefineConstants>
</PropertyGroup>

<ItemGroup>
<AvaloniaXaml Include="..\ReactiveUI.Avalonia.Tests\Mocks\App.axaml" Link="Mocks\App.axaml">
<SubType>Designer</SubType>
</AvaloniaXaml>
<AvaloniaXaml Include="..\ReactiveUI.Avalonia.Tests\Mocks\MainWindow.axaml" Link="Mocks\MainWindow.axaml">
<SubType>Designer</SubType>
</AvaloniaXaml>
<AvaloniaXaml Include="..\ReactiveUI.Avalonia.Tests\Mocks\Views\BarView.axaml" Link="Mocks\Views\BarView.axaml">
<SubType>Designer</SubType>
</AvaloniaXaml>
<AvaloniaXaml Include="..\ReactiveUI.Avalonia.Tests\Mocks\Views\FooView.axaml" Link="Mocks\Views\FooView.axaml">
<SubType>Designer</SubType>
</AvaloniaXaml>
</ItemGroup>

<ItemGroup>
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\App.axaml.cs" Link="Mocks\App.axaml.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\MainWindow.axaml.cs" Link="Mocks\MainWindow.axaml.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\ViewModels\BarViewModel.cs" Link="Mocks\ViewModels\BarViewModel.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\ViewModels\FooViewModel.cs" Link="Mocks\ViewModels\FooViewModel.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\ViewModels\MainWindowViewModel.cs" Link="Mocks\ViewModels\MainWindowViewModel.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\ViewModels\RoutedViewHostPageViewModel.cs" Link="Mocks\ViewModels\RoutedViewHostPageViewModel.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\Views\BarView.axaml.cs" Link="Mocks\Views\BarView.axaml.cs" />
<Compile Include="..\ReactiveUI.Avalonia.Tests\Mocks\Views\FooView.axaml.cs" Link="Mocks\Views\FooView.axaml.cs" />
</ItemGroup>

<ItemGroup>
<Compile Include="..\ReactiveUI.Avalonia.DryIoc1.Tests\AvaloniaUIThreadTestsDryIoc.cs" Link="AvaloniaUIThreadTestsDryIoc.cs" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ReactiveUI.Avalonia.DryIoc\ReactiveUI.Avalonia.DryIoc.csproj" />
</ItemGroup>

<ItemGroup>
<!--
<ProjectReference Include="..\ReactiveUI.Avalonia.Ninject\ReactiveUI.Avalonia.Ninject.csproj" />
-->
<PackageReference Include="Avalonia.Desktop" Version="11.0.0" />
<PackageReference Include="Avalonia.Headless.XUnit" Version="11.0.0" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.0" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) 2021 .NET Foundation and Contributors. All rights reserved.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using Avalonia;
using Avalonia.ReactiveUI;
using Microsoft.Extensions.DependencyInjection;
using Splat;
using Splat.Microsoft.Extensions.DependencyInjection;

namespace ReactiveUI.Avalonia.Splat
{
/// <summary>
/// Avalonia Mixins.
/// </summary>
public static class AvaloniaMixins
{
/// <summary>
/// Uses the splat with microsoft dependency resolver.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="containerConfig">The configure.</param>
/// <param name="withResolver">The get service provider.</param>
/// <returns>An App Builder.</returns>
public static AppBuilder UseReactiveUIWithMicrosoftDependencyResolver(this AppBuilder builder, Action<IServiceCollection> containerConfig, Action<IServiceProvider?>? withResolver = null) =>
builder switch
{
null => throw new ArgumentNullException(nameof(builder)),
_ => builder.UseReactiveUI().AfterPlatformServicesSetup(_ =>
{
if (Locator.CurrentMutable is null)
{
return;
}

if (containerConfig is null)
{
throw new ArgumentNullException(nameof(containerConfig));
}

IServiceCollection serviceCollection = new ServiceCollection();
Locator.CurrentMutable.RegisterConstant(serviceCollection, typeof(IServiceCollection));
Locator.SetLocator(new MicrosoftDependencyResolver(serviceCollection));
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
containerConfig(serviceCollection);
var serviceProvider = serviceCollection.BuildServiceProvider();
if (Locator.Current is MicrosoftDependencyResolver resolver)
{
resolver.UpdateContainer(serviceProvider);
}
else
{
Locator.SetLocator(new MicrosoftDependencyResolver(serviceProvider));
}

if (withResolver is not null)
{
withResolver(serviceProvider);
}
})
};
}
}
Loading

0 comments on commit 45e67e2

Please sign in to comment.