Skip to content

Commit 06c6536

Browse files
authored
Feature: UnifiedApp (#85)
1 parent 01e6b72 commit 06c6536

3 files changed

Lines changed: 196 additions & 4 deletions

File tree

eng/MultiTarget/GlobalUsings.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@
88
global using global::System.Threading.Tasks;
99

1010
// WinUI
11+
#if UAP
12+
global using global::Windows.ApplicationModel;
13+
global using global::Windows.ApplicationModel.Activation;
14+
global using global::Windows.Storage;
15+
global using global::Windows.UI;
16+
global using global::Windows.UI.WindowManagement;
17+
#endif
18+
1119
#if WinUI
1220
global using global::Microsoft;
1321
global using global::Microsoft.UI;
@@ -24,11 +32,8 @@
2432
global using global::Microsoft.UI.Xaml.Media.Animation;
2533
global using global::Microsoft.UI.Xaml.Shapes;
2634
global using global::Microsoft.UI.Xaml.Controls.Primitives;
27-
28-
global using global::Windows.UI;
2935
#elif UWP
3036
global using global::Windows;
31-
global using global::Windows.UI;
3237
global using global::Windows.UI.Xaml;
3338
global using global::Windows.UI.Xaml.Controls;
3439
global using global::Windows.UI.Xaml.Data;
@@ -58,6 +63,8 @@
5863
global using global::iNKORE.UI.WPF.Modern;
5964
global using global::iNKORE.UI.WPF.Modern.Controls;
6065
global using global::iNKORE.UI.WPF.Modern.Common;
66+
67+
global using Frame = global::iNKORE.UI.WPF.Modern.Controls.Frame;
6168
#endif
6269

6370
// CommunityToolkit

src/core/Riverside.Extensions.WinUI/Riverside.Extensions.WinUI.projitems

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@
99
<Import_RootNamespace>Riverside.Extensions.WinUI</Import_RootNamespace>
1010
</PropertyGroup>
1111
<ItemGroup>
12+
<Compile Include="$(MSBuildThisFileDirectory)UnifiedApp.cs" />
1213
</ItemGroup>
13-
</Project>
14+
</Project>
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
// This file contains portions of code from the Files App project, licensed under the MIT License.
2+
3+
using System.Reflection;
4+
5+
namespace Riverside.Extensions.WinUI;
6+
7+
/// <summary>
8+
/// Represents a unified application class that can be used across all platforms.
9+
/// It provides a common set of properties and methods that can be used in any project.
10+
/// </summary>
11+
/// <seealso cref="Application"/>
12+
public abstract partial class UnifiedApp : Application
13+
{
14+
private static CommandBarFlyout? _LastOpenedFlyout;
15+
16+
#if !Wpf && !UWP
17+
/// <summary>
18+
/// Gets a dictionary of windows identified by a string key.
19+
/// </summary>
20+
public Dictionary<string, Window> Windows { get; } = [];
21+
#endif
22+
23+
/// <summary>
24+
/// Gets the application version.
25+
/// </summary>
26+
public static readonly string AppVersion =
27+
#if Wpf
28+
$"{Assembly.GetEntryAssembly()?.GetName().Version?.Major}." +
29+
$"{Assembly.GetEntryAssembly()?.GetName().Version?.Minor}." +
30+
$"{Assembly.GetEntryAssembly()?.GetName().Version?.Build}." +
31+
$"{Assembly.GetEntryAssembly()?.GetName().Version?.Revision}";
32+
#else
33+
$"{Package.Current.Id.Version.Major}." +
34+
$"{Package.Current.Id.Version.Minor}." +
35+
$"{Package.Current.Id.Version.Build}." +
36+
$"{Package.Current.Id.Version.Revision}";
37+
#endif
38+
39+
/// <summary>
40+
/// Gets the current <see cref="UnifiedApp"/> instance in use.
41+
/// </summary>
42+
public new static UnifiedApp Current
43+
=> (UnifiedApp)Application.Current;
44+
45+
/// <summary>
46+
/// Gets or sets the <see cref="IServiceProvider"/> instance to resolve application services.
47+
/// </summary>
48+
public IServiceProvider Services { get; set; }
49+
50+
#if !Wpf
51+
/// <summary>
52+
/// Gets the application data container for local settings.
53+
/// </summary>
54+
public ApplicationDataContainer Settings = ApplicationData.Current.LocalSettings;
55+
#endif
56+
57+
#if !Wpf && !UWP
58+
/// <summary>
59+
/// Opens a new window with the specified key, page type, and optional parameter.
60+
/// </summary>
61+
/// <typeparam name="TPage">The type of the page to navigate to.</typeparam>
62+
/// <param name="windowKey">The key to identify the window.</param>
63+
/// <param name="parameter">The parameter to pass to the page.</param>
64+
public void OpenNewWindow<TPage>(string windowKey, object parameter = null)
65+
{
66+
if (Windows.TryGetValue(windowKey, out Window value))
67+
{
68+
value.Activate();
69+
return;
70+
}
71+
72+
Window newWindow = new();
73+
Frame frame = new();
74+
_ = frame.Navigate(typeof(TPage), parameter);
75+
newWindow.Content = frame;
76+
newWindow.Activate();
77+
78+
Windows[windowKey] = newWindow;
79+
}
80+
#endif
81+
82+
/// <summary>
83+
/// Gets or sets the last opened <see cref="CommandBarFlyout"/>.
84+
/// </summary>
85+
public static CommandBarFlyout? LastOpenedFlyout
86+
{
87+
set
88+
{
89+
_LastOpenedFlyout = value;
90+
91+
if (_LastOpenedFlyout is not null)
92+
_LastOpenedFlyout.Closed += LastOpenedFlyout_Closed;
93+
}
94+
}
95+
96+
/// <summary>
97+
/// Invoked when Navigation to a certain page fails
98+
/// </summary>
99+
/// <param name="sender">The <see cref="Frame"/> which failed navigation</param>
100+
/// <param name="e">Details about the navigation failure</param>
101+
public virtual void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
102+
=> throw new Exception("Failed to load Page "
103+
#if Wpf
104+
+ e.Uri);
105+
#else
106+
+ e.SourcePageType.FullName);
107+
#endif
108+
109+
#if !Wpf
110+
/// <summary>
111+
/// Invoked when the application execution is being suspended.
112+
/// </summary>
113+
/// <remarks>
114+
/// This is the standard method to save application state before the application is suspended.
115+
/// You can override it to save additional state, but you should always call the base implementation.
116+
/// </remarks>
117+
/// <param name="sender">The source of the suspend request.</param>
118+
/// <param name="e">Details about the suspend request.</param>
119+
public virtual void OnSuspending(object sender, SuspendingEventArgs e)
120+
{
121+
SuspendingDeferral deferral = e.SuspendingOperation.GetDeferral();
122+
deferral.Complete();
123+
}
124+
#endif
125+
126+
/// <summary>
127+
/// Invoked when an unobserved task exception occurs.
128+
/// </summary>
129+
/// <param name="sender">The source of the unobserved task exception.</param>
130+
/// <param name="e">Details about the unobserved task exception.</param>
131+
public virtual void OnUnobservedException(object? sender, UnobservedTaskExceptionEventArgs e)
132+
=> e.SetObserved();
133+
134+
/// <summary>
135+
/// Invoked when an unhandled exception occurs.
136+
/// </summary>
137+
/// <remarks>
138+
/// This is the standard method to handle unhandled exceptions.
139+
/// You can override it to provide custom exception handling, but you should always call the base implementation.
140+
///
141+
/// This base version also raises a new <see cref="ContentDialog"/> to display the exception message.
142+
/// </remarks>
143+
/// <param name="sender">The source of the unhandled exception.</param>
144+
/// <param name="e">Details about the unhandled exception.</param>
145+
public async virtual void OnUnhandledException(object? sender,
146+
#if UWP
147+
Windows.UI.Xaml.UnhandledExceptionEventArgs e)
148+
#elif WinUI
149+
Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
150+
#else
151+
UnhandledExceptionEventArgs e)
152+
#endif
153+
{
154+
try
155+
{
156+
await new ContentDialog
157+
{
158+
Title = "Unhandled exception",
159+
Content =
160+
#if UWP
161+
e.Message,
162+
#else
163+
"An unhandled exception occured.",
164+
#endif
165+
CloseButtonText = "Close"
166+
}
167+
.ShowAsync();
168+
}
169+
catch { }
170+
}
171+
172+
/// <summary>
173+
/// Gets invoked when the last opened flyout is closed.
174+
/// </summary>
175+
private static void LastOpenedFlyout_Closed(object? sender, object e)
176+
{
177+
if (sender is not CommandBarFlyout commandBarFlyout)
178+
return;
179+
180+
commandBarFlyout.Closed -= LastOpenedFlyout_Closed;
181+
if (_LastOpenedFlyout == commandBarFlyout)
182+
_LastOpenedFlyout = null;
183+
}
184+
}

0 commit comments

Comments
 (0)