diff --git a/Directory.Build.props b/Directory.Build.props index c6aabc6b9..452a106b7 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,6 +1,6 @@ - 3.0.4 + 3.0.5 12.0 true diff --git a/docs/documentation/navigation-view.md b/docs/documentation/navigation-view.md index 2020474a2..8dd2408c6 100644 --- a/docs/documentation/navigation-view.md +++ b/docs/documentation/navigation-view.md @@ -69,3 +69,157 @@ RootNavigation.Navigate(2); ``` ## Pane display mode + +## Set initial page + +NavigationPage.xaml + +```xml + +``` + +NavigationPage.xaml.cs + +```csharp +public partial class NavigationPage : Page +{ + public NavigationPage(NavigationPageModel model) + { + InitializeComponent(); + + DataContext = model; + Loaded += (_, _) => RootNavigation.Navigate(type(MyDashboardClass)); + } +} +``` + +## Using Navigation in the MVVM + +Firstly, you need to implement the `IPageService` interface + +```csharp +// from src/Wpf.Ui.Demo.Mvvm/Services/PageService.cs +public class PageService : IPageService +{ + /// + /// Service which provides the instances of pages. + /// + private readonly IServiceProvider _serviceProvider; + + /// + /// Initializes a new instance of the class and attaches the . + /// + public PageService(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + /// + public T? GetPage() + where T : class + { + if (!typeof(FrameworkElement).IsAssignableFrom(typeof(T))) + { + throw new InvalidOperationException("The page should be a WPF control."); + } + + return (T?)_serviceProvider.GetService(typeof(T)); + } + + /// + public FrameworkElement? GetPage(Type pageType) + { + if (!typeof(FrameworkElement).IsAssignableFrom(pageType)) + { + throw new InvalidOperationException("The page should be a WPF control."); + } + + return _serviceProvider.GetService(pageType) as FrameworkElement; + } +} +``` + +Then, inject it into the IoC container. + +```csharp +var services = new ServiceCollection(); + +services.AddSingleton(); +services.AddSingleton(); +services.AddSingleton(); + +// inject View and ViewModel +services.AddSingleton(); +services.AddSingleton(); +services.AddSingleton(); +services.AddSingleton(); +services.AddSingleton(); +services.AddSingleton(); +``` + +Lastly, adjust the code for the navigation window. + +```xml + + + + +``` + +```csharp +using System.Collections.ObjectModel; +using System.Windows; +using CommunityToolkit.Mvvm.ComponentModel; +using Wpf.Ui; +using Wpf.Ui.Controls; + +public partial class MainWindow : Window +{ + public MainWindow(IPageService pageService, MainWindowViewModel model) + { + DataContext = model; + InitializeComponent(); + + // Set the page service for the navigation control. + RootNavigationView.SetPageService(pageService); + } +} + +public partial class MainWindowViewModel : ObservableObject +{ + [ObservableProperty] + private ObservableCollection _navigationItems = []; + + public MainWindowViewModel() + { + NavigationItems = + [ + new NavigationViewItem() + { + Content = "Home", + Icon = new SymbolIcon { Symbol = SymbolRegular.Home24 }, + TargetPageType = typeof(HomePage) + }, + new NavigationViewItem() + { + Content = "Counter", + TargetPageType = typeof(CounterPage) + }, + ]; + } +} +``` + +Alternatively, you can use the **WPF UI** Visual Studio Extension that includes a project template for MVVM pattern. diff --git a/docs/documentation/nuget.md b/docs/documentation/nuget.md index f6e53308f..cb0881512 100644 --- a/docs/documentation/nuget.md +++ b/docs/documentation/nuget.md @@ -28,4 +28,4 @@ NuGet is a free, open-source package management system for the Microsoft .NET pl # Done! -Package installed, to learn more, go to the [**Getting started**](/tutorial/getting-started.html) page. +Package installed, to learn more, go to the [**Getting started**](/documentation/getting-started.html) page. diff --git a/docs/documentation/themes.md b/docs/documentation/themes.md index 4fa255169..e98eb724e 100644 --- a/docs/documentation/themes.md +++ b/docs/documentation/themes.md @@ -24,8 +24,8 @@ Or, you can add **WPF UI** resources manually. - - + + @@ -37,16 +37,16 @@ Or, you can add **WPF UI** resources manually. If you want to change the theme while the application is running, you can call the static `Apply` method of the `Theme` class. ```csharp -Wpf.Ui.Appearance.Theme.Apply( - Wpf.Ui.Appearance.ThemeType.Light, // Theme type - Wpf.Ui.Appearance.BackgroundType.Mica, // Background type - true // Whether to change accents automatically +Wpf.Ui.Appearance.ApplicationThemeManager.Apply( + Wpf.Ui.Appearance.ApplicationTheme.Light, // Theme type + Wpf.Ui.Controls.WindowBackdropType.Mica, // Background type + true // Whether to change accents automatically ); ``` ### Automatic change -The theme can be changed automatically when the operating system changes its background or accent using the [Watcher](https://github.com/lepoco/wpfui/blob/main/src/Wpf.Ui/Appearance/Watcher.cs) class. +The theme can be changed automatically when the operating system changes its background or accent using the [SystemThemeWatcher](https://github.com/lepoco/wpfui/blob/main/src/Wpf.Ui/Appearance/SystemThemeWatcher.cs) class. ```csharp namespace MyApp; @@ -59,10 +59,10 @@ public partial class MainWindow : Window Loaded += (sender, args) => { - Wpf.Ui.Appearance.Watcher.Watch( - this, // Window class - Wpf.Ui.Appearance.BackgroundType.Mica, // Background type - true // Whether to change accents automatically + Wpf.Ui.Appearance.SystemThemeWatcher.Watch( + this, // Window class + Wpf.Ui.Controls.WindowBackdropType.Mica, // Background type + true // Whether to change accents automatically ); }; } diff --git a/src/Wpf.Ui.Demo.Simple/AssemblyInfo.cs b/src/Wpf.Ui.Demo.Simple/AssemblyInfo.cs index 273de9fbc..b8f7eb71b 100644 --- a/src/Wpf.Ui.Demo.Simple/AssemblyInfo.cs +++ b/src/Wpf.Ui.Demo.Simple/AssemblyInfo.cs @@ -1,3 +1,8 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + using System.Windows; [assembly: ThemeInfo( diff --git a/src/Wpf.Ui.Extension.Template.Blank/App.xaml.cs b/src/Wpf.Ui.Extension.Template.Blank/App.xaml.cs index 12f11be2c..2f88101a2 100644 --- a/src/Wpf.Ui.Extension.Template.Blank/App.xaml.cs +++ b/src/Wpf.Ui.Extension.Template.Blank/App.xaml.cs @@ -20,7 +20,7 @@ public partial class App // https://docs.microsoft.com/dotnet/core/extensions/logging private static readonly IHost _host = Host .CreateDefaultBuilder() - .ConfigureAppConfiguration(c => { c.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location)); }) + .ConfigureAppConfiguration(c => { c.SetBasePath(Path.GetDirectoryName(AppContext.BaseDirectory)); }) .ConfigureServices((context, services) => { throw new NotImplementedException("No service or window was registered."); diff --git a/src/Wpf.Ui.Extension.Template.Compact/App.xaml.cs b/src/Wpf.Ui.Extension.Template.Compact/App.xaml.cs index bcedf63e4..5e3346fdd 100644 --- a/src/Wpf.Ui.Extension.Template.Compact/App.xaml.cs +++ b/src/Wpf.Ui.Extension.Template.Compact/App.xaml.cs @@ -25,7 +25,7 @@ public partial class App // https://docs.microsoft.com/dotnet/core/extensions/logging private static readonly IHost _host = Host .CreateDefaultBuilder() - .ConfigureAppConfiguration(c => { c.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location)); }) + .ConfigureAppConfiguration(c => { c.SetBasePath(Path.GetDirectoryName(AppContext.BaseDirectory)); }) .ConfigureServices((context, services) => { services.AddHostedService(); diff --git a/src/Wpf.Ui.Extension.Template.Fluent/App.xaml.cs b/src/Wpf.Ui.Extension.Template.Fluent/App.xaml.cs index bcedf63e4..5e3346fdd 100644 --- a/src/Wpf.Ui.Extension.Template.Fluent/App.xaml.cs +++ b/src/Wpf.Ui.Extension.Template.Fluent/App.xaml.cs @@ -25,7 +25,7 @@ public partial class App // https://docs.microsoft.com/dotnet/core/extensions/logging private static readonly IHost _host = Host .CreateDefaultBuilder() - .ConfigureAppConfiguration(c => { c.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location)); }) + .ConfigureAppConfiguration(c => { c.SetBasePath(Path.GetDirectoryName(AppContext.BaseDirectory)); }) .ConfigureServices((context, services) => { services.AddHostedService(); diff --git a/src/Wpf.Ui.FontMapper/FontSource.cs b/src/Wpf.Ui.FontMapper/FontSource.cs index 07f91a684..ef82fed41 100644 --- a/src/Wpf.Ui.FontMapper/FontSource.cs +++ b/src/Wpf.Ui.FontMapper/FontSource.cs @@ -1,3 +1,8 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + namespace Wpf.Ui.FontMapper; class FontSource diff --git a/src/Wpf.Ui.FontMapper/GitTag.cs b/src/Wpf.Ui.FontMapper/GitTag.cs index b05c52d12..a31b1015d 100644 --- a/src/Wpf.Ui.FontMapper/GitTag.cs +++ b/src/Wpf.Ui.FontMapper/GitTag.cs @@ -1,3 +1,8 @@ -namespace Wpf.Ui.FontMapper; +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +namespace Wpf.Ui.FontMapper; record GitTag(string Ref, string Node_Id, string Url); diff --git a/src/Wpf.Ui.Gallery/Views/Pages/DialogsAndFlyouts/ContentDialog.xaml b/src/Wpf.Ui.Gallery/Views/Pages/DialogsAndFlyouts/ContentDialogPage.xaml similarity index 100% rename from src/Wpf.Ui.Gallery/Views/Pages/DialogsAndFlyouts/ContentDialog.xaml rename to src/Wpf.Ui.Gallery/Views/Pages/DialogsAndFlyouts/ContentDialogPage.xaml diff --git a/src/Wpf.Ui.Gallery/Views/Pages/DialogsAndFlyouts/ContentDialog.xaml.cs b/src/Wpf.Ui.Gallery/Views/Pages/DialogsAndFlyouts/ContentDialogPage.xaml.cs similarity index 100% rename from src/Wpf.Ui.Gallery/Views/Pages/DialogsAndFlyouts/ContentDialog.xaml.cs rename to src/Wpf.Ui.Gallery/Views/Pages/DialogsAndFlyouts/ContentDialogPage.xaml.cs diff --git a/src/Wpf.Ui.Gallery/Views/Pages/Layout/ExpanderPage.xaml.cs b/src/Wpf.Ui.Gallery/Views/Pages/Layout/ExpanderPage.xaml.cs index 89af1d655..5dbf69feb 100644 --- a/src/Wpf.Ui.Gallery/Views/Pages/Layout/ExpanderPage.xaml.cs +++ b/src/Wpf.Ui.Gallery/Views/Pages/Layout/ExpanderPage.xaml.cs @@ -1,4 +1,9 @@ -using Wpf.Ui.Controls; +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +using Wpf.Ui.Controls; using Wpf.Ui.Gallery.ControlsLookup; using Wpf.Ui.Gallery.ViewModels.Pages.Layout; diff --git a/src/Wpf.Ui.SyntaxHighlight/Highlighter.cs b/src/Wpf.Ui.SyntaxHighlight/Highlighter.cs index a9912099f..73d4391be 100644 --- a/src/Wpf.Ui.SyntaxHighlight/Highlighter.cs +++ b/src/Wpf.Ui.SyntaxHighlight/Highlighter.cs @@ -2,7 +2,7 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// + // TODO: This class is work in progress. using System; diff --git a/src/Wpf.Ui.Tray/Controls/NotifyIcon.cs b/src/Wpf.Ui.Tray/Controls/NotifyIcon.cs index 7bc0fcac7..7f6b86889 100644 --- a/src/Wpf.Ui.Tray/Controls/NotifyIcon.cs +++ b/src/Wpf.Ui.Tray/Controls/NotifyIcon.cs @@ -388,6 +388,8 @@ private static void OnTooltipTextChanged(DependencyObject d, DependencyPropertyC } notifyIcon.TooltipText = e.NewValue as string ?? string.Empty; + notifyIcon.internalNotifyIconManager.TooltipText = notifyIcon.TooltipText; + _ = notifyIcon.internalNotifyIconManager.ModifyToolTip(); } private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) diff --git a/src/Wpf.Ui.Tray/Hicon.cs b/src/Wpf.Ui.Tray/Hicon.cs index f86466243..5d3d492fb 100644 --- a/src/Wpf.Ui.Tray/Hicon.cs +++ b/src/Wpf.Ui.Tray/Hicon.cs @@ -2,7 +2,7 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// + // TODO: This class is the only reason for using System.Drawing.Common. // It is worth looking for a way to get hIcon without using it. diff --git a/src/Wpf.Ui.Tray/INotifyIcon.cs b/src/Wpf.Ui.Tray/INotifyIcon.cs index 13108eab4..1fceb7515 100644 --- a/src/Wpf.Ui.Tray/INotifyIcon.cs +++ b/src/Wpf.Ui.Tray/INotifyIcon.cs @@ -82,6 +82,11 @@ internal interface INotifyIcon /// bool ModifyIcon(); + /// + /// Tries to modify the tooltip of the in the shell. + /// + bool ModifyToolTip(); + /// /// Tries to remove the from the shell. /// diff --git a/src/Wpf.Ui.Tray/Internal/InternalNotifyIconManager.cs b/src/Wpf.Ui.Tray/Internal/InternalNotifyIconManager.cs index f3e0abe4d..9a1faab92 100644 --- a/src/Wpf.Ui.Tray/Internal/InternalNotifyIconManager.cs +++ b/src/Wpf.Ui.Tray/Internal/InternalNotifyIconManager.cs @@ -104,6 +104,12 @@ public virtual bool ModifyIcon() return TrayManager.ModifyIcon(this); } + /// + public virtual bool ModifyToolTip() + { + return TrayManager.ModifyToolTip(this); + } + /// public virtual bool Unregister() { diff --git a/src/Wpf.Ui.Tray/TrayManager.cs b/src/Wpf.Ui.Tray/TrayManager.cs index 5635947bc..161cf9223 100644 --- a/src/Wpf.Ui.Tray/TrayManager.cs +++ b/src/Wpf.Ui.Tray/TrayManager.cs @@ -124,6 +124,19 @@ public static bool ModifyIcon(INotifyIcon notifyIcon) return Interop.Shell32.Shell_NotifyIcon(Interop.Shell32.NIM.MODIFY, notifyIcon.ShellIconData); } + public static bool ModifyToolTip(INotifyIcon notifyIcon) + { + if (!notifyIcon.IsRegistered) + { + return true; + } + + notifyIcon.ShellIconData.szTip = notifyIcon.TooltipText; + notifyIcon.ShellIconData.uFlags |= Interop.Shell32.NIF.TIP; + + return Interop.Shell32.Shell_NotifyIcon(Interop.Shell32.NIM.MODIFY, notifyIcon.ShellIconData); + } + /// /// Tries to remove the from the shell. /// diff --git a/src/Wpf.Ui/Appearance/ApplicationThemeManager.cs b/src/Wpf.Ui/Appearance/ApplicationThemeManager.cs index 69bcbc136..226be0fcc 100644 --- a/src/Wpf.Ui/Appearance/ApplicationThemeManager.cs +++ b/src/Wpf.Ui/Appearance/ApplicationThemeManager.cs @@ -97,7 +97,7 @@ public static void Apply( SystemTheme.HC1 => "HC1", SystemTheme.HC2 => "HC2", SystemTheme.HCBlack => "HCBlack", - SystemTheme.HCWhite => "HCBlack", + SystemTheme.HCWhite => "HCWhite", _ => "HCWhite", }; break; diff --git a/src/Wpf.Ui/Appearance/WindowBackgroundManager.cs b/src/Wpf.Ui/Appearance/WindowBackgroundManager.cs index 4425f68c9..769e888bc 100644 --- a/src/Wpf.Ui/Appearance/WindowBackgroundManager.cs +++ b/src/Wpf.Ui/Appearance/WindowBackgroundManager.cs @@ -91,11 +91,16 @@ WindowBackdropType backdrop } // This was required to update the background when moving from a HC theme to light/dark theme. However, this breaks theme proper light/dark theme changing on Windows 10. - // else - // { - // _ = WindowBackdrop.RemoveBackground(window); - // } + // But window backdrop effects are not applied when it has an opaque (or any) background on W11 (so removing this breaks backdrop effects when switching themes), however, for legacy MICA it may not be required + // using existing variable, though the OS build which (officially) supports setting DWM_SYSTEMBACKDROP_TYPE attribute is build 22621 + // source: https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type + if (Win32.Utilities.IsOSWindows11Insider1OrNewer && backdrop is not WindowBackdropType.None) + { + _ = WindowBackdrop.RemoveBackground(window); + } + _ = WindowBackdrop.ApplyBackdrop(window, backdrop); + if (applicationTheme is ApplicationTheme.Dark) { ApplyDarkThemeToWindow(window); @@ -105,6 +110,8 @@ WindowBackdropType backdrop RemoveDarkThemeFromWindow(window); } + _ = WindowBackdrop.RemoveTitlebarBackground(window); + foreach (object? subWindow in window.OwnedWindows) { if (subWindow is Window windowSubWindow) @@ -119,6 +126,8 @@ WindowBackdropType backdrop { RemoveDarkThemeFromWindow(windowSubWindow); } + + _ = WindowBackdrop.RemoveTitlebarBackground(window); } } } diff --git a/src/Wpf.Ui/Controls/Anchor/Anchor.cs b/src/Wpf.Ui/Controls/Anchor/Anchor.cs index 032009df4..bc3bdedbe 100644 --- a/src/Wpf.Ui/Controls/Anchor/Anchor.cs +++ b/src/Wpf.Ui/Controls/Anchor/Anchor.cs @@ -2,7 +2,7 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// + // https://docs.microsoft.com/en-us/fluent-ui/web-components/components/anchor // ReSharper disable once CheckNamespace diff --git a/src/Wpf.Ui/Controls/Arc/Arc.cs b/src/Wpf.Ui/Controls/Arc/Arc.cs index 4d14713a8..c668584a7 100644 --- a/src/Wpf.Ui/Controls/Arc/Arc.cs +++ b/src/Wpf.Ui/Controls/Arc/Arc.cs @@ -3,10 +3,12 @@ // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. +using System.Windows.Controls; +using System.Windows.Shapes; using Point = System.Windows.Point; using Size = System.Windows.Size; -// ReSharper disable once CheckNamespace +// ReSharper disable CheckNamespace namespace Wpf.Ui.Controls; /// @@ -22,8 +24,10 @@ namespace Wpf.Ui.Controls; /// Visibility="Visible" /> /// /// -public class Arc : System.Windows.Shapes.Shape +public class Arc : Shape { + private Viewbox? _rootLayout; + /// Identifies the dependency property. public static readonly DependencyProperty StartAngleProperty = DependencyProperty.Register( nameof(StartAngle), @@ -40,6 +44,22 @@ public class Arc : System.Windows.Shapes.Shape new PropertyMetadata(0.0d, PropertyChangedCallback) ); + /// Identifies the dependency property. + public static readonly DependencyProperty SweepDirectionProperty = DependencyProperty.Register( + nameof(SweepDirection), + typeof(SweepDirection), + typeof(Arc), + new PropertyMetadata(SweepDirection.Clockwise, PropertyChangedCallback) + ); + + /// Identifies the dependency property. + public static readonly DependencyProperty StrokeStartLineCapProperty = DependencyProperty.Register( + nameof(StrokeStartLineCap), + typeof(PenLineCap), + typeof(Arc), + new PropertyMetadata(PenLineCap.Round, PropertyChangedCallback) + ); + /// /// Gets or sets the initial angle from which the arc will be drawn. /// @@ -59,37 +79,45 @@ public double EndAngle } /// - /// Gets a value indicating whether one of the two larger arc sweeps is chosen; otherwise, if is , one of the smaller arc sweeps is chosen. + /// Gets or sets the direction to where the arc will be drawn. /// - public bool IsLargeArc { get; internal set; } = false; + public SweepDirection SweepDirection + { + get => (SweepDirection)GetValue(SweepDirectionProperty); + set => SetValue(SweepDirectionProperty, value); + } - /// - protected override Geometry DefiningGeometry => GetDefiningGeometry(); + // TODO: Should we? + public new PenLineCap StrokeStartLineCap + { + get { return (PenLineCap)GetValue(StrokeStartLineCapProperty); } + set { SetValue(StrokeStartLineCapProperty, value); } + } /// - /// Initializes static members of the class. + /// Gets a value indicating whether one of the two larger arc sweeps is chosen; otherwise, if is , one of the smaller arc sweeps is chosen. /// - /// - /// Overrides default properties. - /// - static Arc() + public bool IsLargeArc { get; internal set; } = false; + + private void EnsureRootLayout() { - StrokeStartLineCapProperty.OverrideMetadata( - typeof(Arc), - new FrameworkPropertyMetadata(PenLineCap.Round) - ); + if (_rootLayout != null) + { + return; + } - StrokeEndLineCapProperty.OverrideMetadata( - typeof(Arc), - new FrameworkPropertyMetadata(PenLineCap.Round) - ); + _rootLayout = new Viewbox { SnapsToDevicePixels = true }; + AddVisualChild(_rootLayout); } + /// + protected override Geometry DefiningGeometry => DefinedGeometry(); + /// /// Get the geometry that defines this shape. /// Based on Mark Feldman implementation. /// - protected Geometry GetDefiningGeometry() + protected Geometry DefinedGeometry() { var geometryStream = new StreamGeometry(); var arcSize = new Size( @@ -97,20 +125,18 @@ protected Geometry GetDefiningGeometry() Math.Max(0, (RenderSize.Height - StrokeThickness) / 2) ); - using (StreamGeometryContext context = geometryStream.Open()) - { - context.BeginFigure(PointAtAngle(Math.Min(StartAngle, EndAngle)), false, false); - - context.ArcTo( - PointAtAngle(Math.Max(StartAngle, EndAngle)), - arcSize, - 0, - IsLargeArc, - SweepDirection.Counterclockwise, - true, - false - ); - } + using StreamGeometryContext context = geometryStream.Open(); + context.BeginFigure(PointAtAngle(Math.Min(StartAngle, EndAngle)), false, false); + + context.ArcTo( + PointAtAngle(Math.Max(StartAngle, EndAngle)), + arcSize, + 0, + IsLargeArc, + SweepDirection, + true, + false + ); geometryStream.Transform = new TranslateTransform(StrokeThickness / 2, StrokeThickness / 2); @@ -124,11 +150,42 @@ protected Geometry GetDefiningGeometry() /// The angle at which to create the point. protected Point PointAtAngle(double angle) { - var radAngle = angle * (Math.PI / 180); - var xRadius = (RenderSize.Width - StrokeThickness) / 2; - var yRadius = (RenderSize.Height - StrokeThickness) / 2; - - return new Point(xRadius + (xRadius * Math.Cos(radAngle)), yRadius - (yRadius * Math.Sin(radAngle))); + if (SweepDirection == SweepDirection.Counterclockwise) + { + angle += 90; + angle %= 360; + if (angle < 0) + { + angle += 360; + } + + var radAngle = angle * (Math.PI / 180); + var xRadius = (RenderSize.Width - StrokeThickness) / 2; + var yRadius = (RenderSize.Height - StrokeThickness) / 2; + + return new Point( + xRadius + (xRadius * Math.Cos(radAngle)), + yRadius - (yRadius * Math.Sin(radAngle)) + ); + } + else + { + angle -= 90; + angle %= 360; + if (angle < 0) + { + angle += 360; + } + + var radAngle = angle * (Math.PI / 180); + var xRadius = (RenderSize.Width - StrokeThickness) / 2; + var yRadius = (RenderSize.Height - StrokeThickness) / 2; + + return new Point( + xRadius + (xRadius * Math.Cos(-radAngle)), + yRadius - (yRadius * Math.Sin(-radAngle)) + ); + } } /// @@ -142,8 +199,49 @@ protected static void PropertyChangedCallback(DependencyObject d, DependencyProp } control.IsLargeArc = Math.Abs(control.EndAngle - control.StartAngle) > 180; - - // Force complete new layout pass control.InvalidateVisual(); } + + protected override Visual? GetVisualChild(int index) + { + if (index != 0) + { + throw new ArgumentOutOfRangeException(nameof(index), "Arc should have only 1 child"); + } + + EnsureRootLayout(); + + return _rootLayout; + } + + protected override Size MeasureOverride(Size availableSize) + { + EnsureRootLayout(); + + _rootLayout!.Measure(availableSize); + return _rootLayout.DesiredSize; + } + + protected override Size ArrangeOverride(Size finalSize) + { + EnsureRootLayout(); + + _rootLayout!.Arrange(new Rect(default, finalSize)); + return finalSize; + } + + /// Overrides the default OnRender method to draw the element. + /// A object that is drawn during the rendering pass of this . + protected override void OnRender(DrawingContext drawingContext) + { + base.OnRender(drawingContext); + Pen pen = + new(Stroke, StrokeThickness) + { + StartLineCap = StrokeStartLineCap, + EndLineCap = StrokeStartLineCap + }; + + drawingContext.DrawGeometry(Stroke, pen, DefinedGeometry()); + } } diff --git a/src/Wpf.Ui/Controls/AutoSuggestBox/AutoSuggestBox.cs b/src/Wpf.Ui/Controls/AutoSuggestBox/AutoSuggestBox.cs index 94acd6c1f..fb8a326dc 100644 --- a/src/Wpf.Ui/Controls/AutoSuggestBox/AutoSuggestBox.cs +++ b/src/Wpf.Ui/Controls/AutoSuggestBox/AutoSuggestBox.cs @@ -270,7 +270,12 @@ public override void OnApplyTemplate() /// public new bool Focus() { - return TextBox!.Focus(); + if (TextBox is null) + { + return false; + } + + return TextBox.Focus(); } protected T GetTemplateChild(string name) diff --git a/src/Wpf.Ui/Controls/Badge/Badge.cs b/src/Wpf.Ui/Controls/Badge/Badge.cs index cebd04cdb..2106341f9 100644 --- a/src/Wpf.Ui/Controls/Badge/Badge.cs +++ b/src/Wpf.Ui/Controls/Badge/Badge.cs @@ -2,7 +2,7 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// + // https://docs.microsoft.com/en-us/fluent-ui/web-components/components/badge // ReSharper disable once CheckNamespace diff --git a/src/Wpf.Ui/Controls/BreadcrumbBar/BreadcrumbBar.cs b/src/Wpf.Ui/Controls/BreadcrumbBar/BreadcrumbBar.cs index 4f0fa361d..d0d701788 100644 --- a/src/Wpf.Ui/Controls/BreadcrumbBar/BreadcrumbBar.cs +++ b/src/Wpf.Ui/Controls/BreadcrumbBar/BreadcrumbBar.cs @@ -2,9 +2,9 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// Based on Windows UI Library -// Copyright(c) Microsoft Corporation.All rights reserved. + +/* Based on Windows UI Library + Copyright(c) Microsoft Corporation.All rights reserved. */ using System.Collections.Specialized; using System.Windows.Controls.Primitives; diff --git a/src/Wpf.Ui/Controls/BreadcrumbBar/BreadcrumbBarItem.cs b/src/Wpf.Ui/Controls/BreadcrumbBar/BreadcrumbBarItem.cs index ea6d82561..6f4164cba 100644 --- a/src/Wpf.Ui/Controls/BreadcrumbBar/BreadcrumbBarItem.cs +++ b/src/Wpf.Ui/Controls/BreadcrumbBar/BreadcrumbBarItem.cs @@ -2,8 +2,8 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// Based on Windows UI Library + +/* Based on Windows UI Library */ using Wpf.Ui.Converters; diff --git a/src/Wpf.Ui/Controls/BreadcrumbBar/BreadcrumbBarItemClickedEventArgs.cs b/src/Wpf.Ui/Controls/BreadcrumbBar/BreadcrumbBarItemClickedEventArgs.cs index ba3efbb22..f680d12c4 100644 --- a/src/Wpf.Ui/Controls/BreadcrumbBar/BreadcrumbBarItemClickedEventArgs.cs +++ b/src/Wpf.Ui/Controls/BreadcrumbBar/BreadcrumbBarItemClickedEventArgs.cs @@ -2,7 +2,7 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// + // Based on Windows UI Library // Copyright(c) Microsoft Corporation.All rights reserved. diff --git a/src/Wpf.Ui/Controls/ContextMenu/ContextMenuLoader.xaml.cs b/src/Wpf.Ui/Controls/ContextMenu/ContextMenuLoader.xaml.cs index 57ef7e0db..46ce1a442 100644 --- a/src/Wpf.Ui/Controls/ContextMenu/ContextMenuLoader.xaml.cs +++ b/src/Wpf.Ui/Controls/ContextMenu/ContextMenuLoader.xaml.cs @@ -2,8 +2,8 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// This Code is based on a StackOverflow-Answer: https://stackoverflow.com/a/56736232/9759874 + +/* This Code is based on a StackOverflow-Answer: https://stackoverflow.com/a/56736232/9759874 */ using System.Reflection; using System.Windows.Threading; diff --git a/src/Wpf.Ui/Controls/DateTimeHelper.cs b/src/Wpf.Ui/Controls/DateTimeHelper.cs index 7bfd09025..1590305ad 100644 --- a/src/Wpf.Ui/Controls/DateTimeHelper.cs +++ b/src/Wpf.Ui/Controls/DateTimeHelper.cs @@ -2,13 +2,13 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI 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 more information. -// -// NOTE: This date time helper assumes it is working in a Gregorian calendar -// If we ever support non Gregorian calendars this class would need to be redesigned + +/* NOTE: This date time helper assumes it is working in a Gregorian calendar + If we ever support non-Gregorian calendars this class would need to be redesigned */ using System.Diagnostics; using System.Windows.Controls; diff --git a/src/Wpf.Ui/Controls/DynamicScrollViewer/DynamicScrollViewer.xaml b/src/Wpf.Ui/Controls/DynamicScrollViewer/DynamicScrollViewer.xaml index 91c377518..201647a79 100644 --- a/src/Wpf.Ui/Controls/DynamicScrollViewer/DynamicScrollViewer.xaml +++ b/src/Wpf.Ui/Controls/DynamicScrollViewer/DynamicScrollViewer.xaml @@ -1,4 +1,4 @@ - @@ -192,7 +192,7 @@ CornerRadius="{TemplateBinding Border.CornerRadius}" /> - + diff --git a/src/Wpf.Ui/Controls/NumberBox/NumberBoxSpinButtonPlacementMode.cs b/src/Wpf.Ui/Controls/NumberBox/NumberBoxSpinButtonPlacementMode.cs index 752068831..17c88f42a 100644 --- a/src/Wpf.Ui/Controls/NumberBox/NumberBoxSpinButtonPlacementMode.cs +++ b/src/Wpf.Ui/Controls/NumberBox/NumberBoxSpinButtonPlacementMode.cs @@ -2,7 +2,7 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// + // This Source Code is partially based on the source code provided by the .NET Foundation. // ReSharper disable once CheckNamespace diff --git a/src/Wpf.Ui/Controls/NumberBox/NumberBoxValidationMode.cs b/src/Wpf.Ui/Controls/NumberBox/NumberBoxValidationMode.cs index f99a5d741..4dfe465a1 100644 --- a/src/Wpf.Ui/Controls/NumberBox/NumberBoxValidationMode.cs +++ b/src/Wpf.Ui/Controls/NumberBox/NumberBoxValidationMode.cs @@ -2,7 +2,7 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// + // This Source Code is partially based on the source code provided by the .NET Foundation. // ReSharper disable once CheckNamespace diff --git a/src/Wpf.Ui/Controls/NumberBox/ValidateNumberFormatter.cs b/src/Wpf.Ui/Controls/NumberBox/ValidateNumberFormatter.cs index 8963a305d..19873b87f 100644 --- a/src/Wpf.Ui/Controls/NumberBox/ValidateNumberFormatter.cs +++ b/src/Wpf.Ui/Controls/NumberBox/ValidateNumberFormatter.cs @@ -2,7 +2,7 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// + // This Source Code is partially based on the source code provided by the .NET Foundation. // ReSharper disable once CheckNamespace diff --git a/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.cs b/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.cs index 2d7be4f91..e802d3796 100644 --- a/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.cs +++ b/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.cs @@ -2,11 +2,11 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// + // TODO: This is an initial implementation and requires the necessary corrections, tests and adjustments. -// -// TextProperty contains asterisks OR raw password if IsPasswordRevealed is set to true -// PasswordProperty always contains raw password + +/* TextProperty contains asterisks OR raw password if IsPasswordRevealed is set to true + PasswordProperty always contains raw password */ using System.Windows.Controls; @@ -16,8 +16,9 @@ namespace Wpf.Ui.Controls; /// /// The modified password control. /// -public class PasswordBox : Wpf.Ui.Controls.TextBox +public partial class PasswordBox : Wpf.Ui.Controls.TextBox { + private readonly PasswordHelper _passwordHelper; private bool _lockUpdatingContents; /// Identifies the dependency property. @@ -88,7 +89,7 @@ public bool IsPasswordRevealed } /// - /// Gets or sets a value indicating whether whether to display the password reveal button. + /// Gets or sets a value indicating whether to display the password reveal button. /// public bool RevealButtonEnabled { @@ -112,6 +113,7 @@ public event RoutedEventHandler PasswordChanged public PasswordBox() { _lockUpdatingContents = false; + _passwordHelper = new PasswordHelper(this); } /// @@ -125,15 +127,7 @@ protected override void OnTextChanged(TextChangedEventArgs e) } else { - if (PlaceholderEnabled && Text.Length > 0) - { - SetCurrentValue(PlaceholderEnabledProperty, false); - } - - if (!PlaceholderEnabled && Text.Length < 1) - { - SetCurrentValue(PlaceholderEnabledProperty, true); - } + SetPlaceholderTextVisibility(); RevealClearButton(); } @@ -236,47 +230,11 @@ private void UpdateTextContents(bool isTriggeredByTextInput) } var caretIndex = CaretIndex; - var selectionIndex = SelectionStart; - var currentPassword = Password; - var newPasswordValue = currentPassword; + var newPasswordValue = _passwordHelper.GetPassword(); if (isTriggeredByTextInput) { - var currentText = Text; - var newCharacters = currentText.Replace(PasswordChar.ToString(), string.Empty); - - if (currentText.Length < currentPassword.Length) - { - newPasswordValue = currentPassword.Remove( - selectionIndex, - currentPassword.Length - currentText.Length - ); - } - - if (newCharacters.Length > 1) - { - var index = currentText.IndexOf(newCharacters[0]); - - newPasswordValue = - index > newPasswordValue.Length - 1 - ? newPasswordValue + newCharacters - : newPasswordValue.Insert(index, newCharacters); - } - else - { - for (int i = 0; i < currentText.Length; i++) - { - if (currentText[i] == PasswordChar) - { - continue; - } - - newPasswordValue = - currentText.Length == newPasswordValue.Length - ? newPasswordValue.Remove(i, 1).Insert(i, currentText[i].ToString()) - : newPasswordValue.Insert(i, currentText[i].ToString()); - } - } + newPasswordValue = _passwordHelper.GetNewPassword(); } _lockUpdatingContents = true; diff --git a/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.xaml b/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.xaml index 871698bba..346b8a68d 100644 --- a/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.xaml +++ b/src/Wpf.Ui/Controls/PasswordBox/PasswordBox.xaml @@ -204,8 +204,8 @@ Command="{Binding Path=TemplateButtonCommand, RelativeSource={RelativeSource TemplatedParent}}" CommandParameter="clear" Cursor="Arrow" - IsTabStop="False" - Foreground="{DynamicResource TextControlButtonForeground}"> + Foreground="{DynamicResource TextControlButtonForeground}" + IsTabStop="False"> @@ -228,8 +228,8 @@ Command="{Binding Path=TemplateButtonCommand, RelativeSource={RelativeSource TemplatedParent}}" CommandParameter="reveal" Cursor="Arrow" - IsTabStop="False" - Foreground="{DynamicResource TextControlButtonForeground}"> + Foreground="{DynamicResource TextControlButtonForeground}" + IsTabStop="False"> @@ -256,7 +256,7 @@ CornerRadius="{TemplateBinding Border.CornerRadius}" /> - + diff --git a/src/Wpf.Ui/Controls/PasswordBox/PasswordHelper.cs b/src/Wpf.Ui/Controls/PasswordBox/PasswordHelper.cs new file mode 100644 index 000000000..64ed3fa0d --- /dev/null +++ b/src/Wpf.Ui/Controls/PasswordBox/PasswordHelper.cs @@ -0,0 +1,118 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + +using System.Diagnostics; + +// ReSharper disable once CheckNamespace +namespace Wpf.Ui.Controls; + +#pragma warning disable SA1601 + +public partial class PasswordBox +{ + private class PasswordHelper + { + private readonly PasswordBox _passwordBox; + private string _currentText; + private string _newPasswordValue; + private string _currentPassword; + + public PasswordHelper(PasswordBox passwordBox) + { + _passwordBox = passwordBox; + _currentText = string.Empty; + _newPasswordValue = string.Empty; + _currentPassword = string.Empty; + } + + public string GetNewPassword() + { + _currentPassword = GetPassword(); + _newPasswordValue = _currentPassword; + _currentText = _passwordBox.Text; + var selectionIndex = _passwordBox.SelectionStart; + var passwordChar = _passwordBox.PasswordChar; + var newCharacters = _currentText.Replace(passwordChar.ToString(), string.Empty); + bool isDeleted = false; + + if (IsDeleteOption()) + { + _newPasswordValue = _currentPassword.Remove( + selectionIndex, + _currentPassword.Length - _currentText.Length + ); + isDeleted = true; + } + + switch (newCharacters.Length) + { + case > 1: + { + var index = _currentText.IndexOf(newCharacters[0]); + + _newPasswordValue = + index > _newPasswordValue.Length - 1 + ? _newPasswordValue + newCharacters + : _newPasswordValue.Insert(index, newCharacters); + break; + } + + case 1: + { + for (int i = 0; i < _currentText.Length; i++) + { + if (_currentText[i] == passwordChar) + { + continue; + } + + UpdatePasswordWithInputCharacter(i, _currentText[i].ToString()); + break; + } + + break; + } + + case 0 when !isDeleted: + { + // The input is a PasswordChar, which is to be inserted at the designated position. + int insertIndex = selectionIndex - 1; + UpdatePasswordWithInputCharacter(insertIndex, passwordChar.ToString()); + break; + } + } + + return _newPasswordValue; + } + + private void UpdatePasswordWithInputCharacter(int insertIndex, string insertValue) + { + Debug.Assert(_currentText == _passwordBox.Text, "_currentText == _passwordBox.Text"); + + if (_currentText.Length == _newPasswordValue.Length) + { + // If it's a direct character replacement, remove the existing one before inserting the new one. + _newPasswordValue = _newPasswordValue.Remove(insertIndex, 1).Insert(insertIndex, insertValue); + } + else + { + _newPasswordValue = _newPasswordValue.Insert(insertIndex, insertValue); + } + } + + private bool IsDeleteOption() + { + Debug.Assert(_currentText == _passwordBox.Text, "_currentText == _passwordBox.Text"); + Debug.Assert( + _currentPassword == _passwordBox.Password, + "_currentPassword == _passwordBox.Password" + ); + + return _currentText.Length < _currentPassword.Length; + } + + public string GetPassword() => _passwordBox.Password ?? string.Empty; + } +} diff --git a/src/Wpf.Ui/Controls/ProgressRing/ProgressRing.cs b/src/Wpf.Ui/Controls/ProgressRing/ProgressRing.cs index 8c5e79bef..0e4399e5c 100644 --- a/src/Wpf.Ui/Controls/ProgressRing/ProgressRing.cs +++ b/src/Wpf.Ui/Controls/ProgressRing/ProgressRing.cs @@ -2,8 +2,8 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// https://docs.microsoft.com/en-us/fluent-ui/web-components/components/progress-ring + +/* https://docs.microsoft.com/en-us/fluent-ui/web-components/components/progress-ring */ using Brush = System.Windows.Media.Brush; using Brushes = System.Windows.Media.Brushes; diff --git a/src/Wpf.Ui/Controls/RadioButton/RadioButton.xaml b/src/Wpf.Ui/Controls/RadioButton/RadioButton.xaml index 5dec5478b..ffef00b49 100644 --- a/src/Wpf.Ui/Controls/RadioButton/RadioButton.xaml +++ b/src/Wpf.Ui/Controls/RadioButton/RadioButton.xaml @@ -62,7 +62,7 @@ Stroke="{DynamicResource RadioButtonOuterEllipseStroke}" StrokeThickness="{StaticResource RadioButtonStrokeThickness}" UseLayoutRounding="False" /> - + - + Identifies the dependency property. + public static readonly DependencyProperty CurrentPlaceholderEnabledProperty = DependencyProperty.Register( + nameof(CurrentPlaceholderEnabled), + typeof(bool), + typeof(TextBox), new PropertyMetadata(true) ); @@ -99,7 +107,7 @@ public ElementPlacement IconPlacement } /// - /// Gets or sets numbers pattern. + /// Gets or sets placeholder text. /// public string PlaceholderText { @@ -108,7 +116,7 @@ public string PlaceholderText } /// - /// Gets or sets a value indicating whether to display the placeholder text. + /// Gets or sets a value indicating whether to enable the placeholder text. /// public bool PlaceholderEnabled { @@ -116,6 +124,15 @@ public bool PlaceholderEnabled set => SetValue(PlaceholderEnabledProperty, value); } + /// + /// Gets or sets a value indicating whether to display the placeholder text. + /// + public bool CurrentPlaceholderEnabled + { + get => (bool)GetValue(CurrentPlaceholderEnabledProperty); + protected set => SetValue(CurrentPlaceholderEnabledProperty, value); + } + /// /// Gets or sets a value indicating whether to enable the clear button. /// @@ -154,6 +171,7 @@ public bool IsTextSelectionEnabled public TextBox() { SetValue(TemplateButtonCommandProperty, new RelayCommand(OnTemplateButtonClick)); + CurrentPlaceholderEnabled = PlaceholderEnabled; } /// @@ -161,17 +179,29 @@ protected override void OnTextChanged(TextChangedEventArgs e) { base.OnTextChanged(e); - if (PlaceholderEnabled && Text.Length > 0) + SetPlaceholderTextVisibility(); + + RevealClearButton(); + } + + protected void SetPlaceholderTextVisibility() + { + if (PlaceholderEnabled) { - SetCurrentValue(PlaceholderEnabledProperty, false); + if (CurrentPlaceholderEnabled && Text.Length > 0) + { + SetCurrentValue(CurrentPlaceholderEnabledProperty, false); + } + + if (!CurrentPlaceholderEnabled && Text.Length < 1) + { + SetCurrentValue(CurrentPlaceholderEnabledProperty, true); + } } - - if (!PlaceholderEnabled && Text.Length < 1) + else if (CurrentPlaceholderEnabled) { - SetCurrentValue(PlaceholderEnabledProperty, true); + SetCurrentValue(CurrentPlaceholderEnabledProperty, false); } - - RevealClearButton(); } /// @@ -234,4 +264,19 @@ protected virtual void OnTemplateButtonClick(string? parameter) OnClearButtonClick(); } + + private static void OnPlaceholderEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is not TextBox control) + { + return; + } + + control.OnPlaceholderEnabledChanged(); + } + + protected virtual void OnPlaceholderEnabledChanged() + { + SetPlaceholderTextVisibility(); + } } diff --git a/src/Wpf.Ui/Controls/TextBox/TextBox.xaml b/src/Wpf.Ui/Controls/TextBox/TextBox.xaml index 8e197b9c0..4fc1e5940 100644 --- a/src/Wpf.Ui/Controls/TextBox/TextBox.xaml +++ b/src/Wpf.Ui/Controls/TextBox/TextBox.xaml @@ -214,7 +214,7 @@ CornerRadius="{TemplateBinding Border.CornerRadius}" /> - + diff --git a/src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml b/src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml index 8af4ccca0..5ab185e5c 100644 --- a/src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml +++ b/src/Wpf.Ui/Controls/TitleBar/TitleBar.xaml @@ -177,7 +177,8 @@ + ButtonType="Maximize" + IsHitTestVisible="False"/> The window to which the backdrop effect will be applied. /// The type of backdrop effect to apply. Determines the visual appearance of the window's backdrop. /// if the operation was successful; otherwise, . - public static bool ApplyBackdrop(System.Windows.Window window, WindowBackdropType backdropType) + public static bool ApplyBackdrop(System.Windows.Window? window, WindowBackdropType backdropType) { if (window is null) { @@ -216,6 +216,40 @@ public static bool RemoveBackground(System.Windows.Window? window) return true; } + public static bool RemoveTitlebarBackground(System.Windows.Window? window) + { + if (window is null) + { + return false; + } + + IntPtr windowHandle = new WindowInteropHelper(window).Handle; + + if (windowHandle == IntPtr.Zero) + { + return false; + } + + HwndSource? windowSource = HwndSource.FromHwnd(windowHandle); + + // Remove background from client area + if (windowSource?.Handle != IntPtr.Zero && windowSource?.CompositionTarget != null) + { + // NOTE: https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute + // Specifying DWMWA_COLOR_DEFAULT (value 0xFFFFFFFF) for the color will reset the window back to using the system's default behavior for the caption color. + uint titlebarPvAttribute = 0xFFFFFFFE; + + Dwmapi.DwmSetWindowAttribute( + windowSource.Handle, + Dwmapi.DWMWINDOWATTRIBUTE.DWMWA_CAPTION_COLOR, + ref titlebarPvAttribute, + Marshal.SizeOf(typeof(uint)) + ); + } + + return true; + } + private static bool ApplyDwmwWindowAttrubute(IntPtr hWnd, Dwmapi.DWMSBT dwmSbt) { if (hWnd == IntPtr.Zero) @@ -228,7 +262,7 @@ private static bool ApplyDwmwWindowAttrubute(IntPtr hWnd, Dwmapi.DWMSBT dwmSbt) return false; } - var backdropPvAttribute = (int)dwmSbt; + int backdropPvAttribute = (int)dwmSbt; var dwmApiResult = Dwmapi.DwmSetWindowAttribute( hWnd, diff --git a/src/Wpf.Ui/Converters/ProgressThicknessConverter.cs b/src/Wpf.Ui/Converters/ProgressThicknessConverter.cs index cc10cc0e4..f0880ee0d 100644 --- a/src/Wpf.Ui/Converters/ProgressThicknessConverter.cs +++ b/src/Wpf.Ui/Converters/ProgressThicknessConverter.cs @@ -2,8 +2,8 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// TODO: It's too hardcoded, we should define better formula. + +/* TODO: It's too hardcoded, we should define better formula. */ using System.Windows.Data; diff --git a/src/Wpf.Ui/Hardware/DisplayDpi.cs b/src/Wpf.Ui/Hardware/DisplayDpi.cs index 8ea68b963..88d8d3f9a 100644 --- a/src/Wpf.Ui/Hardware/DisplayDpi.cs +++ b/src/Wpf.Ui/Hardware/DisplayDpi.cs @@ -2,8 +2,8 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// This Source Code is partially based on the source code provided by the .NET Foundation. + +/* This Source Code is partially based on the source code provided by the .NET Foundation. */ namespace Wpf.Ui.Hardware; diff --git a/src/Wpf.Ui/Input/IRelayCommand.cs b/src/Wpf.Ui/Input/IRelayCommand.cs index 0bbd4de35..cf7e75ec5 100644 --- a/src/Wpf.Ui/Input/IRelayCommand.cs +++ b/src/Wpf.Ui/Input/IRelayCommand.cs @@ -2,10 +2,10 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI 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 more information. + +/* 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 more information. */ using System.Windows.Input; diff --git a/src/Wpf.Ui/Input/IRelayCommand{T}.cs b/src/Wpf.Ui/Input/IRelayCommand{T}.cs index ae93e1dd6..9e5b23513 100644 --- a/src/Wpf.Ui/Input/IRelayCommand{T}.cs +++ b/src/Wpf.Ui/Input/IRelayCommand{T}.cs @@ -2,10 +2,10 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI 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 more information. + +/* 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 more information. */ using System.Windows.Input; diff --git a/src/Wpf.Ui/Input/RelayCommand{T}.cs b/src/Wpf.Ui/Input/RelayCommand{T}.cs index 6fd4ff9b3..5cf365d67 100644 --- a/src/Wpf.Ui/Input/RelayCommand{T}.cs +++ b/src/Wpf.Ui/Input/RelayCommand{T}.cs @@ -2,12 +2,12 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI 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 more information. -// -// This file is inspired from the MvvmLight library (lbugnion/MvvmLight) + +/* 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 more information. + + This file is inspired by the MvvmLight library (lbugnion/MvvmLight) */ using System.Runtime.CompilerServices; diff --git a/src/Wpf.Ui/Interop/Dwmapi.cs b/src/Wpf.Ui/Interop/Dwmapi.cs index 8bb49b605..adf6a9618 100644 --- a/src/Wpf.Ui/Interop/Dwmapi.cs +++ b/src/Wpf.Ui/Interop/Dwmapi.cs @@ -2,7 +2,7 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// + // This Source Code is partially based on reverse engineering of the Windows Operating System, // and is intended for use on Windows systems only. // This Source Code is partially based on the source code provided by the .NET Foundation. @@ -14,14 +14,14 @@ // // Windows Kits\10\Include\10.0.22000.0\um\dwmapi.h -using System.Runtime.InteropServices; - -namespace Wpf.Ui.Interop; - // ReSharper disable IdentifierTypo // ReSharper disable InconsistentNaming #pragma warning disable SA1307 // Accessible fields should begin with upper-case letter +using System.Runtime.InteropServices; + +namespace Wpf.Ui.Interop; + /// /// Desktop Window Manager (DWM). /// @@ -619,6 +619,22 @@ public static extern int DwmSetWindowAttribute( [In] int cbAttribute ); + /// + /// Sets the value of Desktop Window Manager (DWM) non-client rendering attributes for a window. + /// + /// The handle to the window for which the attribute value is to be set. + /// A flag describing which value to set, specified as a value of the DWMWINDOWATTRIBUTE enumeration. + /// A pointer to an object containing the attribute value to set. + /// The size, in bytes, of the attribute value being set via the pvAttribute parameter. + /// If the function succeeds, it returns S_OK. Otherwise, it returns an HRESULT error code. + [DllImport(Libraries.Dwmapi)] + public static extern int DwmSetWindowAttribute( + [In] IntPtr hWnd, + [In] DWMWINDOWATTRIBUTE dwAttribute, + [In] ref uint pvAttribute, + [In] int cbAttribute + ); + /// /// Retrieves the current value of a specified Desktop Window Manager (DWM) attribute applied to a window. For programming guidance, and code examples, see Controlling non-client region rendering. /// diff --git a/src/Wpf.Ui/Interop/Kernel32.cs b/src/Wpf.Ui/Interop/Kernel32.cs index 02b2d75e0..d66562109 100644 --- a/src/Wpf.Ui/Interop/Kernel32.cs +++ b/src/Wpf.Ui/Interop/Kernel32.cs @@ -2,7 +2,7 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// + // This Source Code is partially based on reverse engineering of the Windows Operating System, // and is intended for use on Windows systems only. // This Source Code is partially based on the source code provided by the .NET Foundation. @@ -12,13 +12,12 @@ // If you have suggestions for the code below, please submit your changes there. // https://github.com/lepoco/nativemethods +// ReSharper disable IdentifierTypo +// ReSharper disable InconsistentNaming using System.Runtime.InteropServices; namespace Wpf.Ui.Interop; -// ReSharper disable IdentifierTypo -// ReSharper disable InconsistentNaming - /// /// Used by multiple technologies. /// diff --git a/src/Wpf.Ui/Interop/ShObjIdl.cs b/src/Wpf.Ui/Interop/ShObjIdl.cs index d1774844d..cc334f43e 100644 --- a/src/Wpf.Ui/Interop/ShObjIdl.cs +++ b/src/Wpf.Ui/Interop/ShObjIdl.cs @@ -2,7 +2,7 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// + // This Source Code is partially based on reverse engineering of the Windows Operating System, // and is intended for use on Windows systems only. // This Source Code is partially based on the source code provided by the .NET Foundation. @@ -12,13 +12,12 @@ // If you have suggestions for the code below, please submit your changes there. // https://github.com/lepoco/nativemethods -using System.Runtime.InteropServices; - -namespace Wpf.Ui.Interop; - // ReSharper disable IdentifierTypo // ReSharper disable InconsistentNaming #pragma warning disable SA1307 // Accessible fields should begin with upper-case letter +using System.Runtime.InteropServices; + +namespace Wpf.Ui.Interop; /// /// Exposes methods that enumerate the contents of a view and receive notification from callback upon enumeration completion. diff --git a/src/Wpf.Ui/Interop/Shell32.cs b/src/Wpf.Ui/Interop/Shell32.cs index 3a571041f..9b1a4de70 100644 --- a/src/Wpf.Ui/Interop/Shell32.cs +++ b/src/Wpf.Ui/Interop/Shell32.cs @@ -2,7 +2,7 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// + // This Source Code is partially based on reverse engineering of the Windows Operating System, // and is intended for use on Windows systems only. // This Source Code is partially based on the source code provided by the .NET Foundation. @@ -12,16 +12,16 @@ // If you have suggestions for the code below, please submit your changes there. // https://github.com/lepoco/nativemethods -using System.Runtime.InteropServices; -using System.Runtime.InteropServices.ComTypes; - -namespace Wpf.Ui.Interop; - // ReSharper disable IdentifierTypo // ReSharper disable InconsistentNaming #pragma warning disable SA1307 // Accessible fields should begin with upper-case letter #pragma warning disable SA1401 // Fields should be private +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; + +namespace Wpf.Ui.Interop; + /// /// The Windows UI provides users with access to a wide variety of objects necessary to run applications and manage the operating system. /// diff --git a/src/Wpf.Ui/Interop/UnsafeNativeMethods.cs b/src/Wpf.Ui/Interop/UnsafeNativeMethods.cs index ce4cf4653..e73401cca 100644 --- a/src/Wpf.Ui/Interop/UnsafeNativeMethods.cs +++ b/src/Wpf.Ui/Interop/UnsafeNativeMethods.cs @@ -2,10 +2,10 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// This Source Code is partially based on reverse engineering of the Windows Operating System, -// and is intended for use on Windows systems only. -// This Source Code is partially based on the source code provided by the .NET Foundation. + +/* This Source Code is partially based on reverse engineering of the Windows Operating System, + and is intended for use on Windows systems only. + This Source Code is partially based on the source code provided by the .NET Foundation. */ using System.Runtime.InteropServices; using Microsoft.Win32; diff --git a/src/Wpf.Ui/Interop/UnsafeReflection.cs b/src/Wpf.Ui/Interop/UnsafeReflection.cs index 891cfc77f..cb9ff3b05 100644 --- a/src/Wpf.Ui/Interop/UnsafeReflection.cs +++ b/src/Wpf.Ui/Interop/UnsafeReflection.cs @@ -2,10 +2,10 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// This Source Code is partially based on reverse engineering of the Windows Operating System, -// and is intended for use on Windows systems only. -// This Source Code is partially based on the source code provided by the .NET Foundation. + +/* This Source Code is partially based on reverse engineering of the Windows Operating System, + and is intended for use on Windows systems only. + This Source Code is partially based on the source code provided by the .NET Foundation. */ using Wpf.Ui.Controls; using Wpf.Ui.TaskBar; diff --git a/src/Wpf.Ui/Interop/User32.cs b/src/Wpf.Ui/Interop/User32.cs index cf16f0e45..d2d7e10cc 100644 --- a/src/Wpf.Ui/Interop/User32.cs +++ b/src/Wpf.Ui/Interop/User32.cs @@ -2,15 +2,15 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// This Source Code is partially based on reverse engineering of the Windows Operating System, -// and is intended for use on Windows systems only. -// This Source Code is partially based on the source code provided by the .NET Foundation. -// -// NOTE: -// I split unmanaged code stuff into the NativeMethods library. -// If you have suggestions for the code below, please submit your changes there. -// https://github.com/lepoco/nativemethods + +/* This Source Code is partially based on reverse engineering of the Windows Operating System, + and is intended for use on Windows systems only. + This Source Code is partially based on the source code provided by the .NET Foundation. + + NOTE: + I split unmanaged code stuff into the NativeMethods library. + If you have suggestions for the code below, please submit your changes there. + https://github.com/lepoco/nativemethods */ using System.Runtime.InteropServices; diff --git a/src/Wpf.Ui/Interop/UxTheme.cs b/src/Wpf.Ui/Interop/UxTheme.cs index 9eb0f7be4..479e01915 100644 --- a/src/Wpf.Ui/Interop/UxTheme.cs +++ b/src/Wpf.Ui/Interop/UxTheme.cs @@ -2,15 +2,15 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// This Source Code is partially based on reverse engineering of the Windows Operating System, -// and is intended for use on Windows systems only. -// This Source Code is partially based on the source code provided by the .NET Foundation. -// -// NOTE: -// I split unmanaged code stuff into the NativeMethods library. -// If you have suggestions for the code below, please submit your changes there. -// https://github.com/lepoco/nativemethods + +/* This Source Code is partially based on reverse engineering of the Windows Operating System, + and is intended for use on Windows systems only. + This Source Code is partially based on the source code provided by the .NET Foundation. + + NOTE: + I split unmanaged code stuff into the NativeMethods library. + If you have suggestions for the code below, please submit your changes there. + https://github.com/lepoco/nativemethods */ using System.Runtime.InteropServices; using System.Text; diff --git a/src/Wpf.Ui/Interop/WinDef/POINT.cs b/src/Wpf.Ui/Interop/WinDef/POINT.cs index 567aa6423..4aa0fd702 100644 --- a/src/Wpf.Ui/Interop/WinDef/POINT.cs +++ b/src/Wpf.Ui/Interop/WinDef/POINT.cs @@ -2,10 +2,10 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// This Source Code is partially based on reverse engineering of the Windows Operating System, -// and is intended for use on Windows systems only. -// This Source Code is partially based on the source code provided by the .NET Foundation. + +/* This Source Code is partially based on reverse engineering of the Windows Operating System, + and is intended for use on Windows systems only. + This Source Code is partially based on the source code provided by the .NET Foundation. */ using System.Runtime.InteropServices; diff --git a/src/Wpf.Ui/Interop/WinDef/POINTL.cs b/src/Wpf.Ui/Interop/WinDef/POINTL.cs index d595be474..d85aa49b5 100644 --- a/src/Wpf.Ui/Interop/WinDef/POINTL.cs +++ b/src/Wpf.Ui/Interop/WinDef/POINTL.cs @@ -2,10 +2,10 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// This Source Code is partially based on reverse engineering of the Windows Operating System, -// and is intended for use on Windows systems only. -// This Source Code is partially based on the source code provided by the .NET Foundation. + +/* This Source Code is partially based on reverse engineering of the Windows Operating System, + and is intended for use on Windows systems only. + This Source Code is partially based on the source code provided by the .NET Foundation. */ using System.Runtime.InteropServices; diff --git a/src/Wpf.Ui/Interop/WinDef/RECT.cs b/src/Wpf.Ui/Interop/WinDef/RECT.cs index 6b9e27dd8..57ade04eb 100644 --- a/src/Wpf.Ui/Interop/WinDef/RECT.cs +++ b/src/Wpf.Ui/Interop/WinDef/RECT.cs @@ -2,10 +2,10 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// This Source Code is partially based on reverse engineering of the Windows Operating System, -// and is intended for use on Windows systems only. -// This Source Code is partially based on the source code provided by the .NET Foundation. + +/* This Source Code is partially based on reverse engineering of the Windows Operating System, + and is intended for use on Windows systems only. + This Source Code is partially based on the source code provided by the .NET Foundation. */ using System.Runtime.InteropServices; diff --git a/src/Wpf.Ui/Interop/WinDef/RECTL.cs b/src/Wpf.Ui/Interop/WinDef/RECTL.cs index 2df49831f..614f69671 100644 --- a/src/Wpf.Ui/Interop/WinDef/RECTL.cs +++ b/src/Wpf.Ui/Interop/WinDef/RECTL.cs @@ -2,10 +2,10 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// This Source Code is partially based on reverse engineering of the Windows Operating System, -// and is intended for use on Windows systems only. -// This Source Code is partially based on the source code provided by the .NET Foundation. + +/* This Source Code is partially based on reverse engineering of the Windows Operating System, + and is intended for use on Windows systems only. + This Source Code is partially based on the source code provided by the .NET Foundation. */ using System.Runtime.InteropServices; diff --git a/src/Wpf.Ui/Interop/WinDef/SIZE.cs b/src/Wpf.Ui/Interop/WinDef/SIZE.cs index 6e77f4304..a0a2aa48d 100644 --- a/src/Wpf.Ui/Interop/WinDef/SIZE.cs +++ b/src/Wpf.Ui/Interop/WinDef/SIZE.cs @@ -2,10 +2,10 @@ // If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. // Copyright (C) Leszek Pomianowski and WPF UI Contributors. // All Rights Reserved. -// -// This Source Code is partially based on reverse engineering of the Windows Operating System, -// and is intended for use on Windows systems only. -// This Source Code is partially based on the source code provided by the .NET Foundation. + +/* This Source Code is partially based on reverse engineering of the Windows Operating System, + and is intended for use on Windows systems only. + This Source Code is partially based on the source code provided by the .NET Foundation. */ using System.Runtime.InteropServices; diff --git a/src/Wpf.Ui/Markup/FontIconExtension.cs b/src/Wpf.Ui/Markup/FontIconExtension.cs index f190ee91c..c0e1bf655 100644 --- a/src/Wpf.Ui/Markup/FontIconExtension.cs +++ b/src/Wpf.Ui/Markup/FontIconExtension.cs @@ -32,29 +32,24 @@ namespace Wpf.Ui.Markup; [MarkupExtensionReturnType(typeof(FontIcon))] public class FontIconExtension : MarkupExtension { + public FontIconExtension() { } + public FontIconExtension(string glyph) { Glyph = glyph; - FontFamily = new FontFamily("FluentSystemIcons"); - } - - public FontIconExtension(string glyph, FontFamily fontFamily) - : this(glyph) - { - FontFamily = fontFamily; } [ConstructorArgument("glyph")] - public string Glyph { get; set; } + public string? Glyph { get; set; } [ConstructorArgument("fontFamily")] - public FontFamily FontFamily { get; set; } + public FontFamily FontFamily { get; set; } = new("FluentSystemIcons"); public double FontSize { get; set; } public override object ProvideValue(IServiceProvider serviceProvider) { - var fontIcon = new FontIcon { Glyph = Glyph, FontFamily = FontFamily }; + FontIcon fontIcon = new() { Glyph = Glyph, FontFamily = FontFamily }; if (FontSize > 0) { diff --git a/src/Wpf.Ui/Markup/SymbolIconExtension.cs b/src/Wpf.Ui/Markup/SymbolIconExtension.cs index 90ae2ea86..98bcd335a 100644 --- a/src/Wpf.Ui/Markup/SymbolIconExtension.cs +++ b/src/Wpf.Ui/Markup/SymbolIconExtension.cs @@ -32,6 +32,8 @@ namespace Wpf.Ui.Markup; [MarkupExtensionReturnType(typeof(SymbolIcon))] public class SymbolIconExtension : MarkupExtension { + public SymbolIconExtension() { } + public SymbolIconExtension(SymbolRegular symbol) { Symbol = symbol; @@ -58,7 +60,7 @@ public SymbolIconExtension(SymbolRegular symbol, bool filled) public override object ProvideValue(IServiceProvider serviceProvider) { - var symbolIcon = new SymbolIcon { Symbol = Symbol, Filled = Filled }; + SymbolIcon symbolIcon = new() { Symbol = Symbol, Filled = Filled }; if (FontSize > 0) { diff --git a/src/Wpf.Ui/UiApplication.cs b/src/Wpf.Ui/UiApplication.cs index 0cfbe47f4..b12c0b7a9 100644 --- a/src/Wpf.Ui/UiApplication.cs +++ b/src/Wpf.Ui/UiApplication.cs @@ -23,7 +23,22 @@ public class UiApplication /// public UiApplication(Application application) { + if (application is null) + { + return; + } + + if (!ApplicationHasResources(application)) + { + return; + } + _application = application; + + System.Diagnostics.Debug.WriteLine( + $"INFO | {typeof(UiApplication)} application is {_application}", + "Wpf.Ui" + ); } /// @@ -111,4 +126,13 @@ public void Shutdown() { _application?.Shutdown(); } + + private static bool ApplicationHasResources(Application application) + { + return application + .Resources.MergedDictionaries.Where(e => e.Source is not null) + .Any(e => + e.Source.ToString().ToLower().Contains(Appearance.ApplicationThemeManager.LibraryNamespace) + ); + } } diff --git a/src/Wpf.Ui/Win32/Utilities.cs b/src/Wpf.Ui/Win32/Utilities.cs index f07dea80f..a90e9df70 100644 --- a/src/Wpf.Ui/Win32/Utilities.cs +++ b/src/Wpf.Ui/Win32/Utilities.cs @@ -140,8 +140,8 @@ out var majorObj major = (int)majorObj; } - // When the 'CurrentMajorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion' - else if ( + else // When the 'CurrentMajorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion' + if ( TryGetRegistryKey( @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion", @@ -176,8 +176,8 @@ out var minorObj minor = (int)minorObj; } - // When the 'CurrentMinorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion' - else if ( + else // When the 'CurrentMinorVersionNumber' value is not present we fallback to reading the previous key used for this: 'CurrentVersion' + if ( TryGetRegistryKey( @"SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion", diff --git a/tests/Wpf.Ui.Gallery.UnitTests/UnitTest1.cs b/tests/Wpf.Ui.Gallery.UnitTests/UnitTest1.cs index e1c337693..dbdc4b17e 100644 --- a/tests/Wpf.Ui.Gallery.UnitTests/UnitTest1.cs +++ b/tests/Wpf.Ui.Gallery.UnitTests/UnitTest1.cs @@ -1,3 +1,8 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + namespace Wpf.Ui.Gallery.UnitTests; public class UnitTest1 diff --git a/tests/Wpf.Ui.Gallery.UnitTests/Usings.cs b/tests/Wpf.Ui.Gallery.UnitTests/Usings.cs index c802f4480..d5bf6204c 100644 --- a/tests/Wpf.Ui.Gallery.UnitTests/Usings.cs +++ b/tests/Wpf.Ui.Gallery.UnitTests/Usings.cs @@ -1 +1,6 @@ +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT. +// Copyright (C) Leszek Pomianowski and WPF UI Contributors. +// All Rights Reserved. + global using Xunit;