diff --git a/packages/Avalonia/AvaloniaBuildTasks.targets b/packages/Avalonia/AvaloniaBuildTasks.targets
index 33f22f4d02..6af35ff0d2 100644
--- a/packages/Avalonia/AvaloniaBuildTasks.targets
+++ b/packages/Avalonia/AvaloniaBuildTasks.targets
@@ -144,4 +144,30 @@
+
+
+ Build
+
+
+
+
+ http://127.0.0.1:6001
+ $(OutputPath)/$(AssemblyName).dll
+ MainWindow.axaml
+ $(APreviewExecutable)
+ $([System.IO.Path]::ChangeExtension('$(APreviewExecutable)', '.deps.json'))
+ $([System.IO.Path]::ChangeExtension('$(APreviewExecutable)', '.runtimeconfig.json'))
+ $([System.IO.Path]::GetFullPath('$(APreviewFile)'))
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
index e22d03273a..66ed1a27e2 100644
--- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
@@ -1395,10 +1395,8 @@ namespace Avalonia.Controls.Primitives
public object Evaluate(object? dataContext)
{
- dataContext = dataContext ?? throw new ArgumentNullException(nameof(dataContext));
-
// Only update the DataContext if necessary
- if (!dataContext.Equals(DataContext))
+ if (!Equals(dataContext, DataContext))
DataContext = dataContext;
return GetValue(ValueProperty);
diff --git a/src/Avalonia.Native/NativePlatformSettings.cs b/src/Avalonia.Native/NativePlatformSettings.cs
index 53d3da0378..42d05d831c 100644
--- a/src/Avalonia.Native/NativePlatformSettings.cs
+++ b/src/Avalonia.Native/NativePlatformSettings.cs
@@ -23,7 +23,7 @@ internal class NativePlatformSettings : DefaultPlatformSettings
AvnPlatformThemeVariant.Dark => (PlatformThemeVariant.Dark, ColorContrastPreference.NoPreference),
AvnPlatformThemeVariant.Light => (PlatformThemeVariant.Light, ColorContrastPreference.NoPreference),
AvnPlatformThemeVariant.HighContrastDark => (PlatformThemeVariant.Dark, ColorContrastPreference.High),
- AvnPlatformThemeVariant.HighContrastLight => (PlatformThemeVariant.Dark, ColorContrastPreference.High),
+ AvnPlatformThemeVariant.HighContrastLight => (PlatformThemeVariant.Light, ColorContrastPreference.High),
_ => throw new ArgumentOutOfRangeException()
};
var color = _platformSettings.AccentColor;
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs
index bef5a55b06..98e1077885 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/D2DEffects.cs
@@ -28,6 +28,9 @@ namespace Avalonia.Win32.WinRT.Composition
public static readonly Guid CLSID_D2D1Border =
new Guid(0x2A2D49C0, 0x4ACF, 0x43C7, 0x8C, 0x6A, 0x7C, 0x4A, 0x27, 0x87, 0x4D, 0x27);
+ public static readonly Guid CLSID_D2D1Opacity =
+ new Guid("811d79a4-de28-4454-8094-c64685f8bd4c");
+
public static readonly Guid CLSID_D2D1Brightness =
new Guid(0x8CEA8D1E, 0x77B0, 0x4986, 0xB3, 0xB9, 0x2F, 0x0C, 0x0E, 0xAE, 0x78, 0x87);
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs
index 1a922b4acd..10dbcfcc6b 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUIEffectBase.cs
@@ -52,6 +52,110 @@ namespace Avalonia.Win32.WinRT.Composition
_sources = null;
}
}
+
+ class BorderEffect : WinUIEffectBase
+ {
+ private readonly int _x;
+ private readonly int _y;
+ public override Guid EffectId => D2DEffects.CLSID_D2D1Border;
+ public override uint PropertyCount => 2;
+
+ public BorderEffect(int x, int y, params IGraphicsEffectSource[] _sources):base(_sources)
+ {
+ _x = x;
+ _y = y;
+ }
+
+ public override IPropertyValue? GetProperty(uint index)
+ {
+ if (index == 0)
+ return new WinRTPropertyValue((uint)_x);
+ if (index == 1)
+ return new WinRTPropertyValue((uint)_y);
+ return null;
+ }
+ }
+
+ class BlendEffect : WinUIEffectBase
+ {
+ private readonly int _mode;
+
+ public BlendEffect(int mode, params IGraphicsEffectSource[] _sources) : base(_sources)
+ {
+ _mode = mode;
+ }
+
+ public override Guid EffectId => D2DEffects.CLSID_D2D1Blend;
+ public override uint PropertyCount => 1;
+
+ public override IPropertyValue? GetProperty(uint index)
+ {
+ if (index == 0)
+ return new WinRTPropertyValue((uint)_mode);
+ return null;
+ }
+ }
+
+ class CompositeStepEffect : WinUIEffectBase
+ {
+ private readonly float _mode;
+
+ public CompositeStepEffect(int mode, params IGraphicsEffectSource[] _sources) : base(_sources)
+ {
+ _mode = mode;
+ }
+
+ public override Guid EffectId => D2DEffects.CLSID_D2D1Composite;
+ public override uint PropertyCount => 1;
+
+ public override IPropertyValue? GetProperty(uint index)
+ {
+ if (index == 0)
+ return new WinRTPropertyValue((uint)_mode);
+ return null;
+ }
+ }
+
+ class OpacityEffect : WinUIEffectBase
+ {
+ private readonly float _opacity;
+
+ public OpacityEffect(float opacity, params IGraphicsEffectSource[] _sources) : base(_sources)
+ {
+ _opacity = opacity;
+ }
+
+ public override Guid EffectId => D2DEffects.CLSID_D2D1Opacity;
+ public override uint PropertyCount => 1;
+
+ public override IPropertyValue? GetProperty(uint index)
+ {
+ if (index == 0)
+ return new WinRTPropertyValue(_opacity);
+ return null;
+ }
+ }
+
+ class ColorSourceEffect : WinUIEffectBase
+ {
+ private readonly float[] _color;
+
+ public ColorSourceEffect(float[] color)
+ {
+ _color = color;
+ }
+
+ public override Guid EffectId => D2DEffects.CLSID_D2D1Flood;
+ public override uint PropertyCount => 1;
+
+ public override IPropertyValue? GetProperty(uint index)
+ {
+ if (index == 0)
+ return new WinRTPropertyValue(_color);
+ return null;
+ }
+ }
+
internal class WinUIGaussianBlurEffect : WinUIEffectBase
{
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs
index 2f22ba99f9..d720e525d3 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositedWindow.cs
@@ -12,7 +12,8 @@ internal class WinUiCompositedWindow : IDisposable
public EglGlPlatformSurface.IEglWindowGlPlatformSurfaceInfo WindowInfo { get; }
private readonly WinUiCompositionShared _shared;
private readonly ICompositionRoundedRectangleGeometry? _compositionRoundedRectangleGeometry;
- private readonly IVisual? _mica;
+ private readonly IVisual? _micaLight;
+ private readonly IVisual? _micaDark;
private readonly IVisual _blur;
private readonly IVisual _visual;
private PixelSize _size;
@@ -25,7 +26,8 @@ internal class WinUiCompositedWindow : IDisposable
{
_compositionRoundedRectangleGeometry?.Dispose();
_blur.Dispose();
- _mica?.Dispose();
+ _micaLight?.Dispose();
+ _micaDark?.Dispose();
_visual.Dispose();
_surfaceBrush.Dispose();
_target.Dispose();
@@ -50,14 +52,20 @@ internal class WinUiCompositedWindow : IDisposable
_target.SetRoot(containerVisual);
_blur = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.BlurBrush);
- if (shared.MicaBrush != null)
+ if (shared.MicaBrushLight != null)
{
- _mica = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.MicaBrush);
- containerChildren.InsertAtTop(_mica);
+ _micaLight = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.MicaBrushLight);
+ containerChildren.InsertAtTop(_micaLight);
+ }
+
+ if (shared.MicaBrushDark != null)
+ {
+ _micaDark = WinUiCompositionUtils.CreateBlurVisual(shared.Compositor, shared.MicaBrushDark);
+ containerChildren.InsertAtTop(_micaDark);
}
_compositionRoundedRectangleGeometry =
- WinUiCompositionUtils.ClipVisual(shared.Compositor, backdropCornerRadius, _blur, _mica);
+ WinUiCompositionUtils.ClipVisual(shared.Compositor, backdropCornerRadius, _blur, _micaLight, _micaDark);
containerChildren.InsertAtTop(_blur);
using var spriteVisual = shared.Compositor.CreateSpriteVisual();
@@ -68,9 +76,6 @@ internal class WinUiCompositedWindow : IDisposable
using var compositionBrush = _surfaceBrush.QueryInterface();
spriteVisual.SetBrush(compositionBrush);
_target.SetRoot(containerVisual);
-
-
-
}
public void SetSurface(ICompositionSurface surface) => _surfaceBrush.SetSurface(surface);
@@ -79,12 +84,13 @@ internal class WinUiCompositedWindow : IDisposable
{
lock (_shared.SyncRoot)
{
-
_blur.SetIsVisible(blurEffect == BlurEffect.Acrylic
- || blurEffect == BlurEffect.Mica && _mica == null ?
+ || (blurEffect == BlurEffect.MicaLight && _micaLight == null) ||
+ (blurEffect == BlurEffect.MicaDark && _micaDark == null) ?
1 :
0);
- _mica?.SetIsVisible(blurEffect == BlurEffect.Mica ? 1 : 0);
+ _micaLight?.SetIsVisible(blurEffect == BlurEffect.MicaLight ? 1 : 0);
+ _micaDark?.SetIsVisible(blurEffect == BlurEffect.MicaDark ? 1 : 0);
}
}
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs
index b3a328d097..7a775afb3a 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionShared.cs
@@ -9,7 +9,8 @@ internal class WinUiCompositionShared : IDisposable
public ICompositor5 Compositor5 { get; }
public ICompositorDesktopInterop DesktopInterop { get; }
public ICompositionBrush BlurBrush { get; }
- public ICompositionBrush? MicaBrush { get; }
+ public ICompositionBrush? MicaBrushLight { get; }
+ public ICompositionBrush? MicaBrushDark { get; }
public object SyncRoot { get; } = new();
public static readonly Version MinWinCompositionVersion = new(10, 0, 17134);
@@ -21,14 +22,16 @@ internal class WinUiCompositionShared : IDisposable
Compositor = compositor.CloneReference();
Compositor5 = compositor.QueryInterface();
BlurBrush = WinUiCompositionUtils.CreateAcrylicBlurBackdropBrush(compositor);
- MicaBrush = WinUiCompositionUtils.CreateMicaBackdropBrush(compositor);
+ MicaBrushLight = WinUiCompositionUtils.CreateMicaBackdropBrush(compositor, 242, 0.6f);
+ MicaBrushDark = WinUiCompositionUtils.CreateMicaBackdropBrush(compositor, 32, 0.8f);
DesktopInterop = compositor.QueryInterface();
}
public void Dispose()
{
BlurBrush.Dispose();
- MicaBrush?.Dispose();
+ MicaBrushLight?.Dispose();
+ MicaBrushDark?.Dispose();
DesktopInterop.Dispose();
Compositor.Dispose();
Compositor5.Dispose();
diff --git a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs
index 7b970868df..29c1e1fe27 100644
--- a/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/Composition/WinUiCompositionUtils.cs
@@ -1,3 +1,4 @@
+using System;
using System.Numerics;
using MicroCom.Runtime;
@@ -5,16 +6,72 @@ namespace Avalonia.Win32.WinRT.Composition;
internal static class WinUiCompositionUtils
{
- public static ICompositionBrush? CreateMicaBackdropBrush(ICompositor compositor)
+ public static ICompositionBrush? CreateMicaBackdropBrush(ICompositor compositor, float color, float opacity)
{
if (Win32Platform.WindowsVersion.Build < 22000)
return null;
+ using var backDropParameterFactory =
+ NativeWinRTMethods.CreateActivationFactory(
+ "Windows.UI.Composition.CompositionEffectSourceParameter");
+
+
+ var tint = new[] { color / 255f, color / 255f, color / 255f, 255f / 255f };
+
+ using var tintColorEffect = new ColorSourceEffect(tint);
+
+
+ using var tintOpacityEffect = new OpacityEffect(1.0f, tintColorEffect);
+ using var tintOpacityEffectFactory = compositor.CreateEffectFactory(tintOpacityEffect);
+ using var tintOpacityEffectBrushEffect = tintOpacityEffectFactory.CreateBrush();
+ using var tintOpacityEffectBrush = tintOpacityEffectBrushEffect.QueryInterface();
+
+ using var luminosityColorEffect = new ColorSourceEffect(tint);
+
+ using var luminosityOpacityEffect = new OpacityEffect(opacity, luminosityColorEffect);
+ using var luminosityOpacityEffectFactory = compositor.CreateEffectFactory(luminosityOpacityEffect);
+ using var luminosityOpacityEffectBrushEffect = luminosityOpacityEffectFactory.CreateBrush();
+ using var luminosityOpacityEffectBrush =
+ luminosityOpacityEffectBrushEffect.QueryInterface();
+
using var compositorWithBlurredWallpaperBackdropBrush =
compositor.QueryInterface();
using var blurredWallpaperBackdropBrush =
compositorWithBlurredWallpaperBackdropBrush?.TryCreateBlurredWallpaperBackdropBrush();
- return blurredWallpaperBackdropBrush?.QueryInterface();
+ using var micaBackdropBrush = blurredWallpaperBackdropBrush?.QueryInterface();
+
+
+ using var backgroundParameterAsSource =
+ GetParameterSource("Background", backDropParameterFactory, out var backgroundHandle);
+ using var foregroundParameterAsSource =
+ GetParameterSource("Foreground", backDropParameterFactory, out var foregroundHandle);
+
+ using var luminosityBlendEffect =
+ new BlendEffect(23, backgroundParameterAsSource, foregroundParameterAsSource);
+ using var luminosityBlendEffectFactory = compositor.CreateEffectFactory(luminosityBlendEffect);
+ using var luminosityBlendEffectBrush = luminosityBlendEffectFactory.CreateBrush();
+ using var luminosityBlendEffectBrush1 = luminosityBlendEffectBrush.QueryInterface();
+ luminosityBlendEffectBrush.SetSourceParameter(backgroundHandle, micaBackdropBrush);
+ luminosityBlendEffectBrush.SetSourceParameter(foregroundHandle, luminosityOpacityEffectBrush);
+
+
+ using var backgroundParameterAsSource1 =
+ GetParameterSource("Background", backDropParameterFactory, out var backgroundHandle1);
+ using var foregroundParameterAsSource1 =
+ GetParameterSource("Foreground", backDropParameterFactory, out var foregroundHandle1);
+
+ using var colorBlendEffect =
+ new BlendEffect(22, backgroundParameterAsSource1, foregroundParameterAsSource1);
+ using var colorBlendEffectFactory = compositor.CreateEffectFactory(colorBlendEffect);
+ using var colorBlendEffectBrush = colorBlendEffectFactory.CreateBrush();
+ colorBlendEffectBrush.SetSourceParameter(backgroundHandle1, luminosityBlendEffectBrush1);
+ colorBlendEffectBrush.SetSourceParameter(foregroundHandle1, tintOpacityEffectBrush);
+
+
+ // colorBlendEffectBrush.SetSourceParameter(backgroundHandle, micaBackdropBrush);
+
+ using var micaBackdropBrush1 = colorBlendEffectBrush.QueryInterface();
+ return micaBackdropBrush1.CloneReference();
}
public static ICompositionBrush CreateAcrylicBlurBackdropBrush(ICompositor compositor)
@@ -97,4 +154,15 @@ internal static class WinUiCompositionUtils
brush?.Dispose();
}
}
+
+ private static IGraphicsEffectSource GetParameterSource(string name,
+ ICompositionEffectSourceParameterFactory backDropParameterFactory, out IntPtr handle)
+ {
+ var backdropString = new HStringInterop(name);
+ var backDropParameter =
+ backDropParameterFactory.Create(backdropString.Handle);
+ var backDropParameterAsSource = backDropParameter.QueryInterface();
+ handle = backdropString.Handle;
+ return backDropParameterAsSource;
+ }
}
diff --git a/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs b/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
index a3918d9ae6..5f2e752af8 100644
--- a/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/IBlurHost.cs
@@ -4,7 +4,8 @@
{
None,
Acrylic,
- Mica
+ MicaLight,
+ MicaDark
}
internal interface IBlurHost
diff --git a/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs b/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs
index 684e7ff7b5..8874902d4e 100644
--- a/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs
+++ b/src/Windows/Avalonia.Win32/WinRT/WinRTPropertyValue.cs
@@ -1,4 +1,5 @@
using System;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Avalonia.Win32.WinRT
@@ -16,7 +17,15 @@ namespace Avalonia.Win32.WinRT
UInt32 = u;
Type = PropertyType.UInt32;
}
-
+
+ public WinRTPropertyValue(float[] uiColor)
+ {
+ Type = PropertyType.SingleArray;
+ _singleArray = uiColor;
+ }
+
+ private readonly float[]? _singleArray;
+
public PropertyType Type { get; }
public int IsNumericScalar { get; }
public byte UInt8 { get; }
@@ -62,7 +71,17 @@ namespace Avalonia.Win32.WinRT
public unsafe ulong* GetUInt64Array(uint* __valueSize) => throw NotImplemented;
- public unsafe float* GetSingleArray(uint* __valueSize) => throw NotImplemented;
+ public unsafe float* GetSingleArray(uint* __valueSize)
+ {
+ if (_singleArray == null)
+ throw NotImplemented;
+ *__valueSize = (uint)_singleArray.Length;
+ var allocCoTaskMem = Marshal.AllocCoTaskMem(_singleArray.Length * Unsafe.SizeOf());
+ Marshal.Copy(_singleArray, 0, allocCoTaskMem, _singleArray.Length);
+ float* s = (float*)allocCoTaskMem;
+
+ return s;
+ }
public unsafe double* GetDoubleArray(uint* __valueSize) => throw NotImplemented;
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index 057cdb2db0..044c2cad67 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -106,6 +106,7 @@ namespace Avalonia.Win32
private static POINTER_PEN_INFO[]? s_historyPenInfos;
private static POINTER_INFO[]? s_historyInfos;
private static MOUSEMOVEPOINT[]? s_mouseHistoryInfos;
+ private PlatformThemeVariant _currentThemeVariant;
public WindowImpl()
{
@@ -474,7 +475,12 @@ namespace Avalonia.Win32
return;
SetUseHostBackdropBrush(false);
- _blurHost?.SetBlur(BlurEffect.Mica);
+ _blurHost?.SetBlur(_currentThemeVariant switch
+ {
+ PlatformThemeVariant.Light => BlurEffect.MicaLight,
+ PlatformThemeVariant.Dark => BlurEffect.MicaDark,
+ _ => throw new ArgumentOutOfRangeException()
+ });
}
private void SetAccentState(AccentState state)
@@ -778,6 +784,7 @@ namespace Avalonia.Win32
public unsafe void SetFrameThemeVariant(PlatformThemeVariant themeVariant)
{
+ _currentThemeVariant = themeVariant;
if (Win32Platform.WindowsVersion.Build >= 22000)
{
var pvUseBackdropBrush = themeVariant == PlatformThemeVariant.Dark ? 1 : 0;
@@ -786,6 +793,10 @@ namespace Avalonia.Win32
(int)DwmWindowAttribute.DWMWA_USE_IMMERSIVE_DARK_MODE,
&pvUseBackdropBrush,
sizeof(int));
+ if (TransparencyLevel == WindowTransparencyLevel.Mica)
+ {
+ SetTransparencyMica(Win32Platform.WindowsVersion);
+ }
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_SelectedValue.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_SelectedValue.cs
index e9b8895174..9ea12c62fb 100644
--- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_SelectedValue.cs
+++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests_SelectedValue.cs
@@ -268,6 +268,22 @@ namespace Avalonia.Controls.UnitTests.Primitives
Assert.True(called);
}
+ [Fact]
+ public void Handles_Null_SelectedItem_When_SelectedValueBinding_Assigned()
+ {
+ // Issue #11220
+ var items = new object[] { null };
+ var sic = new SelectingItemsControl
+ {
+ ItemsSource = items,
+ SelectedIndex = 0,
+ SelectedValueBinding = new Binding("Name"),
+ Template = Template()
+ };
+
+ Assert.Null(sic.SelectedValue);
+ }
+
private static FuncControlTemplate Template()
{
return new FuncControlTemplate((control, scope) =>