Skip to content

Commit 1d08157

Browse files
authored
Merge pull request #52 from NeverMorewd/master
release 2.1.1-rc
2 parents acbdd3b + 8fbc3f2 commit 1d08157

File tree

87 files changed

+1890
-1039
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+1890
-1039
lines changed

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ jobs:
7575
- name: Publish WPF NuGet package
7676
run: |
7777
if (Test-Path "./nugets/*.nupkg") {
78-
dotnet nuget push "./nugets/*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
78+
dotnet nuget push ".\nugets\*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate
7979
}
8080
8181
- name: Upload WPF NuGet Artifact

src/Lemon.ModuleNavigation.Avaloniaui/AssemblyInfo.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22

33
[assembly: XmlnsPrefix("https://github.com/NeverMorewd/Lemon.ModuleNavigation", "lm")]
44
[assembly: XmlnsDefinition("https://github.com/NeverMorewd/Lemon.ModuleNavigation", "Lemon.ModuleNavigation")]
5-
[assembly: XmlnsDefinition("https://github.com/NeverMorewd/Lemon.ModuleNavigation", "Lemon.ModuleNavigation.Avaloniaui")]
5+
[assembly: XmlnsDefinition("https://github.com/NeverMorewd/Lemon.ModuleNavigation", "Lemon.ModuleNavigation.Avaloniaui")]
6+
[assembly: XmlnsDefinition("https://github.com/NeverMorewd/Lemon.ModuleNavigation", "Lemon.ModuleNavigation.Avaloniaui.Regions")]

src/Lemon.ModuleNavigation.Avaloniaui/DialogService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using Avalonia;
22
using Avalonia.Controls.ApplicationLifetimes;
33
using Lemon.ModuleNavigation.Abstractions;
4-
using Lemon.ModuleNavigation.Dialogs;
4+
using Lemon.ModuleNavigation.Core;
55
using Microsoft.Extensions.DependencyInjection;
66

77
namespace Lemon.ModuleNavigation.Avaloniaui;

src/Lemon.ModuleNavigation.Avaloniaui/Lemon.ModuleNavigation.Avaloniaui.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@
1515

1616
<ItemGroup>
1717
<AvaloniaXaml Remove="bin\**" />
18+
<AvaloniaXaml Remove="RegionsOld\**" />
1819
<Compile Remove="bin\**" />
20+
<Compile Remove="RegionsOld\**" />
1921
<EmbeddedResource Remove="bin\**" />
22+
<EmbeddedResource Remove="RegionsOld\**" />
2023
<None Remove="bin\**" />
24+
<None Remove="RegionsOld\**" />
2125
</ItemGroup>
2226

2327
<ItemGroup>

src/Lemon.ModuleNavigation.Avaloniaui/NavigationExtension.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ void LoadedHandler(object? sender, RoutedEventArgs e)
3636
{
3737
var serviceProvider = navigationProvider!.ServiceProvider;
3838
var handler = serviceProvider.GetRequiredService<INavigationHandler>();
39-
handler.RegionManager.AddRegion(currentValue, control.ToContainer(currentValue));
39+
handler.RegionManager.AddRegion(currentValue, control.ToRegion(currentValue));
4040
}
4141
control.Loaded -= LoadedHandler;
4242
}
@@ -112,7 +112,7 @@ public static void SetModuleContainerName(Control control, string value)
112112
#region CanUnloadProperty
113113
public static readonly AttachedProperty<bool> CanUnloadProperty =
114114
AvaloniaProperty.RegisterAttached<NavigationExtension, Button, bool>("CanUnload",
115-
defaultValue: true,
115+
defaultValue: false,
116116
coerce: CoerceCanUnload);
117117

118118
private static bool CoerceCanUnload(AvaloniaObject targetObject, bool currentValue)
@@ -160,17 +160,23 @@ private static void UnloadModule(object? sender, RoutedEventArgs e)
160160
{
161161
if (sender is Button button)
162162
{
163+
var view = button.FindLogicalAncestorOfType<IView>(includeSelf: false);
164+
if (view != null)
165+
{
166+
}
163167
var tabItem = button.FindLogicalAncestorOfType<TabItem>(includeSelf: false) ?? throw new InvalidOperationException($"There is no 'TabItem' found in parents of {button}");
164168
var tabContainer = tabItem.FindLogicalAncestorOfType<TabControl>(includeSelf: false);
165169
if (tabContainer != null)
166170
{
167-
IModule item = tabItem.DataContext as IModule ?? throw new InvalidOperationException($"The DataContext of tabItem is not derived from IModule");
168-
if (item.CanUnload)
171+
if (tabItem.DataContext is IModule item)
169172
{
170-
if (tabContainer.DataContext is IServiceAware serviceAware)
173+
if (item.CanUnload)
171174
{
172-
var handler = serviceAware.ServiceProvider.GetRequiredService<INavigationHandler>();
173-
handler.ModuleManager.ActiveModules.Remove(item);
175+
if (tabContainer.DataContext is IServiceAware serviceAware)
176+
{
177+
var handler = serviceAware.ServiceProvider.GetRequiredService<INavigationHandler>();
178+
handler.ModuleManager.ActiveModules.Remove(item);
179+
}
174180
}
175181
}
176182
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using Avalonia.Controls;
2+
using Avalonia.Controls.Templates;
3+
using Avalonia.Data;
4+
using Avalonia.Markup.Xaml.Templates;
5+
using Lemon.ModuleNavigation.Abstractions;
6+
using System.ComponentModel;
7+
using System.Runtime.CompilerServices;
8+
9+
namespace Lemon.ModuleNavigation.Avaloniaui.Regions;
10+
11+
public class ContentRegion : Region, IContentRegionContext<IDataTemplate>
12+
{
13+
private readonly ContentControl _contentControl;
14+
public ContentRegion(string name, ContentControl contentControl) : base(name)
15+
{
16+
_contentControl = contentControl;
17+
SetBindingContentTemplate();
18+
SetBindingContent();
19+
}
20+
21+
private object? _content;
22+
public object? Content
23+
{
24+
get => _content;
25+
set
26+
{
27+
_content = value;
28+
OnPropertyChanged();
29+
}
30+
}
31+
32+
private IDataTemplate? _contentTemplate;
33+
public IDataTemplate? ContentTemplate
34+
{
35+
get => _contentTemplate;
36+
set
37+
{
38+
_contentTemplate = value;
39+
OnPropertyChanged();
40+
}
41+
}
42+
43+
public event PropertyChangedEventHandler? PropertyChanged;
44+
45+
/// <summary>
46+
/// When Views with same ViewName were found, the latest one will be picked.
47+
/// </summary>
48+
/// <param name="target"></param>
49+
public override void Activate(NavigationContext target)
50+
{
51+
if (ViewCache.TryGetValue(target, out IView? accurateView))
52+
{
53+
target.View = accurateView;
54+
Content = target;
55+
}
56+
else if (ViewNameCache.TryGetValue(target.ViewName, out IView? view)
57+
&& view.DataContext is INavigationAware navigationAware
58+
&& navigationAware.IsNavigationTarget(target))
59+
{
60+
var context = Contexts.First(c => c.ViewName == target.ViewName);
61+
context.View = view;
62+
Content = context;
63+
}
64+
else
65+
{
66+
Contexts.Add(target);
67+
Content = target;
68+
}
69+
}
70+
71+
public override void DeActivate(string regionName)
72+
{
73+
if (Content is NavigationContext current)
74+
{
75+
if (current.ViewName == regionName)
76+
{
77+
Contexts.Remove(current);
78+
Content = null;
79+
}
80+
}
81+
}
82+
public override void DeActivate(NavigationContext navigationContext)
83+
{
84+
if (Content is NavigationContext current)
85+
{
86+
if (NavigationContext.ViewNameComparer.Equals(current, navigationContext))
87+
{
88+
Contexts.Remove(current);
89+
Content = null;
90+
}
91+
}
92+
}
93+
94+
protected virtual void SetBindingContentTemplate()
95+
{
96+
ContentTemplate = RegionContentTemplate;
97+
_contentControl.Bind(ContentControl.ContentTemplateProperty,
98+
new Binding(nameof(ContentTemplate))
99+
{
100+
Source = this,
101+
Mode = BindingMode.TwoWay
102+
});
103+
}
104+
protected virtual void SetBindingContent()
105+
{
106+
_contentControl.Bind(ContentControl.ContentProperty,
107+
new Binding(nameof(Content))
108+
{
109+
Source = this,
110+
Mode = BindingMode.TwoWay
111+
});
112+
}
113+
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
114+
{
115+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
116+
}
117+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
using Avalonia.Controls;
2+
using Avalonia.Controls.Primitives;
3+
using Avalonia.Controls.Templates;
4+
using Avalonia.Data;
5+
using Avalonia.Markup.Xaml.Templates;
6+
using Lemon.ModuleNavigation.Abstractions;
7+
using System.ComponentModel;
8+
using System.Runtime.CompilerServices;
9+
10+
namespace Lemon.ModuleNavigation.Avaloniaui.Regions;
11+
12+
public class ItemsRegion : Region, IItemsRegionDataContext<IDataTemplate>
13+
{
14+
private readonly ItemsControl _itemsControl;
15+
public ItemsRegion(string name, ItemsControl itemsControl) : base(name)
16+
{
17+
_itemsControl = itemsControl;
18+
SetBindingItemTemplate();
19+
SetBindingSelectedItem();
20+
SetBindingItemsSource();
21+
}
22+
private object? _selectItem;
23+
public object? SelectedItem
24+
{
25+
get
26+
{
27+
return _selectItem;
28+
}
29+
set
30+
{
31+
_selectItem = value;
32+
OnPropertyChanged();
33+
}
34+
}
35+
36+
private IDataTemplate? _itemsTemplate;
37+
public IDataTemplate? ItemTemplate
38+
{
39+
get => _itemsTemplate;
40+
set
41+
{
42+
_itemsTemplate = value;
43+
OnPropertyChanged();
44+
}
45+
}
46+
public event PropertyChangedEventHandler? PropertyChanged;
47+
48+
public override void ScrollIntoView(int index)
49+
{
50+
_itemsControl.ScrollIntoView(index);
51+
}
52+
public override void ScrollIntoView(NavigationContext item)
53+
{
54+
_itemsControl.ScrollIntoView(item);
55+
}
56+
57+
/// <summary>
58+
/// When Views with same ViewName were found, the earliest one will be picked.
59+
/// </summary>
60+
/// <param name="target"></param>
61+
public override void Activate(NavigationContext target)
62+
{
63+
try
64+
{
65+
if (ViewCache.TryGetValue(target, out IView? accurateView))
66+
{
67+
target.View = accurateView;
68+
SelectedItem = target;
69+
return;
70+
}
71+
var context = Contexts.FirstOrDefault(c => c.ViewName == target.ViewName);
72+
if (context is not null
73+
&& context.View is not null
74+
&& context.View.DataContext is INavigationAware navigationAware
75+
&& navigationAware.IsNavigationTarget(target))
76+
{
77+
SelectedItem = context;
78+
return;
79+
}
80+
Contexts.Add(target);
81+
SelectedItem = target;
82+
}
83+
finally
84+
{
85+
ScrollIntoView((SelectedItem as NavigationContext)!);
86+
}
87+
}
88+
public override void DeActivate(string viewName)
89+
{
90+
Contexts.Remove(Contexts.Last(c => c.ViewName == viewName));
91+
}
92+
public override void DeActivate(NavigationContext navigationContext)
93+
{
94+
Contexts.Remove(navigationContext);
95+
}
96+
public void Add(NavigationContext item)
97+
{
98+
Contexts.Add(item);
99+
}
100+
101+
protected virtual void SetBindingItemsSource()
102+
{
103+
_itemsControl.Bind(ItemsControl.ItemsSourceProperty,
104+
new Binding(nameof(Contexts))
105+
{
106+
Source = this
107+
});
108+
}
109+
protected virtual void SetBindingItemTemplate()
110+
{
111+
ItemTemplate = RegionContentTemplate;
112+
_itemsControl.Bind(ItemsControl.ItemTemplateProperty,
113+
new Binding(nameof(ItemTemplate))
114+
{
115+
Source = this
116+
});
117+
}
118+
protected virtual void SetBindingSelectedItem()
119+
{
120+
if (_itemsControl is SelectingItemsControl selector)
121+
{
122+
selector.Bind(SelectingItemsControl.SelectedItemProperty,
123+
new Binding(nameof(SelectedItem))
124+
{
125+
Source = this,
126+
Mode = BindingMode.TwoWay
127+
});
128+
}
129+
}
130+
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
131+
{
132+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
133+
}
134+
}

0 commit comments

Comments
 (0)