Skip to content

[API Proposal]: Backdrop switch in WPF #9966

Open
@harshit7962

Description

@harshit7962

Background and motivation

Since the introduction of Fluent Theme, the fluent applications are defaulted to use Mica as their backdrop. The option to choose from other backdrop types is not supported currently, which can restrict design flexibility. Although, an opt-out switch is provided to remove the default backdrop, it is more of a temporary solution and does not offer a complete flexibility that one might desire.

API Proposal

namespace System.Windows
{
    public abstract class WindowBackdrop() 
    {
        private protected WindowBackdrop() { }
    }

    public static class BackdropTypes
    {
        public static WindowBackdrop None { get; }
        public static WindowBackdrop Auto { get; }

        private sealed class NoneBackdrop : WindowBackdrop { }
        private sealed class AutoBackdrop : WindowBackdrop { }
    }

    public sealed class DesktopAcrylicBackdrop : WindowBackdrop { }

    public sealed class MicaBackdrop : WindowBackdrop
    {
        private MicaKind _kind = MicaKind.Base;

        public MicaKind Kind
        {
            get => _kind;
            set
            {
                if (value != MicaKind.Base && value != MicaKind.Alt)
                {
                    throw new ArgumentException("Invalid MicaKind value.");
                }

                _kind = value;

                // Update the backdrop
            }
        }
    }

    public enum MicaKind
    {
        Base = 0,
        Alt = 1
    }

    public class Window
    {
        public static readonly DependencyProperty BackdropProperty = DependencyProperty.Register(
            nameof(Backdrop), 
            typeof(WindowBackdrop), 
            typeof(Window), 
            new PropertyMetadata(BackdropTypes.None, OnBackdropChanged, CoerceBackdrop));

        public WindowBackdrop Backdrop
        {
            get => (WindowBackdrop)GetValue(BackdropProperty);
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException(nameof(value));
                }

                SetValue(BackdropProperty, value);
            }
        }
    }
}

API Usage

From Xaml
Setting Mica and Acrylic Backdrops

<Window x:Class="SampleApplication.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:SampleApplication" mc:Ignorable="d" 
    Title="Main Window" Height="500" Width="800">
    <Window.Backdrop>
        <MicaBackdrop Kind="Alt" /> <!--Or <DesktopAcrylicBackdrop />-->
    </Window.Backdrop>
    <Grid>
        <Button Content="Click Me" Click="Button_Click" />
    </Grid>
</Window>

Setting None and Auto Backdrops

<Window x:Class="SampleApplication.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:SampleApplication" mc:Ignorable="d" 
    Title="Main Window" Height="500" Width="800" Backdrop="{x:Static BackdropTypes.None}"> <!--Or BackdropTypes.Auto-->
    <Grid>
        <Button Content="Click Me" Click="Button_Click" />
    </Grid>
</Window>

From code-behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        // Setting Mica Base Backdrop
        this.Backdrop = new MicaBackdrop();

        // Setting Mica Alt Backdrop
        this.Backdrop = new MicaBackdrop
        {
            Kind = MicaKind.Alt
        };

        // Setting Acrylic Backdrop
        this.Backdrop = new DesktopAcrylicBackdrop();

        // Having no Backdrop
        this.Backdrop = BackdropTypes.None;

        // Setting Auto Backdrop
        this.Backdrop = BackdropTypes.Auto;
    }
}

Remarks

The current infra of BackdropManager relies on DWM_SYSTEMBACKDROP_TYPE and Win32s DwmSetWindowAttribute. This, at the moment does not allow us to configure the various properties of different backdrops. To have future scope of changing this infra and supporting the properties as discussed in the comment below, we have decided to have backdrop classes which would allow us to add the required properties when needed.

DWM_SYSTEMBACKDROP_TYPE enum:

typedef enum DWM_SYSTEMBACKDROP_TYPE {
  DWMSBT_AUTO,
  DWMSBT_NONE,
  DWMSBT_MAINWINDOW,
  DWMSBT_TRANSIENTWINDOW,
  DWMSBT_TABBEDWINDOW
};

Behavior of the APIs

  1. Irrespective of the Backdrop, applications on windows 10, or earlier, will not support any backdrop.
  2. The default Backdrop of a window is None.
  3. Application on High Contrast themes will not have any backdrop, that is, None.

Mapping of current Backdrops with DWM_SYSTEMBACKDROP_TYPE

Current Usage DWM_SYSTEMBACKDROP_TYPE Behaviour
<MicaBackdrop Kind="Base" /> DWMSBT_MAINWINDOW Mica
<MicaBackdrop Kind="Alt" /> DWMSBT_TABBEDWINDOW Mica-Base
<DesktopAcrylicBackdrop /> DWMSBT_TRANSIENTWINDOW Acrylic
Backdrop="{x:Static BackdropTypes.None}" DWMSBT_NONE No Backdrop
Backdrop="{x:Static BackdropTypes.Auto}" DWMSBT_Auto Based on System Settings

Alternative Designs

The previous design

  namespace System.windows
  {
      public class Application
      {
          public BackdropType Backdrop { get; set; }
      }

      public class Window
      {
          public BackdropType Backdrop { get; set; }
      }

      public enum BackdropType
      {
          None,
          Auto,
          MainWindow,
          TransientWindow,
          TabbedWindow
      }
  }

Risks

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    API suggestionEarly API idea and discussion, it is NOT ready for implementation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions