ウィンドウが非アクティブになったらMica (マイカ) を無効にする - WinUI

ウィンドウが非アクティブになったらMica (マイカ) を無効にするコードを紹介します。

概要

こちらの記事ではMica(マイカ)を利用したウィンドウ背景を実装しました。 多くのマイカを採用しているUWPアプリではウィンドウが非アクティブになるとウィンドウ背景のマイカが無効になります。 この記事では、ウィンドウが非アクティブになったら、マイカを無効にするコードを紹介します。

実装方針

ウィンドウの Activated イベントを実装し、ウィンドウが非アクティブになったことを検出した際に、 Microsoft.UI.Composition.SystemBackdrops.SystemBackdropConfiguration オブジェクトの IsInputActive プロパティをFalseに設定します。

プログラム例

WinUI 3アプリケーションを作成します。

コード

MainWindow.xaml, WindowsSystemDispatcherQueueHelper.cs のコードはこちらの記事と同じものを利用しています。

MainWindow.xaml.cs
using Microsoft.UI.Composition.SystemBackdrops;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using WinRT;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace MicaInactiveDemo
{
  /// <summary>
  /// An empty window that can be used on its own or navigated to within a Frame.
  /// </summary>
  public sealed partial class MainWindow : Window
  {
    WindowsSystemDispatcherQueueHelper wsdqHelper;
    Microsoft.UI.Composition.SystemBackdrops.MicaController micaController;
    Microsoft.UI.Composition.SystemBackdrops.SystemBackdropConfiguration configurationSource;


    public MainWindow()
    {
      this.InitializeComponent();
      wsdqHelper = new WindowsSystemDispatcherQueueHelper();
      wsdqHelper.EnsureWindowsSystemDispatcherQueueController();
      SetBackdrop();
    }

    private void myButton_Click(object sender, RoutedEventArgs e)
    {
      myButton.Content = "Clicked";
    }

    public void SetBackdrop()
    {
      if (micaController != null) {
        micaController.Dispose();
        micaController = null;
      }
      configurationSource = null;

      TrySetMicaBackdrop();
    }

    private bool TrySetMicaBackdrop()
    {
      if (Microsoft.UI.Composition.SystemBackdrops.MicaController.IsSupported()) {
        configurationSource = new Microsoft.UI.Composition.SystemBackdrops.SystemBackdropConfiguration();
        this.Activated += Window_Activated;
        this.Closed += Window_Closed;

        configurationSource.IsInputActive = true;
        switch (((FrameworkElement)this.Content).ActualTheme) {
          case ElementTheme.Dark: configurationSource.Theme = Microsoft.UI.Composition.SystemBackdrops.SystemBackdropTheme.Dark; break;
          case ElementTheme.Light: configurationSource.Theme = Microsoft.UI.Composition.SystemBackdrops.SystemBackdropTheme.Light; break;
          case ElementTheme.Default: configurationSource.Theme = Microsoft.UI.Composition.SystemBackdrops.SystemBackdropTheme.Default; break;
        }

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

        micaController.AddSystemBackdropTarget(this.As<Microsoft.UI.Composition.ICompositionSupportsSystemBackdrop>());
        micaController.SetSystemBackdropConfiguration(configurationSource);
        return true;
      }
      return false;
    }
    
    private void Window_Activated(object sender, WindowActivatedEventArgs args)
    {
      configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated;
    }

    private void Window_Closed(object sender, WindowEventArgs args)
    {
      if (micaController != null) {
        micaController.Dispose();
        micaController = null;
      }
      this.Activated -= Window_Activated;
      configurationSource = null;
    }

  }
}

解説

WindowのActivated イベントです。ウィンドウ状態が、Deactivated の場合は、IsInputActive プロパティにfalseを設定しています。 (それ以外の場合はtrueを設定しています。)
   private void Window_Activated(object sender, WindowActivatedEventArgs args)
    {
      configurationSource.IsInputActive = args.WindowActivationState != WindowActivationState.Deactivated;
    }

WindowのClosed イベントも実装しています。ウィンドウクローズ時に、MicaControllerをDisposeすることが推奨されているようです。
    private void Window_Closed(object sender, WindowEventArgs args)
    {
      if (micaController != null) {
        micaController.Dispose();
        micaController = null;
      }
      this.Activated -= Window_Activated;
      configurationSource = null;
    }

実行結果

プロジェクトを実行します。
下図のウィンドウが表示されます。マイカが適用された背景になっています。


ほかのウィンドウをクリックして、起動したアプリケーションを非アクティブにします。 非アクティブになると、マイカの設定が無効になります。


ライトカラーのテーマでも確認します。起動時のマイカが適用されたウィンドウです。


非アクティブになった状態のウィンドウです。微妙な変化ですが、青みがなくなっていることがわかります。


ウィンドウが非アクティブ時にマイカを無効にすることができました。
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2022-08-13
作成日: 2022-08-13
iPentec all rights reserverd.