diff --git a/build/SourceLink.props b/build/SourceLink.props
index 1e007e01eb..9f05848881 100644
--- a/build/SourceLink.props
+++ b/build/SourceLink.props
@@ -3,7 +3,6 @@
true
false
true
- embedded
$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
@@ -15,6 +14,10 @@
true
+
+ embedded
+
+
diff --git a/samples/ControlCatalog/App.xaml.cs b/samples/ControlCatalog/App.xaml.cs
index 505f486a6d..f6d382f99d 100644
--- a/samples/ControlCatalog/App.xaml.cs
+++ b/samples/ControlCatalog/App.xaml.cs
@@ -5,6 +5,7 @@ using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Markup.Xaml.Styling;
using Avalonia.Styling;
+using Avalonia.Themes.Default;
using Avalonia.Themes.Fluent;
using ControlCatalog.ViewModels;
@@ -29,6 +30,8 @@ namespace ControlCatalog
public static FluentTheme Fluent = new FluentTheme(new Uri("avares://ControlCatalog/Styles"));
+ public static SimpleTheme Default = new SimpleTheme(new Uri("avares://ControlCatalog/Styles"));
+
public static Styles DefaultLight = new Styles
{
new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
@@ -43,14 +46,7 @@ namespace ControlCatalog
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/BaseLight.xaml")
},
- new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
- {
- Source = new Uri("avares://Avalonia.Themes.Default/Accents/BaseLight.xaml")
- },
- new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
- {
- Source = new Uri("avares://Avalonia.Themes.Default/DefaultTheme.xaml")
- }
+ Default
};
public static Styles DefaultDark = new Styles
@@ -67,14 +63,7 @@ namespace ControlCatalog
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/BaseDark.xaml")
},
- new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
- {
- Source = new Uri("avares://Avalonia.Themes.Default/Accents/BaseDark.xaml")
- },
- new StyleInclude(new Uri("resm:Styles?assembly=ControlCatalog"))
- {
- Source = new Uri("avares://Avalonia.Themes.Default/DefaultTheme.xaml")
- }
+ Default
};
public override void Initialize()
diff --git a/samples/ControlCatalog/MainView.xaml.cs b/samples/ControlCatalog/MainView.xaml.cs
index 0579355831..79cf07c8d9 100644
--- a/samples/ControlCatalog/MainView.xaml.cs
+++ b/samples/ControlCatalog/MainView.xaml.cs
@@ -63,11 +63,13 @@ namespace ControlCatalog
}
else if (theme == CatalogTheme.DefaultLight)
{
+ App.Default.Mode = Avalonia.Themes.Default.SimpleThemeMode.Light;
Application.Current.Styles[0] = App.DefaultLight;
Application.Current.Styles[1] = App.DataGridDefault;
}
else if (theme == CatalogTheme.DefaultDark)
{
+ App.Default.Mode = Avalonia.Themes.Default.SimpleThemeMode.Dark;
Application.Current.Styles[0] = App.DefaultDark;
Application.Current.Styles[1] = App.DataGridDefault;
}
diff --git a/src/Avalonia.Controls/ApiCompatBaseline.txt b/src/Avalonia.Controls/ApiCompatBaseline.txt
index 9b7d37e108..a7560c37f2 100644
--- a/src/Avalonia.Controls/ApiCompatBaseline.txt
+++ b/src/Avalonia.Controls/ApiCompatBaseline.txt
@@ -36,6 +36,7 @@ CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Controls.WindowBase' does not i
InterfacesShouldHaveSameMembers : Interface member 'public System.EventHandler Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.ShutdownRequested' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.add_ShutdownRequested(System.EventHandler)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.remove_ShutdownRequested(System.EventHandler)' is present in the implementation but not in the contract.
+InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.TryShutdown(System.Int32)' is present in the implementation but not in the contract.
CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Controls.Embedding.EmbeddableControlRoot' does not implement interface 'Avalonia.Utilities.IWeakSubscriber' in the implementation but it does in the contract.
MembersMustExist : Member 'public System.Action Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.Resized.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.Embedding.Offscreen.OffscreenTopLevelImplBase.Resized.set(System.Action)' does not exist in the implementation but it does exist in the contract.
@@ -62,4 +63,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platfor
MembersMustExist : Member 'public void Avalonia.Platform.IWindowImpl.Resize(Avalonia.Size)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowImpl.Resize(Avalonia.Size, Avalonia.Platform.PlatformResizeReason)' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public Avalonia.Platform.ITrayIconImpl Avalonia.Platform.IWindowingPlatform.CreateTrayIcon()' is present in the implementation but not in the contract.
-Total Issues: 63
+Total Issues: 64
diff --git a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
index 3a2fd68af5..edddf31d45 100644
--- a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
+++ b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs
@@ -76,36 +76,21 @@ namespace Avalonia.Controls.ApplicationLifetimes
return;
if (ShutdownMode == ShutdownMode.OnLastWindowClose && _windows.Count == 0)
- Shutdown();
- else if (ShutdownMode == ShutdownMode.OnMainWindowClose && window == MainWindow)
- Shutdown();
+ TryShutdown();
+ else if (ShutdownMode == ShutdownMode.OnMainWindowClose && ReferenceEquals(window, MainWindow))
+ TryShutdown();
}
public void Shutdown(int exitCode = 0)
{
- if (_isShuttingDown)
- throw new InvalidOperationException("Application is already shutting down.");
-
- _exitCode = exitCode;
- _isShuttingDown = true;
+ DoShutdown(new ShutdownRequestedEventArgs(), true, exitCode);
+ }
- try
- {
- foreach (var w in Windows)
- w.Close();
- var e = new ControlledApplicationLifetimeExitEventArgs(exitCode);
- Exit?.Invoke(this, e);
- _exitCode = e.ApplicationExitCode;
- }
- finally
- {
- _cts?.Cancel();
- _cts = null;
- _isShuttingDown = false;
- }
+ public bool TryShutdown(int exitCode = 0)
+ {
+ return DoShutdown(new ShutdownRequestedEventArgs(), false, exitCode);
}
-
public int Start(string[] args)
{
Startup?.Invoke(this, new ControlledApplicationLifetimeStartupEventArgs(args));
@@ -114,7 +99,10 @@ namespace Avalonia.Controls.ApplicationLifetimes
if(options != null && options.ProcessUrlActivationCommandLine && args.Length > 0)
{
- ((IApplicationPlatformEvents)Application.Current).RaiseUrlsOpened(args);
+ if (Application.Current is IApplicationPlatformEvents events)
+ {
+ events.RaiseUrlsOpened(args);
+ }
}
var lifetimeEvents = AvaloniaLocator.Current.GetService();
@@ -145,23 +133,57 @@ namespace Avalonia.Controls.ApplicationLifetimes
if (_activeLifetime == this)
_activeLifetime = null;
}
-
- private void OnShutdownRequested(object sender, ShutdownRequestedEventArgs e)
+
+ private bool DoShutdown(ShutdownRequestedEventArgs e, bool force = false, int exitCode = 0)
{
- ShutdownRequested?.Invoke(this, e);
+ if (!force)
+ {
+ ShutdownRequested?.Invoke(this, e);
- if (e.Cancel)
- return;
+ if (e.Cancel)
+ return false;
+
+ if (_isShuttingDown)
+ throw new InvalidOperationException("Application is already shutting down.");
+ }
+
+ _exitCode = exitCode;
+ _isShuttingDown = true;
- // When an OS shutdown request is received, try to close all non-owned windows. Windows can cancel
- // shutdown by setting e.Cancel = true in the Closing event. Owned windows will be shutdown by their
- // owners.
- foreach (var w in Windows)
- if (w.Owner is null)
- w.Close();
- if (Windows.Count > 0)
- e.Cancel = true;
+ try
+ {
+ // When an OS shutdown request is received, try to close all non-owned windows. Windows can cancel
+ // shutdown by setting e.Cancel = true in the Closing event. Owned windows will be shutdown by their
+ // owners.
+ foreach (var w in Windows)
+ {
+ if (w.Owner is null)
+ {
+ w.Close();
+ }
+ }
+
+ if (!force && Windows.Count > 0)
+ {
+ e.Cancel = true;
+ return false;
+ }
+
+ var args = new ControlledApplicationLifetimeExitEventArgs(exitCode);
+ Exit?.Invoke(this, args);
+ _exitCode = args.ApplicationExitCode;
+ }
+ finally
+ {
+ _cts?.Cancel();
+ _cts = null;
+ _isShuttingDown = false;
+ }
+
+ return true;
}
+
+ private void OnShutdownRequested(object sender, ShutdownRequestedEventArgs e) => DoShutdown(e);
}
public class ClassicDesktopStyleApplicationLifetimeOptions
diff --git a/src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs
index a70d5dd2f1..a83229b732 100644
--- a/src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs
+++ b/src/Avalonia.Controls/ApplicationLifetimes/IClassicDesktopStyleApplicationLifetime.cs
@@ -9,6 +9,12 @@ namespace Avalonia.Controls.ApplicationLifetimes
///
public interface IClassicDesktopStyleApplicationLifetime : IControlledApplicationLifetime
{
+ ///
+ /// Tries to Shutdown the application. event can be used to cancel the shutdown.
+ ///
+ /// An integer exit code for an application. The default exit code is 0.
+ bool TryShutdown(int exitCode = 0);
+
///
/// Gets the arguments passed to the
///
diff --git a/src/Avalonia.Controls/LayoutTransformControl.cs b/src/Avalonia.Controls/LayoutTransformControl.cs
index 83ad2b3638..a8e15ee463 100644
--- a/src/Avalonia.Controls/LayoutTransformControl.cs
+++ b/src/Avalonia.Controls/LayoutTransformControl.cs
@@ -18,7 +18,7 @@ namespace Avalonia.Controls
AvaloniaProperty.Register(nameof(LayoutTransform));
public static readonly StyledProperty UseRenderTransformProperty =
- AvaloniaProperty.Register(nameof(LayoutTransform));
+ AvaloniaProperty.Register(nameof(UseRenderTransform));
static LayoutTransformControl()
{
diff --git a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
index a2bdcd1ea8..18348571bf 100644
--- a/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
+++ b/src/Avalonia.Controls/Platform/DefaultMenuInteractionHandler.cs
@@ -101,7 +101,7 @@ namespace Avalonia.Controls.Platform
root.Deactivated -= WindowDeactivated;
}
- if (_root is TopLevel tl)
+ if (_root is TopLevel tl && tl.PlatformImpl != null)
tl.PlatformImpl.LostFocus -= TopLevelLostPlatformFocus;
_inputManagerSubscription?.Dispose();
diff --git a/src/Avalonia.Controls/Primitives/PopupRoot.cs b/src/Avalonia.Controls/Primitives/PopupRoot.cs
index 1a11778db2..c59c7c11d9 100644
--- a/src/Avalonia.Controls/Primitives/PopupRoot.cs
+++ b/src/Avalonia.Controls/Primitives/PopupRoot.cs
@@ -44,7 +44,7 @@ namespace Avalonia.Controls.Primitives
/// The dependency resolver to use. If null the default dependency resolver will be used.
///
public PopupRoot(TopLevel parent, IPopupImpl impl, IAvaloniaDependencyResolver dependencyResolver)
- : base(impl, dependencyResolver)
+ : base(ValidatingPopupImpl.Wrap(impl), dependencyResolver)
{
_parent = parent;
}
diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs
index eaee5bdb50..9eb35e0548 100644
--- a/src/Avalonia.Controls/TopLevel.cs
+++ b/src/Avalonia.Controls/TopLevel.cs
@@ -134,6 +134,8 @@ namespace Avalonia.Controls
"Could not create window implementation: maybe no windowing subsystem was initialized?");
}
+ impl = ValidatingToplevelImpl.Wrap(impl);
+
PlatformImpl = impl;
_actualTransparencyLevel = PlatformImpl.TransparencyLevel;
@@ -367,14 +369,15 @@ namespace Avalonia.Controls
Renderer?.Dispose();
Renderer = null;
+ (this as IInputRoot).MouseDevice?.TopLevelClosed(this);
+ PlatformImpl = null;
+
var logicalArgs = new LogicalTreeAttachmentEventArgs(this, this, null);
((ILogical)this).NotifyDetachedFromLogicalTree(logicalArgs);
var visualArgs = new VisualTreeAttachmentEventArgs(this, this);
OnDetachedFromVisualTreeCore(visualArgs);
-
- (this as IInputRoot).MouseDevice?.TopLevelClosed(this);
- PlatformImpl = null;
+
OnClosed(EventArgs.Empty);
LayoutManager?.Dispose();
diff --git a/src/Avalonia.Controls/ValidatingToplevel.cs b/src/Avalonia.Controls/ValidatingToplevel.cs
new file mode 100644
index 0000000000..d1edd28ebc
--- /dev/null
+++ b/src/Avalonia.Controls/ValidatingToplevel.cs
@@ -0,0 +1,337 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Controls.Platform;
+using Avalonia.Controls.Primitives.PopupPositioning;
+using Avalonia.Input;
+using Avalonia.Input.Raw;
+using Avalonia.Input.TextInput;
+using Avalonia.Platform;
+using Avalonia.Rendering;
+
+namespace Avalonia.Controls;
+
+internal class ValidatingToplevelImpl : ITopLevelImpl, ITopLevelImplWithNativeControlHost,
+ ITopLevelImplWithNativeMenuExporter, ITopLevelImplWithTextInputMethod
+{
+ private readonly ITopLevelImpl _impl;
+ private bool _disposed;
+
+ public ValidatingToplevelImpl(ITopLevelImpl impl)
+ {
+ _impl = impl ?? throw new InvalidOperationException(
+ "Could not create TopLevel implementation: maybe no windowing subsystem was initialized?");
+ }
+
+ public void Dispose()
+ {
+ _disposed = true;
+ _impl.Dispose();
+ }
+
+ protected void CheckDisposed()
+ {
+ if (_disposed)
+ throw new ObjectDisposedException(_impl.GetType().FullName);
+ }
+
+ protected ITopLevelImpl Inner
+ {
+ get
+ {
+ CheckDisposed();
+ return _impl;
+ }
+ }
+
+ public static ITopLevelImpl Wrap(ITopLevelImpl impl)
+ {
+#if DEBUG
+ if (impl is ValidatingToplevelImpl)
+ return impl;
+ return new ValidatingToplevelImpl(impl);
+#else
+ return impl;
+#endif
+ }
+
+ public Size ClientSize => Inner.ClientSize;
+ public Size? FrameSize => Inner.FrameSize;
+ public double RenderScaling => Inner.RenderScaling;
+ public IEnumerable
/// The window implementation.
public Window(IWindowImpl impl)
- : base(impl)
+ : base(ValidatingWindowImpl.Wrap(impl))
{
- impl.Closing = HandleClosing;
- impl.GotInputWhenDisabled = OnGotInputWhenDisabled;
- impl.WindowStateChanged = HandleWindowStateChanged;
+ var wrapped = (IWindowImpl)base.PlatformImpl!;
+ wrapped.Closing = HandleClosing;
+ wrapped.GotInputWhenDisabled = OnGotInputWhenDisabled;
+ wrapped.WindowStateChanged = HandleWindowStateChanged;
_maxPlatformClientSize = PlatformImpl?.MaxAutoSizeHint ?? default(Size);
- impl.ExtendClientAreaToDecorationsChanged = ExtendClientAreaToDecorationsChanged;
+ wrapped.ExtendClientAreaToDecorationsChanged = ExtendClientAreaToDecorationsChanged;
this.GetObservable(ClientSizeProperty).Skip(1).Subscribe(x => PlatformImpl?.Resize(x, PlatformResizeReason.Application));
PlatformImpl?.ShowTaskbarIcon(ShowInTaskbar);
diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs
index 5861d0452d..2207d0550a 100644
--- a/src/Avalonia.Controls/WindowBase.cs
+++ b/src/Avalonia.Controls/WindowBase.cs
@@ -57,12 +57,13 @@ namespace Avalonia.Controls
{
}
- public WindowBase(IWindowBaseImpl impl, IAvaloniaDependencyResolver dependencyResolver) : base(impl, dependencyResolver)
+ public WindowBase(IWindowBaseImpl impl, IAvaloniaDependencyResolver dependencyResolver) : base(ValidatingWindowBaseImpl.Wrap(impl), dependencyResolver)
{
Screens = new Screens(PlatformImpl?.Screen);
- impl.Activated = HandleActivated;
- impl.Deactivated = HandleDeactivated;
- impl.PositionChanged = HandlePositionChanged;
+ var wrapped = PlatformImpl!;
+ wrapped.Activated = HandleActivated;
+ wrapped.Deactivated = HandleDeactivated;
+ wrapped.PositionChanged = HandlePositionChanged;
}
///
diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml
index 45bfe5ff81..c32638f6ca 100644
--- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml
+++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml
@@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:Avalonia.Diagnostics.Views"
xmlns:diag="clr-namespace:Avalonia.Diagnostics"
+ xmlns:default="using:Avalonia.Themes.Default"
Title="Avalonia DevTools"
x:Class="Avalonia.Diagnostics.Views.MainWindow">
@@ -9,8 +10,7 @@
-
-
+
diff --git a/src/Avalonia.Themes.Default/Accents/BaseDark.xaml b/src/Avalonia.Themes.Default/Accents/BaseDark.xaml
index 5f18bac44a..1843abebfd 100644
--- a/src/Avalonia.Themes.Default/Accents/BaseDark.xaml
+++ b/src/Avalonia.Themes.Default/Accents/BaseDark.xaml
@@ -1,13 +1,9 @@
-
diff --git a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml
index 30c6d39856..6247815303 100644
--- a/src/Avalonia.Themes.Default/Accents/BaseLight.xaml
+++ b/src/Avalonia.Themes.Default/Accents/BaseLight.xaml
@@ -1,82 +1,38 @@
-
diff --git a/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj b/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
index 678f75b43f..ef200b5532 100644
--- a/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
+++ b/src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
@@ -13,10 +13,7 @@
-
-
-
-
+
diff --git a/src/Avalonia.Themes.Default/AutoCompleteBox.xaml b/src/Avalonia.Themes.Default/Controls/AutoCompleteBox.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/AutoCompleteBox.xaml
rename to src/Avalonia.Themes.Default/Controls/AutoCompleteBox.xaml
diff --git a/src/Avalonia.Themes.Default/Button.xaml b/src/Avalonia.Themes.Default/Controls/Button.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/Button.xaml
rename to src/Avalonia.Themes.Default/Controls/Button.xaml
diff --git a/src/Avalonia.Themes.Default/ButtonSpinner.xaml b/src/Avalonia.Themes.Default/Controls/ButtonSpinner.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ButtonSpinner.xaml
rename to src/Avalonia.Themes.Default/Controls/ButtonSpinner.xaml
diff --git a/src/Avalonia.Themes.Default/Calendar.xaml b/src/Avalonia.Themes.Default/Controls/Calendar.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/Calendar.xaml
rename to src/Avalonia.Themes.Default/Controls/Calendar.xaml
diff --git a/src/Avalonia.Themes.Default/CalendarButton.xaml b/src/Avalonia.Themes.Default/Controls/CalendarButton.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/CalendarButton.xaml
rename to src/Avalonia.Themes.Default/Controls/CalendarButton.xaml
diff --git a/src/Avalonia.Themes.Default/CalendarDatePicker.xaml b/src/Avalonia.Themes.Default/Controls/CalendarDatePicker.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/CalendarDatePicker.xaml
rename to src/Avalonia.Themes.Default/Controls/CalendarDatePicker.xaml
diff --git a/src/Avalonia.Themes.Default/CalendarDayButton.xaml b/src/Avalonia.Themes.Default/Controls/CalendarDayButton.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/CalendarDayButton.xaml
rename to src/Avalonia.Themes.Default/Controls/CalendarDayButton.xaml
diff --git a/src/Avalonia.Themes.Default/CalendarItem.xaml b/src/Avalonia.Themes.Default/Controls/CalendarItem.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/CalendarItem.xaml
rename to src/Avalonia.Themes.Default/Controls/CalendarItem.xaml
diff --git a/src/Avalonia.Themes.Default/CaptionButtons.xaml b/src/Avalonia.Themes.Default/Controls/CaptionButtons.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/CaptionButtons.xaml
rename to src/Avalonia.Themes.Default/Controls/CaptionButtons.xaml
diff --git a/src/Avalonia.Themes.Default/Carousel.xaml b/src/Avalonia.Themes.Default/Controls/Carousel.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/Carousel.xaml
rename to src/Avalonia.Themes.Default/Controls/Carousel.xaml
diff --git a/src/Avalonia.Themes.Default/CheckBox.xaml b/src/Avalonia.Themes.Default/Controls/CheckBox.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/CheckBox.xaml
rename to src/Avalonia.Themes.Default/Controls/CheckBox.xaml
diff --git a/src/Avalonia.Themes.Default/ComboBox.xaml b/src/Avalonia.Themes.Default/Controls/ComboBox.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ComboBox.xaml
rename to src/Avalonia.Themes.Default/Controls/ComboBox.xaml
diff --git a/src/Avalonia.Themes.Default/ComboBoxItem.xaml b/src/Avalonia.Themes.Default/Controls/ComboBoxItem.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ComboBoxItem.xaml
rename to src/Avalonia.Themes.Default/Controls/ComboBoxItem.xaml
diff --git a/src/Avalonia.Themes.Default/ContentControl.xaml b/src/Avalonia.Themes.Default/Controls/ContentControl.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ContentControl.xaml
rename to src/Avalonia.Themes.Default/Controls/ContentControl.xaml
diff --git a/src/Avalonia.Themes.Default/ContextMenu.xaml b/src/Avalonia.Themes.Default/Controls/ContextMenu.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ContextMenu.xaml
rename to src/Avalonia.Themes.Default/Controls/ContextMenu.xaml
diff --git a/src/Avalonia.Themes.Default/DataValidationErrors.xaml b/src/Avalonia.Themes.Default/Controls/DataValidationErrors.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/DataValidationErrors.xaml
rename to src/Avalonia.Themes.Default/Controls/DataValidationErrors.xaml
diff --git a/src/Avalonia.Themes.Default/DatePicker.xaml b/src/Avalonia.Themes.Default/Controls/DatePicker.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/DatePicker.xaml
rename to src/Avalonia.Themes.Default/Controls/DatePicker.xaml
diff --git a/src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml b/src/Avalonia.Themes.Default/Controls/EmbeddableControlRoot.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml
rename to src/Avalonia.Themes.Default/Controls/EmbeddableControlRoot.xaml
diff --git a/src/Avalonia.Themes.Default/Expander.xaml b/src/Avalonia.Themes.Default/Controls/Expander.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/Expander.xaml
rename to src/Avalonia.Themes.Default/Controls/Expander.xaml
diff --git a/src/Avalonia.Themes.Default/FlyoutPresenter.xaml b/src/Avalonia.Themes.Default/Controls/FlyoutPresenter.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/FlyoutPresenter.xaml
rename to src/Avalonia.Themes.Default/Controls/FlyoutPresenter.xaml
diff --git a/src/Avalonia.Themes.Default/FocusAdorner.xaml b/src/Avalonia.Themes.Default/Controls/FocusAdorner.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/FocusAdorner.xaml
rename to src/Avalonia.Themes.Default/Controls/FocusAdorner.xaml
diff --git a/src/Avalonia.Themes.Default/GridSplitter.xaml b/src/Avalonia.Themes.Default/Controls/GridSplitter.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/GridSplitter.xaml
rename to src/Avalonia.Themes.Default/Controls/GridSplitter.xaml
diff --git a/src/Avalonia.Themes.Default/ItemsControl.xaml b/src/Avalonia.Themes.Default/Controls/ItemsControl.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ItemsControl.xaml
rename to src/Avalonia.Themes.Default/Controls/ItemsControl.xaml
diff --git a/src/Avalonia.Themes.Default/Label.xaml b/src/Avalonia.Themes.Default/Controls/Label.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/Label.xaml
rename to src/Avalonia.Themes.Default/Controls/Label.xaml
diff --git a/src/Avalonia.Themes.Default/ListBox.xaml b/src/Avalonia.Themes.Default/Controls/ListBox.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ListBox.xaml
rename to src/Avalonia.Themes.Default/Controls/ListBox.xaml
diff --git a/src/Avalonia.Themes.Default/ListBoxItem.xaml b/src/Avalonia.Themes.Default/Controls/ListBoxItem.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ListBoxItem.xaml
rename to src/Avalonia.Themes.Default/Controls/ListBoxItem.xaml
diff --git a/src/Avalonia.Themes.Default/ManagedFileChooser.xaml b/src/Avalonia.Themes.Default/Controls/ManagedFileChooser.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ManagedFileChooser.xaml
rename to src/Avalonia.Themes.Default/Controls/ManagedFileChooser.xaml
diff --git a/src/Avalonia.Themes.Default/Menu.xaml b/src/Avalonia.Themes.Default/Controls/Menu.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/Menu.xaml
rename to src/Avalonia.Themes.Default/Controls/Menu.xaml
diff --git a/src/Avalonia.Themes.Default/MenuFlyoutPresenter.xaml b/src/Avalonia.Themes.Default/Controls/MenuFlyoutPresenter.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/MenuFlyoutPresenter.xaml
rename to src/Avalonia.Themes.Default/Controls/MenuFlyoutPresenter.xaml
diff --git a/src/Avalonia.Themes.Default/MenuItem.xaml b/src/Avalonia.Themes.Default/Controls/MenuItem.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/MenuItem.xaml
rename to src/Avalonia.Themes.Default/Controls/MenuItem.xaml
diff --git a/src/Avalonia.Themes.Default/NativeMenuBar.xaml b/src/Avalonia.Themes.Default/Controls/NativeMenuBar.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/NativeMenuBar.xaml
rename to src/Avalonia.Themes.Default/Controls/NativeMenuBar.xaml
diff --git a/src/Avalonia.Themes.Default/NotificationCard.xaml b/src/Avalonia.Themes.Default/Controls/NotificationCard.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/NotificationCard.xaml
rename to src/Avalonia.Themes.Default/Controls/NotificationCard.xaml
diff --git a/src/Avalonia.Themes.Default/NumericUpDown.xaml b/src/Avalonia.Themes.Default/Controls/NumericUpDown.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/NumericUpDown.xaml
rename to src/Avalonia.Themes.Default/Controls/NumericUpDown.xaml
diff --git a/src/Avalonia.Themes.Default/OverlayPopupHost.xaml b/src/Avalonia.Themes.Default/Controls/OverlayPopupHost.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/OverlayPopupHost.xaml
rename to src/Avalonia.Themes.Default/Controls/OverlayPopupHost.xaml
diff --git a/src/Avalonia.Themes.Default/PathIcon.xaml b/src/Avalonia.Themes.Default/Controls/PathIcon.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/PathIcon.xaml
rename to src/Avalonia.Themes.Default/Controls/PathIcon.xaml
diff --git a/src/Avalonia.Themes.Default/PopupRoot.xaml b/src/Avalonia.Themes.Default/Controls/PopupRoot.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/PopupRoot.xaml
rename to src/Avalonia.Themes.Default/Controls/PopupRoot.xaml
diff --git a/src/Avalonia.Themes.Default/ProgressBar.xaml b/src/Avalonia.Themes.Default/Controls/ProgressBar.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ProgressBar.xaml
rename to src/Avalonia.Themes.Default/Controls/ProgressBar.xaml
diff --git a/src/Avalonia.Themes.Default/RadioButton.xaml b/src/Avalonia.Themes.Default/Controls/RadioButton.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/RadioButton.xaml
rename to src/Avalonia.Themes.Default/Controls/RadioButton.xaml
diff --git a/src/Avalonia.Themes.Default/RepeatButton.xaml b/src/Avalonia.Themes.Default/Controls/RepeatButton.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/RepeatButton.xaml
rename to src/Avalonia.Themes.Default/Controls/RepeatButton.xaml
diff --git a/src/Avalonia.Themes.Default/ScrollBar.xaml b/src/Avalonia.Themes.Default/Controls/ScrollBar.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ScrollBar.xaml
rename to src/Avalonia.Themes.Default/Controls/ScrollBar.xaml
diff --git a/src/Avalonia.Themes.Default/ScrollViewer.xaml b/src/Avalonia.Themes.Default/Controls/ScrollViewer.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ScrollViewer.xaml
rename to src/Avalonia.Themes.Default/Controls/ScrollViewer.xaml
diff --git a/src/Avalonia.Themes.Default/Separator.xaml b/src/Avalonia.Themes.Default/Controls/Separator.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/Separator.xaml
rename to src/Avalonia.Themes.Default/Controls/Separator.xaml
diff --git a/src/Avalonia.Themes.Default/Slider.xaml b/src/Avalonia.Themes.Default/Controls/Slider.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/Slider.xaml
rename to src/Avalonia.Themes.Default/Controls/Slider.xaml
diff --git a/src/Avalonia.Themes.Default/SplitView.xaml b/src/Avalonia.Themes.Default/Controls/SplitView.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/SplitView.xaml
rename to src/Avalonia.Themes.Default/Controls/SplitView.xaml
diff --git a/src/Avalonia.Themes.Default/TabControl.xaml b/src/Avalonia.Themes.Default/Controls/TabControl.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/TabControl.xaml
rename to src/Avalonia.Themes.Default/Controls/TabControl.xaml
diff --git a/src/Avalonia.Themes.Default/TabItem.xaml b/src/Avalonia.Themes.Default/Controls/TabItem.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/TabItem.xaml
rename to src/Avalonia.Themes.Default/Controls/TabItem.xaml
diff --git a/src/Avalonia.Themes.Default/TabStrip.xaml b/src/Avalonia.Themes.Default/Controls/TabStrip.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/TabStrip.xaml
rename to src/Avalonia.Themes.Default/Controls/TabStrip.xaml
diff --git a/src/Avalonia.Themes.Default/TabStripItem.xaml b/src/Avalonia.Themes.Default/Controls/TabStripItem.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/TabStripItem.xaml
rename to src/Avalonia.Themes.Default/Controls/TabStripItem.xaml
diff --git a/src/Avalonia.Themes.Default/TextBox.xaml b/src/Avalonia.Themes.Default/Controls/TextBox.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/TextBox.xaml
rename to src/Avalonia.Themes.Default/Controls/TextBox.xaml
diff --git a/src/Avalonia.Themes.Default/TimePicker.xaml b/src/Avalonia.Themes.Default/Controls/TimePicker.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/TimePicker.xaml
rename to src/Avalonia.Themes.Default/Controls/TimePicker.xaml
diff --git a/src/Avalonia.Themes.Default/TitleBar.xaml b/src/Avalonia.Themes.Default/Controls/TitleBar.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/TitleBar.xaml
rename to src/Avalonia.Themes.Default/Controls/TitleBar.xaml
diff --git a/src/Avalonia.Themes.Default/ToggleButton.xaml b/src/Avalonia.Themes.Default/Controls/ToggleButton.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ToggleButton.xaml
rename to src/Avalonia.Themes.Default/Controls/ToggleButton.xaml
diff --git a/src/Avalonia.Themes.Default/ToggleSwitch.xaml b/src/Avalonia.Themes.Default/Controls/ToggleSwitch.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ToggleSwitch.xaml
rename to src/Avalonia.Themes.Default/Controls/ToggleSwitch.xaml
diff --git a/src/Avalonia.Themes.Default/ToolTip.xaml b/src/Avalonia.Themes.Default/Controls/ToolTip.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/ToolTip.xaml
rename to src/Avalonia.Themes.Default/Controls/ToolTip.xaml
diff --git a/src/Avalonia.Themes.Default/TreeView.xaml b/src/Avalonia.Themes.Default/Controls/TreeView.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/TreeView.xaml
rename to src/Avalonia.Themes.Default/Controls/TreeView.xaml
diff --git a/src/Avalonia.Themes.Default/TreeViewItem.xaml b/src/Avalonia.Themes.Default/Controls/TreeViewItem.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/TreeViewItem.xaml
rename to src/Avalonia.Themes.Default/Controls/TreeViewItem.xaml
diff --git a/src/Avalonia.Themes.Default/UserControl.xaml b/src/Avalonia.Themes.Default/Controls/UserControl.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/UserControl.xaml
rename to src/Avalonia.Themes.Default/Controls/UserControl.xaml
diff --git a/src/Avalonia.Themes.Default/Window.xaml b/src/Avalonia.Themes.Default/Controls/Window.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/Window.xaml
rename to src/Avalonia.Themes.Default/Controls/Window.xaml
diff --git a/src/Avalonia.Themes.Default/WindowNotificationManager.xaml b/src/Avalonia.Themes.Default/Controls/WindowNotificationManager.xaml
similarity index 100%
rename from src/Avalonia.Themes.Default/WindowNotificationManager.xaml
rename to src/Avalonia.Themes.Default/Controls/WindowNotificationManager.xaml
diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml b/src/Avalonia.Themes.Default/DefaultTheme.xaml
index 109fde390c..702fcc7c7a 100644
--- a/src/Avalonia.Themes.Default/DefaultTheme.xaml
+++ b/src/Avalonia.Themes.Default/DefaultTheme.xaml
@@ -2,65 +2,65 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Avalonia.Themes.Default.DefaultTheme">
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml.cs b/src/Avalonia.Themes.Default/DefaultTheme.xaml.cs
index effdb88537..598b418977 100644
--- a/src/Avalonia.Themes.Default/DefaultTheme.xaml.cs
+++ b/src/Avalonia.Themes.Default/DefaultTheme.xaml.cs
@@ -1,4 +1,3 @@
-using Avalonia.Markup.Xaml;
using Avalonia.Styling;
namespace Avalonia.Themes.Default
diff --git a/src/Avalonia.Themes.Default/SimpleTheme.cs b/src/Avalonia.Themes.Default/SimpleTheme.cs
new file mode 100644
index 0000000000..1d9f2d5f9d
--- /dev/null
+++ b/src/Avalonia.Themes.Default/SimpleTheme.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+using Avalonia.Markup.Xaml.Styling;
+using Avalonia.Styling;
+#nullable enable
+
+namespace Avalonia.Themes.Default
+{
+ public class SimpleTheme : AvaloniaObject, IStyle, IResourceProvider
+ {
+ public static readonly StyledProperty ModeProperty =
+ AvaloniaProperty.Register(nameof(Mode));
+
+ private readonly Uri _baseUri;
+ private bool _isLoading;
+ private IStyle? _loaded;
+ private Styles _sharedStyles = new();
+ private Styles _simpleDark = new();
+ private Styles _simpleLight = new();
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The base URL for the XAML context.
+ public SimpleTheme(Uri baseUri)
+ {
+ _baseUri = baseUri;
+ InitStyles(_baseUri);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The XAML service provider.
+ public SimpleTheme(IServiceProvider serviceProvider)
+ {
+ var service = serviceProvider.GetService(typeof(IUriContext));
+ if (service == null)
+ {
+ throw new Exception("There is no service object of type IUriContext!");
+ }
+ _baseUri = ((IUriContext)service).BaseUri;
+ InitStyles(_baseUri);
+ }
+
+ public event EventHandler OwnerChanged
+ {
+ add
+ {
+ if (Loaded is IResourceProvider rp)
+ {
+ rp.OwnerChanged += value;
+ }
+ }
+ remove
+ {
+ if (Loaded is IResourceProvider rp)
+ {
+ rp.OwnerChanged -= value;
+ }
+ }
+ }
+
+ IReadOnlyList IStyle.Children => _loaded?.Children ?? Array.Empty();
+
+ bool IResourceNode.HasResources => (Loaded as IResourceProvider)?.HasResources ?? false;
+
+ public IStyle Loaded
+ {
+ get
+ {
+ if (_loaded == null)
+ {
+ _isLoading = true;
+
+ if (Mode == SimpleThemeMode.Light)
+ {
+ _loaded = new Styles { _sharedStyles, _simpleLight };
+ }
+ else if (Mode == SimpleThemeMode.Dark)
+ {
+ _loaded = new Styles { _sharedStyles, _simpleDark };
+ }
+ _isLoading = false;
+ }
+
+ return _loaded!;
+ }
+ }
+
+ ///
+ /// Gets or sets the mode of the fluent theme (light, dark).
+ ///
+ public SimpleThemeMode Mode
+ {
+ get => GetValue(ModeProperty);
+ set => SetValue(ModeProperty, value);
+ }
+ public IResourceHost? Owner => (Loaded as IResourceProvider)?.Owner;
+
+ void IResourceProvider.AddOwner(IResourceHost owner) => (Loaded as IResourceProvider)?.AddOwner(owner);
+
+ void IResourceProvider.RemoveOwner(IResourceHost owner) => (Loaded as IResourceProvider)?.RemoveOwner(owner);
+
+ public SelectorMatchResult TryAttach(IStyleable target, IStyleHost? host) => Loaded.TryAttach(target, host);
+
+ public bool TryGetResource(object key, out object? value)
+ {
+ if (!_isLoading && Loaded is IResourceProvider p)
+ {
+ return p.TryGetResource(key, out value);
+ }
+
+ value = null;
+ return false;
+ }
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+ if (change.Property == ModeProperty)
+ {
+ if (Mode == SimpleThemeMode.Dark)
+ {
+ (Loaded as Styles)![1] = _simpleDark[0];
+ }
+ else
+ {
+ (Loaded as Styles)![1] = _simpleLight[0];
+ }
+ }
+ }
+
+ private void InitStyles(Uri baseUri)
+ {
+ _sharedStyles = new Styles
+ {
+ new StyleInclude(baseUri)
+ {
+ Source = new Uri("avares://Avalonia.Themes.Default/DefaultTheme.xaml")
+ },
+ new StyleInclude(baseUri)
+ {
+ Source = new Uri("avares://Avalonia.Themes.Default/Accents/Base.xaml")
+ }
+ };
+ _simpleLight = new Styles
+ {
+ new StyleInclude(baseUri)
+ {
+ Source = new Uri("avares://Avalonia.Themes.Default/Accents/BaseLight.xaml")
+ }
+ };
+
+ _simpleDark = new Styles
+ {
+ new StyleInclude(baseUri)
+ {
+ Source = new Uri("avares://Avalonia.Themes.Default/Accents/BaseDark.xaml")
+ }
+ };
+ }
+
+ }
+}
diff --git a/src/Avalonia.Themes.Default/SimpleThemeMode.cs b/src/Avalonia.Themes.Default/SimpleThemeMode.cs
new file mode 100644
index 0000000000..be33466327
--- /dev/null
+++ b/src/Avalonia.Themes.Default/SimpleThemeMode.cs
@@ -0,0 +1,8 @@
+namespace Avalonia.Themes.Default
+{
+ public enum SimpleThemeMode
+ {
+ Light,
+ Dark
+ }
+}
diff --git a/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml b/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml
index f2344ab380..836cc27db3 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ButtonSpinner.xaml
@@ -1,7 +1,8 @@
+ xmlns:converters="clr-namespace:Avalonia.Controls.Converters;assembly=Avalonia.Controls"
+ x:CompileBindings="True">
diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml
index ca538e4b0a..3a6af60983 100644
--- a/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/CalendarButton.xaml
@@ -11,7 +11,7 @@
-
+
diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml
index 26c3bbc19f..ffd3972b66 100644
--- a/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/CalendarDatePicker.xaml
@@ -7,7 +7,8 @@
+ xmlns:sys="clr-namespace:System;assembly=netstandard"
+ x:CompileBindings="True">
-
+
diff --git a/src/Avalonia.Themes.Fluent/Controls/CalendarItem.xaml b/src/Avalonia.Themes.Fluent/Controls/CalendarItem.xaml
index 5bf3ac11af..a9c8281cf0 100644
--- a/src/Avalonia.Themes.Fluent/Controls/CalendarItem.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/CalendarItem.xaml
@@ -6,7 +6,9 @@
-->
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:CompileBindings="True"
+ x:DataType="CalendarItem">
@@ -32,6 +34,7 @@
-
\ No newline at end of file
+
diff --git a/src/Avalonia.Themes.Fluent/Controls/MenuItem.xaml b/src/Avalonia.Themes.Fluent/Controls/MenuItem.xaml
index 72c25cea37..831537f578 100644
--- a/src/Avalonia.Themes.Fluent/Controls/MenuItem.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/MenuItem.xaml
@@ -1,7 +1,9 @@
+ xmlns:sys="clr-namespace:System;assembly=netstandard"
+ x:DataType="MenuItem"
+ x:CompileBindings="True">
diff --git a/src/Avalonia.Themes.Fluent/Controls/NativeMenuBar.xaml b/src/Avalonia.Themes.Fluent/Controls/NativeMenuBar.xaml
index 799fe6ffe4..243095c004 100644
--- a/src/Avalonia.Themes.Fluent/Controls/NativeMenuBar.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/NativeMenuBar.xaml
@@ -1,6 +1,7 @@
diff --git a/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml b/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
index 3320fc9a41..9aa73fc52e 100644
--- a/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/TimePicker.xaml
@@ -7,7 +7,8 @@
+ xmlns:sys="clr-namespace:System;assembly=netstandard"
+ x:CompileBindings="True">
40
1
diff --git a/src/Avalonia.Themes.Fluent/Controls/ToolTip.xaml b/src/Avalonia.Themes.Fluent/Controls/ToolTip.xaml
index debdfb2772..2d18be91cb 100644
--- a/src/Avalonia.Themes.Fluent/Controls/ToolTip.xaml
+++ b/src/Avalonia.Themes.Fluent/Controls/ToolTip.xaml
@@ -1,6 +1,7 @@
+ xmlns:sys="clr-namespace:System;assembly=netstandard"
+ x:CompileBindings="True">
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:DataType="WindowNotificationManager"
+ x:CompileBindings="True">
";
var styles = AvaloniaRuntimeXamlLoader.Parse(xaml);
diff --git a/tests/Avalonia.RenderTests/Media/StreamGeometryTests.cs b/tests/Avalonia.RenderTests/Media/StreamGeometryTests.cs
new file mode 100644
index 0000000000..fc9cbf6a7f
--- /dev/null
+++ b/tests/Avalonia.RenderTests/Media/StreamGeometryTests.cs
@@ -0,0 +1,56 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Avalonia.Controls;
+using Avalonia.Controls.Shapes;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Xunit;
+
+#if AVALONIA_SKIA
+namespace Avalonia.Skia.RenderTests
+#else
+namespace Avalonia.Direct2D1.RenderTests.Media
+#endif
+{
+ public class StreamGeometryTests : TestBase
+ {
+ public StreamGeometryTests()
+ : base(@"Media\StreamGeometry")
+ {
+ }
+
+ [Fact]
+ public async Task PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions()
+ {
+ var grid = new Avalonia.Controls.Primitives.UniformGrid() { Columns = 2, Rows = 4, Width = 320, Height = 400 };
+ foreach (var sweepDirection in new[] { SweepDirection.Clockwise, SweepDirection.CounterClockwise })
+ foreach (var isLargeArc in new[] { false, true })
+ foreach (var isPrecise in new[] { false, true })
+ {
+ Point Pt(double x, double y) => new Point(x, y);
+ Size Sz(double w, double h) => new Size(w, h);
+ var streamGeometry = new StreamGeometry();
+ using (var context = streamGeometry.Open())
+ {
+ context.BeginFigure(Pt(20, 20), true);
+
+ if(isPrecise)
+ context.PreciseArcTo(Pt(40, 40), Sz(20, 20), 0, isLargeArc, sweepDirection);
+ else
+ context.ArcTo(Pt(40, 40), Sz(20, 20), 0, isLargeArc, sweepDirection);
+ context.LineTo(Pt(40, 20));
+ context.LineTo(Pt(20, 20));
+ context.EndFigure(true);
+ }
+ var pathShape = new Avalonia.Controls.Shapes.Path();
+ pathShape.Data = streamGeometry;
+ pathShape.Stroke = new SolidColorBrush(Colors.CornflowerBlue);
+ pathShape.Fill = new SolidColorBrush(Colors.Gold);
+ pathShape.StrokeThickness = 2;
+ pathShape.Margin = new Thickness(20);
+ grid.Children.Add(pathShape);
+ }
+ await RenderToFile(grid);
+ }
+ }
+}
diff --git a/tests/Avalonia.UnitTests/TestServices.cs b/tests/Avalonia.UnitTests/TestServices.cs
index 2b57a6db01..da678fd74b 100644
--- a/tests/Avalonia.UnitTests/TestServices.cs
+++ b/tests/Avalonia.UnitTests/TestServices.cs
@@ -174,7 +174,7 @@ namespace Avalonia.UnitTests
};
var baseLight = (IStyle)AvaloniaXamlLoader.Load(
- new Uri("resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"));
+ new Uri("avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"));
result.Add(baseLight);
return result;
diff --git a/tests/Avalonia.UnitTests/UnitTestApplication.cs b/tests/Avalonia.UnitTests/UnitTestApplication.cs
index 2d37057779..dc10754ea2 100644
--- a/tests/Avalonia.UnitTests/UnitTestApplication.cs
+++ b/tests/Avalonia.UnitTests/UnitTestApplication.cs
@@ -10,6 +10,7 @@ using System.Reactive.Disposables;
using System.Reactive.Concurrency;
using Avalonia.Input.Platform;
using Avalonia.Animation;
+using Avalonia.Shared.PlatformSupport;
namespace Avalonia.UnitTests
{
@@ -29,6 +30,11 @@ namespace Avalonia.UnitTests
RegisterServices();
}
+ static UnitTestApplication()
+ {
+ AssetLoader.RegisterResUriParsers();
+ }
+
public static new UnitTestApplication Current => (UnitTestApplication)Application.Current;
public TestServices Services => _services;
diff --git a/tests/TestFiles/Direct2D1/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.deferred.expected.png b/tests/TestFiles/Direct2D1/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.deferred.expected.png
new file mode 100644
index 0000000000..825b1d7ea7
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.deferred.expected.png differ
diff --git a/tests/TestFiles/Direct2D1/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.immediate.expected.png b/tests/TestFiles/Direct2D1/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.immediate.expected.png
new file mode 100644
index 0000000000..825b1d7ea7
Binary files /dev/null and b/tests/TestFiles/Direct2D1/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.immediate.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.deferred.expected.png b/tests/TestFiles/Skia/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.deferred.expected.png
new file mode 100644
index 0000000000..f7cc90678a
Binary files /dev/null and b/tests/TestFiles/Skia/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.deferred.expected.png differ
diff --git a/tests/TestFiles/Skia/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.immediate.expected.png b/tests/TestFiles/Skia/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.immediate.expected.png
new file mode 100644
index 0000000000..f7cc90678a
Binary files /dev/null and b/tests/TestFiles/Skia/Media/StreamGeometry/PreciseEllipticArc_Produces_Valid_Arcs_In_All_Directions.immediate.expected.png differ