Condividi tramite


Applica materiali Mica o Acrilici nelle applicazioni desktop per Windows 11

I Materiali in Windows 11 sono effetti visivi applicati alle superfici UX che hanno la somiglianza di manufatti reali. I materiali occludenti, come l'acrilico e la mica, sono utilizzati come livelli di base sotto i controlli interattivi dell'interfaccia utente.

Mica è un materiale opaco che incorpora il tema e lo sfondo del desktop dell'utente per creare un aspetto altamente personalizzato. Mica è progettato per le prestazioni, in quanto acquisisce solo lo sfondo una volta per crearne la visualizzazione, quindi è consigliabile per il livello base dell'app, soprattutto nell'area della barra del titolo.

L'Acrilico è un materiale semitrasparente che riproduce l'effetto del vetro smerigliato. L'acrilico viene utilizzato solo per le superfici transitorie che perdono luce, come i riquadri a comparsa e i menu contestuali.

Questo articolo descrive come applicare Mica o Acrilico come livello base dell'app XAML SDK per app di Windows/WinUI 3.

Nota

Come usare un materiale di sfondo

L'app Raccolta WinUI 3 include esempi interattivi della maggior parte dei controlli e delle funzionalità di WinUI 3. Scaricare l'app da Microsoft Store od ottenere il codice sorgente su GitHub

Per applicare un materiale Mica o Acrilico alla propria app, impostare la proprietà Window.SystemBackdrop su un XAML SystemBackdrop (in genere, uno deI materiali di sfondo predefiniti, MicaBackdrop o DesktopAcrylicBackdrop).

Questi esempi mostrano come farlo in XAML e nel codice.

Mica

<Window
    ... >

    <Window.SystemBackdrop>
        <MicaBackdrop Kind="BaseAlt"/>
    </Window.SystemBackdrop>

</Window>
public MainWindow()
{
    this.InitializeComponent();

    SystemBackdrop = new MicaBackdrop() 
                        { Kind = MicaKind.BaseAlt };
}

Acrilico

<Window
    ... >

    <Window.SystemBackdrop>
        <DesktopAcrylicBackdrop/>
    </Window.SystemBackdrop>

</Window>
public MainWindow()
{
    this.InitializeComponent();

    SystemBackdrop = new DesktopAcrylicBackdrop();
}

Come usare un controller di sfondo del sistema

Nota

A partire da Windows App SDK 1.3, è possibile applicare del materiale impostando la proprietà Window.SystemBackdrop su un codice XAML SystemBackdrop come descritto nella sezione precedente. Questo è il modo consigliato per applicare un materiale.

Nella parte restante di questo articolo viene illustrato come usare le API Composition MicaController e DesktopAcrylicController .

Per usare un materiale di sfondo nella propria app, è possibile usare uno dei controller che implementa l'interfaccia ISystemBackdropController (MicaController o DesktopAcrylicController). Queste classi gestiscono sia il rendering del materiale di sfondo del sistema che la gestione dei criteri di sistema per il materiale.

Per usare la Mica come materiale di sfondo, creare un oggetto MicaController. Per usare l'acrilico, creare un oggetto DesktopAcrylicController. Il codice di configurazione e di supporto è lo stesso per ogni tipo di materiale di sfondo del sistema.

Questo codice illustra come creare un MicaController.

MicaController m_backdropController;

bool TrySetSystemBackdrop()
{
    if (MicaController.IsSupported())
    {
        ...
        m_backdropController = new MicaController();
        ...
    }
}
// namespace MUCSB = Microsoft::UI::Composition::SystemBackdrops;

winrt::MUCSB::MicaController m_backdropController{ nullptr };

void SetBackground()
{
    if (winrt::MUCSB::MicaController::IsSupported())
    {
        ...
        m_backdropController = winrt::MUCSB::MicaController();
        ...
    }
}

Per utilizzare la variante Mica Alt di Mica, creare un MicaController oggetto e impostare la proprietà Kind su MicaKind.BaseAlt.

MicaController m_backdropController;

bool TrySetSystemBackdrop()
{
    if (MicaController.IsSupported())
    {
        ...
        m_backdropController = new MicaController()
        {
            Kind = MicaKind.BaseAlt
        };
        ...
    }
}
// namespace MUCSB = Microsoft::UI::Composition::SystemBackdrops;

winrt::MUCSB::MicaController m_backdropController{ nullptr };

void SetBackground()
{
    if (winrt::MUCSB::MicaController::IsSupported())
    {
        ...
        m_backdropController = winrt::MUCSB::MicaController();
        m_backdropController.Kind(winrt::MUCSB::MicaKind::BaseAlt);
        ...
    }
}

Questo codice illustra come creare un DesktopAcrylicController.

DesktopAcrylicController m_backdropController;

bool TrySetSystemBackdrop()
{
    if (DesktopAcrylicController.IsSupported())
    {
        ...
        m_backdropController = new DesktopAcrylicController();
        ...
    }
}
// namespace MUCSB = Microsoft::UI::Composition::SystemBackdrops;

winrt::MUCSB::DesktopAcrylicController m_backdropController{ nullptr };

void SetBackground()
{
    if (winrt::MUCSB::DesktopAcrylicController::IsSupported())
    {
        ...
        m_backdropController = winrt::MUCSB::DesktopAcrylicController();
        ...
    }
}

Per impostazione predefinita, il controller risponde ai temi Chiaro e Scuro del sistema. Per eseguire l'override di questo comportamento, è possibile impostare le proprietà seguenti sul controller:

Per usare il materiale di sfondo nella propria app, sono necessari gli elementi seguenti:

  • Supporto del sistema

    Il sistema in cui viene eseguita l'app deve supportare il materiale di sfondo. Richiedere il metodo MicaController.IsSupported o il metodo DesktopAcrylicController.IsSupported per assicurarsi che il materiale di sfondo sia supportato in fase di esecuzione.

  • Una destinazione valida

    È necessario fornire una destinazione che implementa l'interfaccia ICompositionSupportsSystemBackdrop . In un'app XAML, la Finestra XAML implementa questa interfaccia e viene usata come destinazione di sfondo.

  • Un oggetto SystemBackdropConfiguration

    SystemBackdropConfiguration fornisce al controller di sfondo del sistema informazioni su criteri specifici dell'app per configurare correttamente il materiale sullo sfondo del sistema.

  • Oggetto DispatcherQueue.

    È necessario un oggetto Windows.System.DispatcherQueue nel thread XAML principale. Vedere la WindowsSystemDispatcherQueueHelper classe nel codice di esempio o nel Campione di raccolta WinUI 3.

Esempio: usare Mica in un'app di Windows AppSDK/WinUI 3

Questo esempio mostra come configurare il materiale dello sfondo Mica in un'app XAML.

Suggerimento

Vedere anche questi progetti di esempio in GitHub:

C#: SampleSystemBackdropsWindow nella raccolta WinUI3.

C++/WinRT: Campione mica Windows App SDK.

using Microsoft.UI.Composition.SystemBackdrops;
using Microsoft.UI.Xaml;
using System.Runtime.InteropServices; // For DllImport
using WinRT; // required to support Window.As<ICompositionSupportsSystemBackdrop>()

public sealed partial class MainWindow : Window
{
    WindowsSystemDispatcherQueueHelper m_wsdqHelper; // See below for implementation.
    MicaController m_backdropController;
    SystemBackdropConfiguration m_configurationSource;

    public MainWindow()
    {
        this.InitializeComponent();

        TrySetSystemBackdrop();
    }

    bool TrySetSystemBackdrop()
    {
        if (Microsoft.UI.Composition.SystemBackdrops.MicaController.IsSupported())
        {
            m_wsdqHelper = new WindowsSystemDispatcherQueueHelper();
            m_wsdqHelper.EnsureWindowsSystemDispatcherQueueController();

            // Create the policy object.
            m_configurationSource = new SystemBackdropConfiguration();
            this.Activated += Window_Activated;
            this.Closed += Window_Closed;
            ((FrameworkElement)this.Content).ActualThemeChanged += Window_ThemeChanged;

            // Initial configuration state.
            m_configurationSource.IsInputActive = true;
            SetConfigurationSourceTheme();

            m_backdropController = new Microsoft.UI.Composition.SystemBackdrops.MicaController();

            // Enable the system backdrop.
            // Note: Be sure to have "using WinRT;" to support the Window.As<...>() call.
            m_backdropController.AddSystemBackdropTarget(this.As<Microsoft.UI.Composition.ICompositionSupportsSystemBackdrop>());
            m_backdropController.SetSystemBackdropConfiguration(m_configurationSource);
            return true; // succeeded
        }

        return false; // Mica is not supported on this system
    }

    private void Window_Activated(object sender, WindowActivatedEventArgs args)
        {
            m_configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated;
        }

    private void Window_Closed(object sender, WindowEventArgs args)
        {
            // Make sure any Mica/Acrylic controller is disposed
            // so it doesn't try to use this closed window.
            if (m_backdropController != null)
            {
                m_backdropController.Dispose();
                m_backdropController = null;
            }
            this.Activated -= Window_Activated;
            m_configurationSource = null;
        }

    private void Window_ThemeChanged(FrameworkElement sender, object args)
        {
            if (m_configurationSource != null)
            {
                SetConfigurationSourceTheme();
            }
        }

    private void SetConfigurationSourceTheme()
        {
            switch (((FrameworkElement)this.Content).ActualTheme)
            {
                case ElementTheme.Dark: m_configurationSource.Theme = Microsoft.UI.Composition.SystemBackdrops.SystemBackdropTheme.Dark; break;
                case ElementTheme.Light: m_configurationSource.Theme = Microsoft.UI.Composition.SystemBackdrops.SystemBackdropTheme.Light; break;
                case ElementTheme.Default: m_configurationSource.Theme = Microsoft.UI.Composition.SystemBackdrops.SystemBackdropTheme.Default; break;
            }
        }
}

class WindowsSystemDispatcherQueueHelper
{
    [StructLayout(LayoutKind.Sequential)]
    struct DispatcherQueueOptions
    {
        internal int dwSize;
        internal int threadType;
        internal int apartmentType;
    }

    [DllImport("CoreMessaging.dll")]
    private static extern int CreateDispatcherQueueController([In] DispatcherQueueOptions options, [In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object dispatcherQueueController);

    object m_dispatcherQueueController = null;
    public void EnsureWindowsSystemDispatcherQueueController()
    {
        if (Windows.System.DispatcherQueue.GetForCurrentThread() != null)
        {
            // one already exists, so we'll just use it.
            return;
        }

        if (m_dispatcherQueueController == null)
        {
            DispatcherQueueOptions options;
            options.dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions));
            options.threadType = 2;    // DQTYPE_THREAD_CURRENT
            options.apartmentType = 2; // DQTAT_COM_STA

            CreateDispatcherQueueController(options, ref m_dispatcherQueueController);
        }
    }
}
// pch.h
...
#include <winrt/Microsoft.UI.Composition.SystemBackdrops.h>
#include <winrt/Windows.System.h>
#include <dispatcherqueue.h>

// MainWindow.xaml.h
...
namespace winrt
{
    namespace MUC = Microsoft::UI::Composition;
    namespace MUCSB = Microsoft::UI::Composition::SystemBackdrops;
    namespace MUX = Microsoft::UI::Xaml;
    namespace WS = Windows::System;
}
...
struct MainWindow : MainWindowT<MainWindow>
{
    winrt::MUCSB::SystemBackdropConfiguration m_configuration{ nullptr };
    winrt::MUCSB::MicaController m_backdropController{ nullptr };
    winrt::MUX::Window::Activated_revoker m_activatedRevoker;
    winrt::MUX::Window::Closed_revoker m_closedRevoker;
    winrt::MUX::FrameworkElement::ActualThemeChanged_revoker m_themeChangedRevoker;
    winrt::MUX::FrameworkElement m_rootElement{ nullptr };
    winrt::WS::DispatcherQueueController m_dispatcherQueueController{ nullptr };

    MainWindow::MainWindow()
    {
        InitializeComponent();

        SetBackground();

        m_closedRevoker = this->Closed(winrt::auto_revoke, [&](auto&&, auto&&)
        {
            if (nullptr != m_backdropController)
            {
                m_backdropController.Close();
                m_backdropController = nullptr;
            }

            if (nullptr != m_dispatcherQueueController)
            {
                m_dispatcherQueueController.ShutdownQueueAsync();
                m_dispatcherQueueController = nullptr;
            }
        });
    }

    void SetBackground()
    {
        if (winrt::MUCSB::MicaController::IsSupported())
        {
            // We ensure that there is a Windows.System.DispatcherQueue on the current thread.
            // Always check if one already exists before attempting to create a new one.
            if (nullptr == winrt::WS::DispatcherQueue::GetForCurrentThread() &&
                nullptr == m_dispatcherQueueController)
            {
                m_dispatcherQueueController = CreateSystemDispatcherQueueController();
            }

            // Setup the SystemBackdropConfiguration object.
            SetupSystemBackdropConfiguration();

            // Setup Mica on the current Window.
            m_backdropController = winrt::MUCSB::MicaController();
            m_backdropController.SetSystemBackdropConfiguration(m_configuration);
            m_backdropController.AddSystemBackdropTarget(
                this->m_inner.as<winrt::MUC::ICompositionSupportsSystemBackdrop>());
        }
        else
        {
            // The backdrop material is not supported.
        }
    }

    winrt::WS::DispatcherQueueController CreateSystemDispatcherQueueController()
    {
        DispatcherQueueOptions options
        {
            sizeof(DispatcherQueueOptions),
            DQTYPE_THREAD_CURRENT,
            DQTAT_COM_NONE
        };

        ::ABI::Windows::System::IDispatcherQueueController* ptr{ nullptr };
        winrt::check_hresult(CreateDispatcherQueueController(options, &ptr));
        return { ptr, take_ownership_from_abi };
    }

    void SetupSystemBackdropConfiguration()
    {
        m_configuration = winrt::MUCSB::SystemBackdropConfiguration();

        // Activation state.
        m_activatedRevoker = this->Activated(winrt::auto_revoke,
            [&](auto&&, MUX::WindowActivatedEventArgs const& args)
            {
                m_configuration.IsInputActive(
                    winrt::MUX::WindowActivationState::Deactivated != args.WindowActivationState());
            });

        // Initial state.
        m_configuration.IsInputActive(true);

        // Application theme.
        m_rootElement = this->Content().try_as<winrt::MUX::FrameworkElement>();
        if (nullptr != m_rootElement)
        {
            m_themeChangedRevoker = m_rootElement.ActualThemeChanged(winrt::auto_revoke,
                [&](auto&&, auto&&)
                {
                    m_configuration.Theme(
                        ConvertToSystemBackdropTheme(m_rootElement.ActualTheme()));
                });

            // Initial state.
            m_configuration.Theme(
                ConvertToSystemBackdropTheme(m_rootElement.ActualTheme()));
        }
    }

    winrt::MUCSB::SystemBackdropTheme ConvertToSystemBackdropTheme(
        winrt::MUX::ElementTheme const& theme)
    {
        switch (theme)
        {
        case winrt::MUX::ElementTheme::Dark:
            return winrt::MUCSB::SystemBackdropTheme::Dark;
        case winrt::MUX::ElementTheme::Light:
            return winrt::MUCSB::SystemBackdropTheme::Light;
        default:
            return winrt::MUCSB::SystemBackdropTheme::Default;
        }
    }
    ...
};
...