Skip to content
This repository was archived by the owner on Apr 8, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
52ffc2a
Update dependency Projektanker.Icons.Avalonia.FontAwesome to 8.4.0 (#86)
OmidID May 8, 2025
60bc11e
Update dependency Projektanker.Icons.Avalonia to 8.4.0 (#85)
OmidID May 8, 2025
386fc23
Update dependency Projektanker.Icons.Avalonia to v9 (#95)
OmidID May 8, 2025
e550a31
Update dependency Projektanker.Icons.Avalonia.FontAwesome to v9 (#96)
OmidID May 8, 2025
c580506
fix issue of crash when host navigate back (#100)
OmidID Jun 3, 2025
8d2ccec
Update dependency ReactiveUI to 20.3.1 (#99)
OmidID Jun 4, 2025
75e4f92
Update avalonia monorepo to 11.3.1 (#101)
OmidID Jun 6, 2025
519a437
Update dependency Xamarin.AndroidX.Core.SplashScreen to 1.0.1.16 (#102)
OmidID Jun 11, 2025
f75ddbf
Update avalonia monorepo to 11.3.2 (#103)
OmidID Jun 26, 2025
871974e
Update dependency ReactiveUI to 20.4.1 (#104)
OmidID Jul 1, 2025
8bdacfe
Synchronize window title with navigation bar header (#105)
Copilot Jul 2, 2025
6d09690
Update avalonia monorepo to 11.3.4 (#108)
OmidID Aug 18, 2025
315f224
Update dependency Xamarin.AndroidX.Core.SplashScreen to 1.0.1.17 (#109)
OmidID Aug 18, 2025
f4260eb
Update dependency ReactiveUI to v21 (#110)
OmidID Sep 3, 2025
97ba84b
Update avalonia monorepo to 11.3.5 (#111)
OmidID Sep 3, 2025
9bf7c67
Release version 1.3.2.2 - Update package version in csproj and README…
Copilot Sep 3, 2025
04600b9
Merge pull request #114 from AvaloniaInside/main
OmidID Sep 3, 2025
39403ad
chore(deps): update avalonia monorepo to 11.3.6
renovate-bot Sep 13, 2025
4b00757
Merge pull request #115 from AvaloniaInside/renovate/avalonia-monorepo
OmidID Sep 13, 2025
345e7b6
chore(deps): update dependency newtonsoft.json to 13.0.4
renovate-bot Sep 17, 2025
0a7ac66
Merge pull request #116 from AvaloniaInside/renovate/newtonsoft.json-…
OmidID Sep 18, 2025
195e65d
chore(deps): update avalonia monorepo to 11.3.7
renovate-bot Oct 4, 2025
9ed6a3f
Merge pull request #117 from AvaloniaInside/renovate/avalonia-monorepo
OmidID Oct 6, 2025
dc344ef
chore(deps): update avalonia monorepo to 11.3.8
renovate-bot Oct 24, 2025
2b0f15a
Merge pull request #119 from AvaloniaInside/renovate/avalonia-monorepo
OmidID Oct 24, 2025
053575c
chore(deps): update avalonia monorepo to 11.3.9
renovate-bot Nov 19, 2025
20e221a
Merge pull request #120 from AvaloniaInside/renovate/avalonia-monorepo
OmidID Nov 19, 2025
be40b71
Update Avalonia.ReactiveUI to ReactiveUI.Avalonia
Mateusz-Nejman Nov 22, 2025
75ffc47
migrate to Avalonia 11.3.12
OmidID Feb 20, 2026
9ddb734
Merge pull request #126 from AvaloniaInside/migrate/avalonia-11.3.12
OmidID Feb 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ We welcome feedback, suggestions, and contributions from anyone who is intereste
To use AvaloniaInside.Shell in your Avalonia project, you can install the package via NuGet using the following command in the Package Manager Console:

```bash
dotnet add package AvaloniaInside.Shell --version 1.3.2.2
dotnet add package AvaloniaInside.Shell --version 1.3.3
```

Alternatively, you can also install the package through Visual Studio's NuGet Package Manager.
Expand All @@ -32,7 +32,6 @@ public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.LogToTrace()
.UseReactiveUI()
.UseShell();
```

Expand Down
35 changes: 0 additions & 35 deletions src/AvaloniaInside.Shell.sln
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Files", "Files", "{50F7051E
Directory.Packages.props = Directory.Packages.props
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShellBottomCustomNavigator", "Example\ShellBottomCustomNavigator\ShellBottomCustomNavigator\ShellBottomCustomNavigator.csproj", "{6D8FCCDB-C66B-4B81-9555-725E1EE912B8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShellBottomCustomNavigator.Android", "Example\ShellBottomCustomNavigator\ShellBottomCustomNavigator.Android\ShellBottomCustomNavigator.Android.csproj", "{4CEAC589-3446-4370-9357-C362E03DB56E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShellBottomCustomNavigator.Desktop", "Example\ShellBottomCustomNavigator\ShellBottomCustomNavigator.Desktop\ShellBottomCustomNavigator.Desktop.csproj", "{6FAADB02-7185-463E-8C93-5DAEE90EF782}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShellBottomCustomNavigator.iOS", "Example\ShellBottomCustomNavigator\ShellBottomCustomNavigator.iOS\ShellBottomCustomNavigator.iOS.csproj", "{C77D28D8-7583-40FE-9EA7-6E8B5F902A8B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ShellBottomCustomNavigator.Browser", "Example\ShellBottomCustomNavigator\ShellBottomCustomNavigator.Browser\ShellBottomCustomNavigator.Browser.csproj", "{58D15C4F-ADC5-4550-9224-365FFB38955D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -66,26 +56,6 @@ Global
{75883514-564B-4EBA-83D8-68FD9FDB0CB2}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{75883514-564B-4EBA-83D8-68FD9FDB0CB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{75883514-564B-4EBA-83D8-68FD9FDB0CB2}.Release|Any CPU.Build.0 = Release|Any CPU
{6D8FCCDB-C66B-4B81-9555-725E1EE912B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D8FCCDB-C66B-4B81-9555-725E1EE912B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D8FCCDB-C66B-4B81-9555-725E1EE912B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6D8FCCDB-C66B-4B81-9555-725E1EE912B8}.Release|Any CPU.Build.0 = Release|Any CPU
{4CEAC589-3446-4370-9357-C362E03DB56E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4CEAC589-3446-4370-9357-C362E03DB56E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4CEAC589-3446-4370-9357-C362E03DB56E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4CEAC589-3446-4370-9357-C362E03DB56E}.Release|Any CPU.Build.0 = Release|Any CPU
{6FAADB02-7185-463E-8C93-5DAEE90EF782}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FAADB02-7185-463E-8C93-5DAEE90EF782}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FAADB02-7185-463E-8C93-5DAEE90EF782}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FAADB02-7185-463E-8C93-5DAEE90EF782}.Release|Any CPU.Build.0 = Release|Any CPU
{C77D28D8-7583-40FE-9EA7-6E8B5F902A8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C77D28D8-7583-40FE-9EA7-6E8B5F902A8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C77D28D8-7583-40FE-9EA7-6E8B5F902A8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C77D28D8-7583-40FE-9EA7-6E8B5F902A8B}.Release|Any CPU.Build.0 = Release|Any CPU
{58D15C4F-ADC5-4550-9224-365FFB38955D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{58D15C4F-ADC5-4550-9224-365FFB38955D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58D15C4F-ADC5-4550-9224-365FFB38955D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58D15C4F-ADC5-4550-9224-365FFB38955D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -96,11 +66,6 @@ Global
{721FC232-3B13-492D-A96B-C6784FEDB10C} = {A495BEFD-2260-489E-A8F3-003EF9603D43}
{E2E23F24-CC66-4940-91EA-68C28DC04602} = {A495BEFD-2260-489E-A8F3-003EF9603D43}
{75883514-564B-4EBA-83D8-68FD9FDB0CB2} = {A495BEFD-2260-489E-A8F3-003EF9603D43}
{6D8FCCDB-C66B-4B81-9555-725E1EE912B8} = {A495BEFD-2260-489E-A8F3-003EF9603D43}
{4CEAC589-3446-4370-9357-C362E03DB56E} = {A495BEFD-2260-489E-A8F3-003EF9603D43}
{6FAADB02-7185-463E-8C93-5DAEE90EF782} = {A495BEFD-2260-489E-A8F3-003EF9603D43}
{C77D28D8-7583-40FE-9EA7-6E8B5F902A8B} = {A495BEFD-2260-489E-A8F3-003EF9603D43}
{58D15C4F-ADC5-4550-9224-365FFB38955D} = {A495BEFD-2260-489E-A8F3-003EF9603D43}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {10F59C6F-508A-4C41-820B-AAC163C9FDB2}
Expand Down
50 changes: 26 additions & 24 deletions src/AvaloniaInside.Shell/AppBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,43 +1,45 @@
using System;
using Avalonia;
using AvaloniaInside.Shell.Presenters;
using Splat;

namespace AvaloniaInside.Shell;

public static class AppBuilderExtensions
{
public static AppBuilder UseShell(this AppBuilder builder, Func<INavigationViewLocator>? viewLocatorFactory = null) =>
builder.AfterPlatformServicesSetup(_ => Locator.RegisterResolverCallbackChanged(() =>
builder.AfterPlatformServicesSetup(_ =>
{
if (Locator.CurrentMutable is null)
{
return;
}

Locator.CurrentMutable.Register<INavigationRegistrar, NavigationRegistrar>();
Locator.CurrentMutable.Register<IPresenterProvider, PresenterProvider>();
AvaloniaLocator.CurrentMutable
.Bind<INavigationRegistrar>().ToSingleton<NavigationRegistrar>()
.Bind<IPresenterProvider>().ToSingleton<PresenterProvider>();

if (viewLocatorFactory is null)
{
Locator.CurrentMutable.Register<INavigationViewLocator, DefaultNavigationViewLocator>();
AvaloniaLocator.CurrentMutable
.Bind<INavigationViewLocator>().ToSingleton<DefaultNavigationViewLocator>();
}

Locator.CurrentMutable.Register<INavigationUpdateStrategy>(() =>
new DefaultNavigationUpdateStrategy(Locator.Current.GetService<IPresenterProvider>()!));

Locator.CurrentMutable.Register<INavigator>(() =>
{
var viewLocator = viewLocatorFactory != null ? viewLocatorFactory.Invoke() : Locator.Current.GetService<INavigationViewLocator>()!;
var registrar = Locator.Current.GetService<INavigationRegistrar>()!;
return new Navigator(
registrar,
new RelativeNavigateStrategy(registrar),
Locator.Current.GetService<INavigationUpdateStrategy>()!,
viewLocator
AvaloniaLocator.CurrentMutable
.Bind<INavigationUpdateStrategy>()
.ToFunc(() =>
new DefaultNavigationUpdateStrategy(
AvaloniaLocator.CurrentMutable.GetService<IPresenterProvider>()!));


AvaloniaLocator.CurrentMutable
.Bind<INavigator>()
.ToFunc(() =>
{
var viewLocator = viewLocatorFactory != null ? viewLocatorFactory.Invoke() : AvaloniaLocator.CurrentMutable.GetService<INavigationViewLocator>()!;
var registrar = AvaloniaLocator.CurrentMutable.GetService<INavigationRegistrar>()!;
return new Navigator(
registrar,
new RelativeNavigateStrategy(registrar),
AvaloniaLocator.CurrentMutable.GetService<INavigationUpdateStrategy>()!,
viewLocator
);
});
}));
});
});

public static AppBuilder UseShell(this AppBuilder builder, Func<NavigationNode, object> viewFactory)
=> builder.UseShell(() => new DelegateNavigationViewLocator(viewFactory));
Expand Down
7 changes: 4 additions & 3 deletions src/AvaloniaInside.Shell/AvaloniaInside.Shell.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net9.0</TargetFrameworks>
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<Version>1.3.2.2</Version>
<Version>1.3.3</Version>
<Title>Shell view for Avalonia</Title>
<Description>Shell reduces the complexity of mobile/desktop application development by providing the fundamental features that most applications require</Description>
<Copyright>AvaloniaInside</Copyright>
Expand All @@ -13,6 +13,8 @@
<PackageTags>avalonia,shell</PackageTags>
<PackageReadmeFile>README.md</PackageReadmeFile>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<AvaloniaAccessUnstablePrivateApis>true</AvaloniaAccessUnstablePrivateApis>
<Avalonia_I_Want_To_Use_Private_Apis_In_Nuget_Package_And_Promise_To_Pin_The_Exact_Avalonia_Version_In_Package_Dependency>true</Avalonia_I_Want_To_Use_Private_Apis_In_Nuget_Package_And_Promise_To_Pin_The_Exact_Avalonia_Version_In_Package_Dependency>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
Expand All @@ -24,7 +26,6 @@
<ItemGroup>
<PackageReference Include="Avalonia" />
<PackageReference Include="Avalonia.Themes.Fluent" />
<PackageReference Include="Avalonia.ReactiveUI" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" />
</ItemGroup>
Expand Down
40 changes: 19 additions & 21 deletions src/AvaloniaInside.Shell/Navigator.Attach.cs
Original file line number Diff line number Diff line change
@@ -1,36 +1,34 @@
using Avalonia;
using Avalonia.Input;
using System;

namespace AvaloniaInside.Shell;

public partial class Navigator
{
static Navigator()
{
ToProperty.Changed.Subscribe(HandleToChanged);
}

#region To Property

public static readonly AttachedProperty<BindingNavigate> ToProperty =
AvaloniaProperty.RegisterAttached<Navigator, AvaloniaObject, BindingNavigate>("To");
AvaloniaProperty.RegisterAttached<Navigator, AvaloniaObject, BindingNavigate>(
"To",
coerce: HandleToChanged);

private static void HandleToChanged(AvaloniaPropertyChangedEventArgs<BindingNavigate> e)
private static BindingNavigate HandleToChanged(AvaloniaObject obj, BindingNavigate value)
{
try
{
if (e.Sender is ICommandSource commandSource)
{
if (e.NewValue is { HasValue: true } v)
{
((dynamic)commandSource).Command = v.Value;
v.Value.Sender = e.Sender;
}
}
}
catch { /*IGNORE*/ }
}
try
{
if (obj is ICommandSource commandSource)
{
((dynamic)commandSource).Command = value;
value.Sender = obj;
}
}
catch
{
/*IGNORE*/
}

return value;
}

public static BindingNavigate GetTo(AvaloniaObject element) =>
element.GetValue(ToProperty);
Expand Down
8 changes: 3 additions & 5 deletions src/AvaloniaInside.Shell/ShellView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
using Avalonia.Input;
using Avalonia.Interactivity;
using AvaloniaInside.Shell.Platform;
using ReactiveUI;
using Splat;

namespace AvaloniaInside.Shell;

Expand Down Expand Up @@ -338,12 +336,12 @@ public static void SetEnableSafeAreaForRight(AvaloniaObject element, bool parame

public ShellView()
{
Navigator = Locator.Current
Navigator = AvaloniaLocator.CurrentMutable
.GetService<INavigator>() ?? throw new ArgumentException("Cannot find INavigationService");
Navigator.RegisterShell(this);

BackCommand = ReactiveCommand.CreateFromTask(BackActionAsync);
SideMenuCommand = ReactiveCommand.CreateFromTask(MenuActionAsync);
BackCommand = new SimpleAsyncCommand(BackActionAsync);
SideMenuCommand = new SimpleAsyncCommand(MenuActionAsync);

var isMobile = OperatingSystem.IsAndroid() || OperatingSystem.IsIOS();
if (!isMobile)
Expand Down
62 changes: 62 additions & 0 deletions src/AvaloniaInside.Shell/SimpleAsyncCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;

namespace AvaloniaInside.Shell;

public class SimpleAsyncCommand : ICommand
{
private readonly Func<object?, CancellationToken, Task> _execute;
private readonly Func<object?, bool>? _canExecute;
private bool _isExecuting;

public SimpleAsyncCommand(Func<Task> execute, Func<bool>? canExecute = null)
: this((_, _) => execute(), canExecute == null ? null : _ => canExecute())
{
}

public SimpleAsyncCommand(Func<object?, Task> execute, Func<object?, bool>? canExecute = null)
: this((param, _) => execute(param), canExecute)
{
}

public SimpleAsyncCommand(Func<CancellationToken, Task> execute, Func<bool>? canExecute = null)
: this((_, ct) => execute(ct), canExecute == null ? null : _ => canExecute())
{
}

public SimpleAsyncCommand(Func<object?, CancellationToken, Task> execute, Func<object?, bool>? canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}

public bool CanExecute(object? parameter) => !_isExecuting && (_canExecute?.Invoke(parameter) ?? true);

public void Execute(object? parameter)
{
// Fire-and-forget from ICommand.Execute (void). Use a safe, observed task.
_ = ExecuteAsync(parameter, CancellationToken.None);
}

public event EventHandler? CanExecuteChanged;

public async Task ExecuteAsync(object? parameter, CancellationToken cancellationToken)
{
if (_isExecuting) return;

try
{
_isExecuting = true;
CanExecuteChanged?.Invoke(this, EventArgs.Empty);

await _execute(parameter, cancellationToken).ConfigureAwait(false);
}
finally
{
_isExecuting = false;
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
}
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project>
<PropertyGroup>
<AvaloniaVersion>11.2.5</AvaloniaVersion>
<AvaloniaVersion>11.3.12</AvaloniaVersion>
</PropertyGroup>
</Project>
40 changes: 19 additions & 21 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
<Project>
<PropertyGroup>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Avalonia" Version="11.3.5"/>
<PackageVersion Include="Avalonia.Desktop" Version="11.3.5" />
<PackageVersion Include="Avalonia.Android" Version="11.3.5" />
<PackageVersion Include="Avalonia.iOS" Version="11.3.5" />
<PackageVersion Include="Avalonia.Browser" Version="11.3.5" />
<PackageVersion Include="Avalonia.Themes.Fluent" Version="11.3.5" />
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.5" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.5" />
<PackageVersion Include="Avalonia.Fonts.Inter" Version="11.3.5" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Projektanker.Icons.Avalonia" Version="9.6.2" />
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.6.2" />
<PackageVersion Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.0.1.17" />
<PackageVersion Include="ReactiveUI" Version="21.0.1" />
</ItemGroup>
</Project>
<PropertyGroup>
<CentralPackageTransitivePinningEnabled>true</CentralPackageTransitivePinningEnabled>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Avalonia" Version="11.3.12" />
<PackageVersion Include="Avalonia.Desktop" Version="11.3.12" />
<PackageVersion Include="Avalonia.Android" Version="11.3.12" />
<PackageVersion Include="Avalonia.iOS" Version="11.3.12" />
<PackageVersion Include="Avalonia.Browser" Version="11.3.12" />
<PackageVersion Include="Avalonia.Themes.Fluent" Version="11.3.12" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.12" />
<PackageVersion Include="Avalonia.Fonts.Inter" Version="11.3.12" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
<PackageVersion Include="Projektanker.Icons.Avalonia" Version="9.6.2" />
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.6.2" />
<PackageVersion Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.0.1.17" />
</ItemGroup>
</Project>
Loading
Loading