Quantcast
Channel: SourceChord
Viewing all 153 articles
Browse latest View live

WPFでFluent Design Systemのアクリルっぽいウィンドウを作ってみる

$
0
0

この記事は、XAML Advent Calendar 2017の1日目の記事です。

今年のbuildでは、Fluent Design Systemが発表され、Windowsの各種UIでも徐々にこういうデザインの部分が増えてきました。

このFluent Designですが、UWPからは簡単に実装することができるAPIが色々用意されています。 しかし、残念ながらWPFでこのようなデザインを実装するための手段は用意されていません。

そうは言っても、WPFでもこういうカッコいいデザインのウィンドウを作ってみたいですよね。
ということでWPFでこういうFluent Designのアクリル風なウィンドウを真似してみました。

f:id:minami_SC:20171201234528g:plain

Windowを半透明にする方法

Fluent Design Systemのアクリル効果を適用するAPIはUWP用のものしかなく、WPF向のAPIはありません。
また、Win32APIでもこのようなアクリル化を行うAPIはないので、デスクトップアプリでFluentDesignと同等のアクリル効果を出すことはできません。

完全に同じ効果を出すことはできませんが、Windowsの非公開APIでSetWindowCompositionAttributeという関数があり、このAPIを使うとウィンドウ背景をいい感じにぼかすことができます。

FluentDesingのボケ方とはちょっと違うんですが、現状WPFでそれっぽい表示をする方法はこれしか見当たりません。。。
ということで、この非公開APIを使って、アクリルっぽいウィンドウを作ってみました。

参考リンク

以下のリポジトリで行っているアクリルエフェクトを参考にやってみました。 https://github.com/bbougot/AcrylicWPF上記リポジトリのサンプルでも、SetWindowCompositionAttribute関数を使って背景のぼかし処理を行っています。

SetWindowCompositionAttribute関数を使ったぼかし処理については↓の記事も参考になります。 https://withinrafael.com/2015/07/08/adding-the-aero-glass-blur-to-your-windows-10-apps/

サンプルコード

とりあえず、XAMLとコードビハインドをそれぞれ以下のように書いてみます。

MainWindow.xaml

WindowChromeを設定し、GlassFrameThickness="-1"と設定して、ウィンドウのクライアント領域全体を透かすようにしてます。
また、以下の画像のようなノイズ画像を用意し、ぼかし背景の全面に少しノイズを加えています。
f:id:minami_SC:20171201234854p:plain

<Window x:Class="AcrylicWindowSample.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:local="clr-namespace:AcrylicWindowSample"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Title="MainWindow"Width="525"Height="350"BorderBrush="#FF2990CC"BorderThickness="1"mc:Ignorable="d"><WindowChrome.WindowChrome><WindowChrome CaptionHeight="{x:Static SystemParameters.CaptionHeight}"GlassFrameThickness="-1"ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}"UseAeroCaptionButtons="True" /></WindowChrome.WindowChrome><Window.Background><!-- Tiled noise texture --><ImageBrush ImageSource="Images/noise.png"Opacity="0.05"Stretch="None"TileMode="Tile"Viewport="0,0,128,128"ViewportUnits="Absolute" /></Window.Background><Grid><TextBlock HorizontalAlignment="Center"VerticalAlignment="Center"FontSize="46"Foreground="CornflowerBlue"Text="Acrylic Window"><TextBlock.Effect><DropShadowEffect ShadowDepth="0"BlurRadius="35"Color="DarkGray"Opacity="0.8" /></TextBlock.Effect></TextBlock></Grid></Window>
MainWindow.xaml.cs

コードビハインドでは、EnableBlurという関数を作り、この関数の中で非公開APIのSetWindowCompositionAttribute関数を使ったウィンドウのぼかし処理を実装します。
また、このEnableBlurメソッドは、OnApplyTemplateのタイミングで呼び出しを行います。

namespace AcrylicWindowSample
{
    [StructLayout(LayoutKind.Sequential)]
    internalstruct WindowCompositionAttributeData
    {
        public WindowCompositionAttribute Attribute;
        public IntPtr Data;
        publicint SizeOfData;
    }

    internalenum WindowCompositionAttribute
    {
        WCA_ACCENT_POLICY = 19
    }

    internalenum AccentState
    {
        ACCENT_DISABLED = 0,
        ACCENT_ENABLE_GRADIENT = 1,
        ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
        ACCENT_ENABLE_BLURBEHIND = 3,
        ACCENT_INVALID_STATE = 4
    }

    [StructLayout(LayoutKind.Sequential)]
    internalstruct AccentPolicy
    {
        public AccentState AccentState;
        publicint AccentFlags;
        publicuint GradientColor;
        publicint AnimationId;
    }

    /// <summary>/// MainWindow.xaml の相互作用ロジック/// </summary>publicpartialclass MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        publicoverridevoid OnApplyTemplate()
        {
            base.OnApplyTemplate();
            // ウィンドウ背景のぼかし効果を有効にする
            EnableBlur(this);
        }


        [DllImport("user32.dll")]
        internalstaticexternint SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data);

        internalstaticvoid EnableBlur(Window win)
        {
            var windowHelper = new WindowInteropHelper(win);

            var accent = new AccentPolicy();
            var accentStructSize = Marshal.SizeOf(accent);
            accent.AccentState = AccentState.ACCENT_ENABLE_BLURBEHIND;
            accent.AccentFlags = 2;
            //               ↓の色はAABBGGRRの順番で設定する
            accent.GradientColor = 0x99FFFFFF;  // 60%の透明度が基本

            var accentPtr = Marshal.AllocHGlobal(accentStructSize);
            Marshal.StructureToPtr(accent, accentPtr, false);

            var data = new WindowCompositionAttributeData();
            data.Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY;
            data.SizeOfData = accentStructSize;
            data.Data = accentPtr;

            SetWindowCompositionAttribute(windowHelper.Handle, ref data);

            Marshal.FreeHGlobal(accentPtr);
        }

    }
}

実行結果

こんな風に、ちょっとFluentDesignっぽいアクリル風なウィンドウができました。
f:id:minami_SC:20171201234621p:plain

ここで、以下の accent.GradientColorの値を変えると、ウィンドウ背景の色味を調整することができます。

            //               ↓の色はAABBGGRRの順番で設定する
            accent.GradientColor = 0x99FFFFFF;  // 60%の透明度が基本

accent.GradientColor = 0xAA222222;とするとこんな感じの表示になります。 f:id:minami_SC:20171201234639p:plain

サンプルコード一式は、GitHubの以下のリポジトリに置いておきました。 github.com

非公開APIを使った処理なので、あまり積極的に使うべき方法ではないとは思います。
ですが、現状のWPFでアクリルっぽいウィンドウを作るには、こんな方法しかないのかな。。。

今後、WPFの更新とかで、こういう用途のAPIが拡充されるといいなぁ。。。


Ctr+C/Ctrl+Vなどのショートカットを、マウス/タッチパネル操作で実行するツールを作ってみました

$
0
0

本日は12/10ですが、この記事はXAML Advent Calendar 2017の6日目の記事です。 遅くなってしまいすみません。。。

当初はFluent Design関係の話題を書くつもりでしたが、結局あまり関係ないテーマになってしまいました。

Ctrl+CやCtrl+Vなど、コピペなどのショートカットを、マウス操作やタッチ操作で実行できるツールを作ってみました。
正直、思い付きで作っただけなので、コードとしては特筆すべき点や面白みはあまりないかもしれません。。。
↓こんな感じのツールです。 f:id:minami_SC:20171210235823g:plain

作ったもの

コピー/ペーストや、Undo/Redoのコマンド実行用のボタンを、ウィンドウ最前面に表示するだけのツールです。

ソースコード一式は以下の場所に置いています。

github.com

releaseページに実行ファイル類をzipにして置いています。
コイツを展開して、exeファイルを適当なパスに配置して実行すれば使えます。

タブレットとかで、タッチパネルオンリーな操作してるときとかは、こいつをタスクバーにピン留めしておけば、こういうショートカットを実行したいときに便利なんじゃないかな、、、と思います。

やっていること

常に最前面に表示する、小さいツールウィンドウを作り、各種ボタンをクリックしたら、Ctrl+C/Ctrl+Vなどの各種ショートカットキーのキー操作をエミュレートしているだけです。

まぁ、言ってしまえばこれだけの処理なのですが、工夫したのは以下の点です。 * ショートカットを実行しようとして、このツールのボタンをクリックすると、このツールがアクティブウィンドウとなってしまう。 * ⇒Ctrl+C/Ctrl+Vなどのコマンドが、このツール自身に対して送信されてしまう。

ということで、SetWindowLong関数を使って、あらかじめこのウィンドウがアクティブにならないように設定しています。 Ctrl+Cなどのショートカットを実行するボタンをクリックしても、このウィンドウがアクティブにならないため、それまでユーザーが操作していたウィンドウに対して、各種ショートカットキーのコマンドを送信できるようになっています。

その他

一応、近年の流行のFluent Design絡みの話題として。 このアプリはWPFで書いていますが、↓に書いた方法を使って、Fluent Design Systemのアクリル風なウィンドウにしてみました。

sourcechord.hatenablog.com

こういう、常に最前面に置いておきたいツールは、アクリル風なデザインは結構マッチするんじゃないかな、、と思います。

グリッドレイアウト用のライブラリ GridExtraを更新しました~Grid子要素の自動レイアウト機能などの追加~

$
0
0

この記事は、XAML Advent Calendar 2017の22日目の記事です。

以前↓に書いた、各種グリッドレイアウトを補助するGridExtraというライブラリを更新しました。
WPF/UWP向けに、グリッドレイアウト補助ライブラリを作ってみました~GridExtra~ - SourceChord

ソースコードリポジトリはこちら

Nugetから以下のコマンドでインストールできます。

Install-Package GridExtra

主に以下のような変更が入っています。

  • GridExクラスの更新
    • GridEx.AutoFillChildren添付プロパティ
      • Gridパネル内の子要素を、UniformGridやWrapPanelみたいに各要素を自動で順々に並べる機能
  • WrapPanelExクラスの追加
    • WrapPanelEx.AdaptiveLayout添付プロパティ
      • WrapPanelの子要素がOrientation方向の幅いっぱいに広がるようにレイアウトを自動調整する機能

ということで変更点などを、ざっとご紹介したいと思います。

GridExの更新内容

GridEx.AutoFillChildren添付プロパティ

gridへの、要素の自動流し込み

今回の更新のメイン!! GridEx.AutoFillChildrenという添付プロパティをTrueにすると、子要素をGrid内の各領域へと自動で順番に流し込んでいきます。

Gridなんだけど、WrapPanelみたいに要素を順番に流し込んでいけるイメージ。

f:id:minami_SC:20171222232439g:plain

使い方

f:id:minami_SC:20171222234049p:plain
こういう風にグリッド内に順番にコントロールを配置したい場合、
以下のように、子要素でGrid.Row/Grid.Columnを個別に設定せず、自動で配置することができます。

<Grid ge:GridEx.ColumnDefinition="*, *"ge:GridEx.RowDefinition="Auto, Auto, Auto"ge:GridEx.AutoFillChildren="True"ShowGridLines="True"><TextBlock Text="Name:" /><TextBox VerticalAlignment="Top"Margin="5"/><TextBlock Text="Age:" /><TextBox VerticalAlignment="Top"Margin="5"/><Button ge:GridEx.Area="2, 1, 1, 1"Margin="5"Width="60"HorizontalAlignment="Right"Content="OK" /></Grid>
Orientationの指定

GridEx.AutoFillOrientation添付プロパティを指定することで、自動レイアウトする方向を指定できます。
こんな風に、縦方向の並びで順番に並べることもできます。

<Grid ge:GridEx.ColumnDefinition="*, *, *"ge:GridEx.RowDefinition="*, *"ge:GridEx.AutoFillChildren="True"ge:GridEx.AutoFillOrientation="Vertical"><Button Content="1" /><Button Content="2" /><Button Content="3" /><Button Content="4" /><Button Content="5"  /><Button Content="6" /></Grid>

f:id:minami_SC:20171222234236p:plain

自動レイアウトに、固定要素を混ぜる

AutoFillChildrenを用いたレイアウトをする際、GridEx.AreaGridEx.AreaNameなど、GridExでの位置指定を行う添付プロパティが設定された子要素があると、自動レイアウトの対象から除外し、指定された位置に固定配置します。

<Grid ge:GridEx.ColumnDefinition="*, *, *"ge:GridEx.RowDefinition="*, *"ge:GridEx.AutoFillChildren="True"><Button Content="1" /><Button Content="2" /><Button Content="3" /><Button Content="4" /><Button Content="Fixed Item"ge:GridEx.Area="0,1,1,1"/></Grid>

f:id:minami_SC:20171222234350p:plain

まぁ、これはこれでどこかで用途あるんじゃないかな、と。
AutoFill絡みのプロパティは、今後もう少し追加していきたいなと思います。

GridEx.Row/Column Definitionで、行・列サイズのmin/max指定に対応

GridExでは、GridEx.RowDefinitionGridEx.ColumnDefinitionという添付プロパティで、Gridの行・列数を定義する機能を作ってました。
この定義では、行・列の各要素のサイズ指定はできたのですが、MinWidth/MinHeightなどの値を設定できませんでした。

行・列定義を行う文字列の文法に少し仕様を追加し、 以下のような形式で、複数の行や列のサイズをMin/Max条件含めてまとめて定義できるようにしました。 ge:GridEx.ColumnDefinition="50, *(50-200), 2*(80-), 2*(-300)"

こんな風にグリッド定義をすることができます。

<Grid ge:GridEx.RowDefinition="*, *, *, *"ge:GridEx.ColumnDefinition="50, *(50-200), 2*(80-), 2*(-300)"ShowGridLines="True"><Button Grid.Row="1"Grid.Column="2"Margin="5"Content="Button" /></Grid>

これは、以下のようなコードと同じレイアウトとなります。

<Grid.ColumnDefinitions><ColumnDefinition Width="50"/><ColumnDefinition Width="*"MinWidth="50"MaxWidth="200"/><ColumnDefinition Width="2*"MinWidth="80"/><ColumnDefinition Width="2*"MaxWidth="300"/></Grid.ColumnDefinitions>

地味ですが、これで一応GridExクラスの機能だけで、Gridの行・列 定義を一通りできるようになったかと思います。

WrapPanelExクラスの追加

WrapPanelのレイアウト調整を行うヘルパークラス、WrapPanelExを追加しました。
WrapPanelでWrapPanelEx.AdaptiveLayout="True"という添付プロパティを設定すると、通常のWrapPanelのように各要素を等間隔で配置するのではなく、指定幅以上でパネルを埋め尽くすようにレイアウトします。
UWP Community ToolkitのAdaptiveGridViewのようなレイアウト方法です。

ちょっと言葉で表現しにくいので、動きは↓のgif見てください。
f:id:minami_SC:20171222232502g:plain

<Grid><Grid.RowDefinitions><RowDefinition /><RowDefinition Height="Auto"/></Grid.RowDefinitions><WrapPanel ItemWidth="200"ItemHeight="70"Orientation="Horizontal"ge:WrapPanelEx.AdaptiveLayout="{Binding IsChecked, ElementName=chkIsAdaptive}"><Button /><Button /><Button /><Button /><Button /><Button /><Button /></WrapPanel><CheckBox x:Name="chkIsAdaptive"Grid.Row="1"Margin="5"Content="WrapPanelEx.AdaptiveLayout"/></Grid>

今回の更新内容は以上ですが、今後も面白そうなレイアウト手法があれば、色々と取り入れながら更新していきたいと思ってます。

Windows Template Studio 1.6を使ってみた

$
0
0

この記事は、XAML Advent Calendar 2017の23日目の記事です。

UWPのアプリ雛形を作成できるVS拡張機能Windows Template Studioですが、先日バージョン1.6がリリースされたので使ってみました。

最近あまり使ってなかったのですが、v1.5でローカライズ対応されてUIが日本語表示されるようになってます。
f:id:minami_SC:20171223235012p:plain

Fluent Designへの対応

ハンバーガーメニューのナビゲーション領域などで、Fluent Designへの対応が進みました。
f:id:minami_SC:20171223234913g:plain

Acrylicなエフェクトもかかってますし、メニュー項目を選択したときのアニメーションなども追加されてます。

Image Galleryページ

ページの雛形にImage Galleryという種類が増えました。
この雛形では、Fluent Design SystemのConnected Animationな動きが実装されてます。
f:id:minami_SC:20171223234926g:plain

他にも、「機能の追加」ページで扱える機能に「Drag&Drop」や「Web to App Link」などが加わってます。
f:id:minami_SC:20171223234956p:plain

今回の更新は、Fluent Designへの対応が進んだ点が大きいですね。
UWPでのFluent Desingの実装例を見るうえでも役立つと思うので、UWPアプリを作る際には、一度この辺の雛形プロジェクトを動かしてみると役に立つかもしれません。

WPFでFluent Design Systemを再現するライブラリを作ってみました~FluentWPF~

$
0
0

はじめに

少し遅れてしまいましたが、この記事はXAML Advent Calendar 2017の25日目の記事です。

今年のBuildでは、Fluent Design Systemなどの発表がありましたが、このデザインをWPFで用いる方法は提供されていません。

対応するAPIがないなら、XAMLの機能を駆使してそれっぽく作ってしまえ!!ということで、FluentDesignをXAMLで再現したライブラリを作ってみました。
XAMLの拡張性は伊達じゃない!!

f:id:minami_SC:20171226020340g:plain:w300

StyleやStoryboard、マークアップ拡張やコンバーターに各種添付プロパティと、XAMLの機能をフル活用して色々なエフェクトを再現しています。
ただ、ウィンドウのアクリル化はXAMLだけではどうにもならないので、↓を使ってそれっぽく再現しています。
WPFでFluent Design Systemのアクリルっぽいウィンドウを作ってみる - SourceChord

概要

WPF向けにFluent Design Systemをそれっぽく再現したテーマのライブラリです。
主に以下のような機能を実装しました。

  • Acrylic
    • AcrylicWindow・・・半透明でぼかしをかけて透過するスタイルのウィンドウ。
    • AcrylicBrush・・・・ウィンドウ内の指定したXAML要素をぼかして表示するためのブラシ
  • Reveal・・・・・・・マウスカーソルの位置に応じた照明効果が効いた、各種コントロール用スタイル。
  • ParallaxView・・・UWPの同名コントロールを再現したもの。
  • AccentColor・・・・OSのテーマカラーなどを用いたColor/Brush定義

準備

Nugetで「FluentWPF」と検索して、インストールしてください。

パッケージマネージャコンソールからインストールする場合は以下のコマンドで。

Install-Package FluentWPF

https://www.nuget.org/packages/FluentWPF/

準備

FluentWPFを使いたいXAMLコードで、以下の名前空間の定義を追加します。

xmlns:fw="clr-namespace:SourceChord.FluentWPF;assembly=FluentWPF"

App.xamlに、以下のようなリソースディクショナリの参照を追加します。

<Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="pack://application:,,,/FluentWPF;component/Styles/Controls.xaml" /></ResourceDictionary.MergedDictionaries></ResourceDictionary></Application.Resources>

ということで、使い方を順に説明していきます。


Acrylic

まずは、Fluent Design Systemで最も印象的な、アクリル効果の効いたウィンドウの作成方法から。

AcrylicWindow

AcrylicWindow派生のWindowクラスを作ると、アクリル効果のかかったウィンドウを表示します。

f:id:minami_SC:20171226013944p:plain

<fw:AcrylicWindow x:Class="FluentWPFSample.Views.AcrylicWindow"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:fw="clr-namespace:SourceChord.FluentWPF;assembly=FluentWPF"xmlns:local="clr-namespace:FluentWPFSample.Views"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Title="AcrylicWindow"Width="300"Height="300"mc:Ignorable="d"><Grid></Grid></fw:AcrylicWindow>

コードビハインド
コードビハインドでは、ウィンドウのクラス定義からWindowの継承をしている部分を削除しておきます。

//public partial class AcrylicWindow : Windowpublicpartialclass AcrylicWindow
    {
        public AcrylicWindow()
        {
            InitializeComponent();
        }
    }
プロパティなど
プロパティ名説明
TintColorColor半透過効果に加える色味を設定
TintOpacitydoubleTintColorの不透明度を設定
NoiseOpacitydouble半透過効果に加えるノイズの不透明度を設定
FallbackColorColorウィンドウが非アクティブになった際の、フォールバックカラーを指定
ShowTitleBarboolウィンドウのタイトルバーを表示するか否かを設定

AcrylicWindowを添付プロパティとして設定する

AcrylicWindowクラスを継承するのではなく、既存ウィンドウに添付プロパティを設定することでもアクリル化ができます。

f:id:minami_SC:20171226014000p:plain

<Window x:Class="FluentWPFSample.Views.AcrylicWindow2"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:FluentWPFSample.Views"xmlns:fw="clr-namespace:SourceChord.FluentWPF;assembly=FluentWPF"mc:Ignorable="d"Title="AcrylicWindow2"Height="300"Width="300"fw:AcrylicWindow.Enabled="True"fw:AcrylicWindow.TintColor="Violet"><Grid></Grid></Window>

MahApps.Metroとの併用

添付プロパティとしてAcrylicなウィンドウを作成できるようにしているので、MahApps.Metroのような独自ウィンドウクラスを用いるライブラリとも併用できます。

MahApps.MetroのMetroWindowや各種コントロールと組み合わせると、こんな感じになります。

f:id:minami_SC:20171226014015p:plain

<controls:MetroWindow x:Class="MahAppsTest.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:fw="clr-namespace:SourceChord.FluentWPF;assembly=FluentWPF"xmlns:local="clr-namespace:MahAppsTest"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Title="MainWindow"Width="525"Height="350"fw:AcrylicWindow.Enabled="True"fw:AcrylicWindow.ShowTitleBar="False"Background="Transparent"BorderThickness="1"GlowBrush="{DynamicResource AccentColorBrush}"mc:Ignorable="d"><Grid><Grid.ColumnDefinitions><ColumnDefinition Width="Auto" /><ColumnDefinition /></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition Height="Auto" /><RowDefinition Height="Auto" /><RowDefinition /></Grid.RowDefinitions><TextBlock Margin="5"HorizontalAlignment="Left"VerticalAlignment="Center"Text="Name:" /><TextBox Grid.Column="1"Height="23"Margin="5"HorizontalAlignment="Stretch"VerticalAlignment="Top"Text="TextBox"TextWrapping="Wrap" /><Button Grid.Row="1"Grid.Column="1"Width="75"Margin="5"HorizontalAlignment="Right"VerticalAlignment="Top"Content="Button" /><Slider Grid.Row="2"Grid.Column="1"Margin="5"HorizontalAlignment="Stretch"VerticalAlignment="Top" /></Grid></controls:MetroWindow>

そのままだと、FluentWPFのAcrylicWindowによるタイトルバーがMetroWindow内部に描画されてしまうため、AcrylicWindow.ShowTitleBar="False"という設定を行っています。

AcrylicBrush

XAMLで書かれた背面にあるUI要素をぼかして表示します。 こんな感じ!!

f:id:minami_SC:20171226020316g:plain

<Window.Resources><BooleanToVisibilityConverter x:Key="booleanToVisibilityConverter" /></Window.Resources><Grid><Grid.RowDefinitions><RowDefinition /><RowDefinition Height="Auto" /></Grid.RowDefinitions><Grid x:Name="grid"Background="White"><Grid.ColumnDefinitions><ColumnDefinition Width="Auto" /><ColumnDefinition /></Grid.ColumnDefinitions><StackPanel><Button Width="75"Margin="5"Content="Button" /><Button Width="75"Margin="5"Content="Button" /><Button Width="75"Margin="5"Content="Button" /></StackPanel><Image Grid.Column="1"Margin="5"Source="/FluentWPFSample;component/Assets/Images/1.jpg" /></Grid><Rectangle Grid.ColumnSpan="2"Margin="40"Fill="{fw:AcrylicBrush grid}"Stroke="Black"Visibility="{Binding IsChecked, ElementName=chkShowAcrylicLayer, Converter={StaticResource booleanToVisibilityConverter}}" /><CheckBox x:Name="chkShowAcrylicLayer"Grid.Row="1"Margin="5"HorizontalAlignment="Left"Content="Show Acrylic Rect"IsChecked="True" /></Grid>

このマークアップ拡張では、指定したUI要素をVisualBrushとして扱い、強烈なぼかしをかけたりTintColorで色味を加えたりしたブラシを作ります。

昔、↓のようなブラシ用マークアップ拡張を作ったことがあるのですが、この方法を応用してFluentDesign用に作り直しました。

注意点

このマークアップ拡張では、指定した要素をVisualBrushとして使用しています。
そのため、VisualTree上で親に当たるものをTargetとすると、VisualBrushのレンダリングが無限ループとなり正常に描画されません。
このマークアップ拡張は、親子関係にある要素同士では使わないように注意してください。

プロパティなど

AcrylicBrushマークアップ拡張では、以下のようなプロパティを用意しています。

プロパティ名説明
TargetNamestring(プロパティ名省略可)
TintColorColor半透過効果に加える色味を設定
TintOpacitydoubleTintColorの不透明度を設定
NoiseOpacitydouble半透過効果に加えるノイズの不透明度を設定

この辺のプロパティを弄ると、色々なアクリル効果を演出できます。

こんなブラシを定義すると、

Fill="{fw:AcrylicBrush grid, TintColor=Red, TintOpacity=0.3, NoiseOpacity=0.1}"

こうなります。
f:id:minami_SC:20171226014057p:plain

Reveal

FluentDesignでのRevealエフェクトを再現したスタイルを作っています。
こんな風に、マウスの動きに応じてコントロールの輪郭を光らせたり、クリックした位置から波紋状に広がる光のエフェクトなどを再現しています。

f:id:minami_SC:20171226014111g:plain

<Grid fw:PointerTracker.Enabled="True"Background="#01FFFFFF"Margin="3"><StackPanel><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"Style="{StaticResource ButtonRevealStyle}"/><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"Background="Transparent"Style="{StaticResource ButtonRevealStyle}"/><TextBox HorizontalAlignment="Left"Height="23"Margin="5"Text="TextBox"Width="120"Style="{StaticResource TextBoxRevealStyle}"/></StackPanel></Grid>

RevealEffectをかけたい領域の親要素に対しては、以下の2つの設定を行う必要があります。

  • PointerTracker.Enabled="True"という添付プロパティを設定
    • この添付プロパティをTrueにした領域内で、マウスカーソル位置のトラッキングを開始します。
  • 背景色を透明以外にする
    • WPFでは、完全に透明な領域ではマウスイベントが発生しないため、マウスカーソルの移動に関するイベントが発生しなくなってしまうため。

今のところ、以下のようなスタイルを作っています。

  • ButtonRevealStyle
  • ButtonAccentRevealStyle
  • TextBoxRevealStyle
  • ListBoxRevealStyle

応用例

Windows10の電卓風なデザインを作ってみました。

f:id:minami_SC:20171226020340g:plain

<fw:AcrylicWindow x:Class="FluentWPFSample.Views.RevealStyles"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:FluentWPFSample.Views"xmlns:fw="clr-namespace:SourceChord.FluentWPF;assembly=FluentWPF"mc:Ignorable="d"Title="RevealStyles"Height="320"Width="480"fw:AcrylicWindow.TintColor="GhostWhite"><Grid fw:PointerTracker.Enabled="True"Background="#01FFFFFF"><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition /></Grid.RowDefinitions><UniformGrid Rows="1"Columns="5"><Button Content="MC"Margin="2"Height="24"Style="{StaticResource ButtonRevealStyle}"Background="Transparent"/><Button Content="MR"Margin="2"Height="24"Style="{StaticResource ButtonRevealStyle}"Background="Transparent"/><Button Content="M+"Margin="2"Height="24"Style="{StaticResource ButtonRevealStyle}"Background="Transparent"/><Button Content="M-"Margin="2"Height="24"Style="{StaticResource ButtonRevealStyle}"Background="Transparent"/><Button Content="MS"Margin="2"Height="24"Style="{StaticResource ButtonRevealStyle}"Background="Transparent"/></UniformGrid><UniformGrid Grid.Row="1"Columns="4"Rows="4"><Button Content="7"Margin="2"Style="{StaticResource ButtonRevealStyle}" /><Button Content="8"Margin="2"Style="{StaticResource ButtonRevealStyle}" /><Button Content="9"Margin="2"Style="{StaticResource ButtonRevealStyle}" /><Button Content="×"Margin="2"Style="{StaticResource ButtonAccentRevealStyle}" /><Button Content="4"Margin="2"Style="{StaticResource ButtonRevealStyle}" /><Button Content="5"Margin="2"Style="{StaticResource ButtonRevealStyle}" /><Button Content="6"Margin="2"Style="{StaticResource ButtonRevealStyle}" /><Button Content="-"Margin="2"Style="{StaticResource ButtonAccentRevealStyle}" /><Button Content="2"Margin="2"Style="{StaticResource ButtonRevealStyle}" /><Button Content="3"Margin="2"Style="{StaticResource ButtonRevealStyle}" /><Button Content="4"Margin="2"Style="{StaticResource ButtonRevealStyle}" /><Button Content="+"Margin="2"Style="{StaticResource ButtonAccentRevealStyle}"/><Button Content="±"Margin="2"Style="{StaticResource ButtonRevealStyle}"/><Button Content="0"Margin="2"Style="{StaticResource ButtonRevealStyle}"/><Button Content="."Margin="2"Style="{StaticResource ButtonRevealStyle}"/><Button Content="="Margin="2"Style="{StaticResource ButtonAccentRevealStyle}"/></UniformGrid></Grid></fw:AcrylicWindow>

Parallax

Parallaxエフェクトをかけるための、ParallaxViewコントロールを作りました。

使い方は、UWP本家のものとだいたい同じ雰囲気にしています。

f:id:minami_SC:20171226020417g:plain

<Grid><fw:ParallaxView VerticalShift="200"HorizontalShift="200"Source="{Binding ElementName=list}"><Image Source="/FluentWPFSample;component/Assets/Images/1.jpg"Stretch="UniformToFill"/></fw:ParallaxView><ListBox x:Name="list"Background="#88EEEEEE"ScrollViewer.CanContentScroll="False"ItemsSource="{Binding Items}"/></Grid>
publicpartialclass ParallaxSample : Window
    {
        public List<string> Items { get; set; }

        public ParallaxSample()
        {
            InitializeComponent();
            this.DataContext = this;

            this.Items = new List<string>();
            for (var i = 0; i < 100; i++)
            {
                this.Items.Add($"item{i:D3}");
            }
        }
    }

AccentColors

OSのテーマで設定されたアクセントカラーを取得します。
f:id:minami_SC:20171226014202p:plain:w400

以下のようなColor/Brush定義を用意しています。

  • Colors
    • ImmersiveSystemAccent
    • ImmersiveSystemAccentLight1
    • ImmersiveSystemAccentLight2
    • ImmersiveSystemAccentLight3
    • ImmersiveSystemAccentDark1
    • ImmersiveSystemAccentDark2
    • ImmersiveSystemAccentDark3
  • Brushes
    • ImmersiveSystemAccentBrush
    • ImmersiveSystemAccentLight1Brush
    • ImmersiveSystemAccentLight2Brush
    • ImmersiveSystemAccentLight3Brush
    • ImmersiveSystemAccentDark1Brush
    • ImmersiveSystemAccentDark2Brush
    • ImmersiveSystemAccentDark3Brush

使用例
ブラシとして画面表示するとこんな感じです。
f:id:minami_SC:20171226020450p:plain:w350

<StackPanel Margin="5"><StackPanel.Resources><Style TargetType="Border"><Setter Property="Width"Value="120" /><Setter Property="Height"Value="120" /><Setter Property="Margin"Value="3" /><Setter Property="BorderBrush"Value="Black" /><Setter Property="BorderThickness"Value="1" /></Style><Style TargetType="TextBlock"><Setter Property="TextWrapping"Value="Wrap" /><Setter Property="VerticalAlignment"Value="Bottom" /><Setter Property="FontSize"Value="14" /></Style></StackPanel.Resources><StackPanel Orientation="Horizontal"Margin="5"><Border Background="{x:Static fw:AccentColors.ImmersiveSystemAccentBrush}"><TextBlock Text="ImmersiveSystemAccentBrush" /></Border></StackPanel><StackPanel Orientation="Horizontal"Margin="5"><Border Background="{x:Static fw:AccentColors.ImmersiveSystemAccentLight1Brush}"><TextBlock Text="ImmersiveSystemAccentLight1Brush"/></Border><Border Background="{x:Static fw:AccentColors.ImmersiveSystemAccentLight2Brush}"><TextBlock Text="ImmersiveSystemAccentLight2Brush"/></Border><Border Background="{x:Static fw:AccentColors.ImmersiveSystemAccentLight3Brush}"><TextBlock Text="ImmersiveSystemAccentLight3Brush" /></Border></StackPanel><StackPanel Orientation="Horizontal"Margin="5"><Border Background="{x:Static fw:AccentColors.ImmersiveSystemAccentDark1Brush}"><TextBlock Text="ImmersiveSystemAccentDark1Brush"Foreground="White"/></Border><Border Background="{x:Static fw:AccentColors.ImmersiveSystemAccentDark2Brush}"><TextBlock Text="ImmersiveSystemAccentDark2Brush"Foreground="White"/></Border><Border Background="{x:Static fw:AccentColors.ImmersiveSystemAccentDark3Brush}"><TextBlock Text="ImmersiveSystemAccentDark3Brush"Foreground="White"/></Border></StackPanel></StackPanel>

今後の予定

まだまだ完成度は低いですが、今後もFluentDesignの再現性を高めるために、いろいろ更新しようと思ってます。
当面は、以下のような対応を予定してます。

  • 各種コントロール用のスタイル定義
    • Buttonなどだけではなく、CheckBox/RadioButtonや、ListViewやSliderなどの各種スタイル定義も作る。
  • Windows10環境以外での動作チェック
    • まだWin7/8.xでの動作確認ができてません。おそらくAcrylicWindowなどは、ちゃんと表示できてないと思います。
    • Win7/Win8.x系では、ただの半透明ウィンドウにするなどのフォールバック処理を実装予定。
  • Connected Animation
    • これの再現は、なかなか難しいかも。。。出来たら対応します。

もうちょいライブラリを作り込んでから、サンプルコード類もたくさん用意しようと思います。

FluentWPF v0.2.0~AcrylicPanel/DropShadowPanelの追加~

$
0
0

先日、↓のFluent Design SystemをWPFで再現するライブラリを作りましたが、ちょこっとバージョンアップしてみました。

sourcechord.hatenablog.com

f:id:minami_SC:20180110081212p:plain

主に以下のような変更を行いました。

  • 新規コントロールの追加
    • AcrylicPanel・・・・・・背景ぼかし処理をするパネル
    • DropShadowPanel・・・影の表示方法に少し手を入れたDropShadowEffect付きパネル
  • バグフィックス
    • AcrylicBrushのバグフィックス
      AcrylicBrush使用時に、LayoutChangedイベントが発生し続けて、CPU負荷が高くなる不具合を修正
    • AcrylicWindowのWin10環境以外への対応
      Win10以外の環境では、AcrylicWindowの背景ぼかし処理を無効化しました。

Acrylicなぼかしウィンドウの作成には、SetWindowCompositionAttributeという非公開API使っているので、以前のOSへの対応はやっぱ仕組み的に難しいですね。。。
ということで、Win10以外のOSでは、AcrylicWindowのぼかし処理を無効化しました。
(Win7ならAeroGrass効果をうまく使えば、それっぽい表示を真似できるかもしれませんが。。)

新規コントロール

  • AcrylicPanel・・・・・・背景ぼかし処理を持ったパネル
  • DropShadowPanel・・・影の表示方法に少し手を入れたDropShadowEffect付きパネル

これらは、○○Panelという名前にしてますが、WPFのPanel派生なレイアウト用コントロールではありません。
命名は少し悩みましたが、UWP Community ToolkitにもDropShadowPanelという名前で似たような内容のコントロールがあるので、こんな名前のコントロールにしました。

AcrylicPanel

f:id:minami_SC:20180110081126p:plain

<fw:AcrylicPanel Grid.ColumnSpan="2"Width="200"Height="200"HorizontalAlignment="Right"Target="{Binding ElementName=grid}"<TextBlock Text="TextBlock"HorizontalAlignment="Center"VerticalAlignment="Center"/></fw:AcrylicPanel>

Targetプロパティで、ぼかし対象の領域を指定します。
Targetで指定した要素をVisualBrushとして利用し、ぼかしエフェクトなどをかけています。
そのため、VisualTree上で親に当たるものをTargetとすると、VisualBrushのレンダリングが無限ループとなり正常に描画されません。親子関係にある要素同士では使わないように注意してください。

DropShadowPanel

f:id:minami_SC:20180110081138p:plain

<fw:DropShadowPanel Grid.Row="1"ShadowMode="Outer"Margin="50"><TextBlock Text="ShadowMode: Outer"HorizontalAlignment="Center"VerticalAlignment="Center"/></fw:DropShadowPanel>

以下のような3つのモードで、DropShadowEffectをかけるコントロールです。

  • ShadowModeプロパティ
    • Content・・・子要素すべてにまとめて影を付けます。
    • Inner・・・・・DropShadowPanelの内側にのみ影を表示するモード。内部に凹んだような表示を簡単に作れます。
    • Outer・・・・DropShadowPanelの外側にのみ影を表示します。パネル背景が半透明な場合などに、コントロール内部に影が表示され、パネル内部の色味がDropShadowに影響されるのを防ぐことができます。

XAMLではDropShadowEffectなどのEffectを利用すると、そのEffectがかかったコントロールと子孫要素は、ベクター形式の描画ではなくなります。またClearTypeなどの効果も効かなくなってしまいます。
f:id:minami_SC:20180110081151p:plain
DropShadowPanelでは、影と子要素を別々に描画しているので、DropShadowをかけつつ内部の子要素は通常どおりの表示ができるようにしています。

FluentWPF 0.2.1をリリースしました

$
0
0

以前作成した↓のライブラリを更新しました。

github.com

Nugetからは以下のコマンドでインストールできます。

Install-Package FluentWPF

https://www.nuget.org/packages/FluentWPF/

変更内容

変更点は、下記1点です。

  • AcrylicWindow
    • TitleBarForegroundプロパティを追加
      ウィンドウのタイトルバーなどの色を指定できます。

こんな風に、暗い背景色のウィンドウを作ったときに、タイトルバーの文字色などを調整すると、いい感じに表示できます。
f:id:minami_SC:20180129002214p:plain

今回の変更は、プルリクもらった内容を取り込んでのリリースでした。
プルリクをもらったのは初めての経験なのですが、すごくうれしいもんですね!!

VirtualShortcutKeyが窓の杜で紹介されました


Electron+TypeScriptなプロジェクトの雛形を更新~Electron1.8.2+TypeScript2.7.1~

$
0
0

以前作ったElectron+TypeScriptのサンプルコードを、それぞれの最新バージョンにアップデートしました。

それぞれ、以下のバージョンに更新してます。

  • electron v1.8.2
  • typescript v2.7.1

こういう雛形って、定期的に新しいバージョンに追従しておかないと、変更内容を追いきれなくなりますからね。

今回はコードには変更を加えず、ライブラリ類のバージョン更新だけでOKでした。
今後も、定期的にライブラリの更新に追従しておこうと思います。

FluentWPF 0.2.2をリリースしました

$
0
0

2件ほどプルリクをいただいたので、マージしてFluentWPF0.2.2としてリリースしました。

Release v0.2.2 · sourcechord/FluentWPF · GitHub

Nugetからは以下のコマンドでインストールできます。

Install-Package FluentWPF

https://www.nuget.org/packages/FluentWPF/

変更内容

今回の変更内容は以下の2点です。
(どちらもプルリクでいただいた内容です。)

  • AcrylicWindow.ShowTitleBar="False"のときに、タイトルバー部分の余白ができる
  • ウィンドウ作成後に、AcrylicWindow.Enabled添付プロパティをTrueにしても、ウィンドウがアクリル化されない不具合を修正

AcrylicWindow.ShowTitleBar="False"としたときに、以下のようにタイトルバーがあった部分に無駄な余白ができてしまっていました。
f:id:minami_SC:20180221231918p:plain

<fw:AcrylicWindow x:Class="FluentWPFSample.Views.AcrylicWindow"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:fw="clr-namespace:SourceChord.FluentWPF;assembly=FluentWPF"xmlns:local="clr-namespace:FluentWPFSample.Views"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Title="AcrylicWindow"Width="300"Height="300"ShowTitleBar="False"mc:Ignorable="d"><Grid Background="#70FFFFFF"><TextBlock Margin="10"HorizontalAlignment="Left"VerticalAlignment="Top"Text="この部分がコンテンツ領域"TextWrapping="Wrap" /></Grid></fw:AcrylicWindow>

今回のバージョンアップで、こんな風にちゃんとウィンドウ全域が描画領域になります。
f:id:minami_SC:20180221231929p:plain

今後の予定

現在、OSのアクセントカラーやLight/Darkのテーマ設定を反映できるように対応を進めています。
f:id:minami_SC:20180221233148g:plain

この辺、ある程度動作するコードは書けてるんだけど、クラス名とかXAMLからのプロパティ定義をどんな仕様にするか、まだ少し悩んでいます。

もう少し時間がかかりそうですが、こんな対応を進めてこうと思ってます。
とりあえず、今月中にはテーマ対応をして次バージョンをリリースしたいなぁ。

VirtualShortcutKey 1.1.0リリース

$
0
0

VirtualShortcutKey 1.1.0をリリースしました。 github.comダウンロードページ

今回の更新は、Win7/8.xへの対応が主な変更点です。

変更内容

  • Windows 7/8.x系OSへの対応
    以前のバージョンでは、Windows7/8.x系OSでUI表示が乱れる不具合がありましたが、この表示の乱れを修正しています。

  • ウィンドウのアクリル効果の微修正
    わずかにですがFluentDesignのアクリル風エフェクト効果を修正しました。
    半透明のアクリル効果を加えたウィンドウでは、ウィンドウに若干のノイズを加えてざらつき感をだしています。
    今回のバージョンでは、このノイズをほんっっの少しだけ弱めて、滑らかな表示にしました。

1.0.01.1.0
f:id:minami_SC:20180228012224p:plainf:id:minami_SC:20180228012234p:plain

任意のウィンドウをアクリル化するツールを作ろうとして挫折

$
0
0

ちょっと思い付きで、Windows10向けに任意のWindowをアクリル化するツールを作ろうとしてました。

こんな感じ。
f:id:minami_SC:20180323000452g:plain

Spy++とかのツールみたいに、対象ウィンドウへとドロップ操作を行うと、そのウィンドウをアクリル化します。
ウィンドウハンドルを取得して、そのウィンドウに対してSetWindowCompositionAttribute関数呼べば、イイ感じにできないかな、、、と思い試してみました。

ただ、コマンドプロンプトとかPowerShellのウィンドウなどはアクリル化できるんですが、普通のアプリではうまくいきません。

一般的なウィンドウを持ったアプリでは、アプリ自身が背景色を持っているため、このSetWindowCompositionAttribute関数でウィンドウをアクリル化しても、半透明になりません。
アプリの背景色を書き換える、、と言った方法も考えたのですが、アプリごとに作りが違って対応しきれないです。

ということで、このツールはこの辺まででお蔵入りさせておこうと思います。
作りかけコード類は↓にあげました。 ウィンドウハンドル取得処理とか色々と小技を使ってるので、後々なんかのツールを作る上でも役に立つかな、と。

FluentWPF 0.3.0をリリースしました

$
0
0

0.2系のリリースからはだいぶ時間がかかりましたが、色々とまとまった機能追加ができたので、FluentWPF0.3.0としてリリースしました。

今回の変更内容は以下のようなものです。

  • osのテーマ・アクセントカラー設定への対応
  • ResourceDictionaryExクラス
    • OSのLight/Darkテーマ設定に応じてリソース切替を行う仕組みの導入

f:id:minami_SC:20180403010336g:plain

変更内容

アクセントカラーへの追従

OSのアクセントカラーの設定に追従できるようにしました。

今までのバージョンでも、AccentColorsクラスでOSのアクセントカラーを参照できました。
このクラスを少し改善して、OSの設定変更に追従するようにしました。
x:Staticでアクセスした場合はテーマ変更に追従できないので注意

<StackPanel Orientation="Horizontal"Margin="5"><Border Background="{Binding Path=(fw:AccentColors.ImmersiveSystemAccentBrush)}"><TextBlock Text="ImmersiveSystemAccentBrush" /></Border><Border Background="White"><StackPanel><RadioButton Content="Light"IsEnabled="False"IsChecked="{Binding Path=(fw:SystemTheme.Theme),                                     Converter={StaticResource radioButtonConverter}, ConverterParameter=Light, Mode=OneWay}"/><RadioButton Content="Dark"IsEnabled="False"IsChecked="{Binding Path=(fw:SystemTheme.Theme),                                     Converter={StaticResource radioButtonConverter}, ConverterParameter=Dark, Mode=OneWay}"/></StackPanel></Border></StackPanel><StackPanel Orientation="Horizontal"Margin="5"><Border Background="{Binding Path=(fw:AccentColors.ImmersiveSystemAccentLight1Brush)}"><TextBlock Text="ImmersiveSystemAccentLight1Brush"/></Border><Border Background="{Binding Path=(fw:AccentColors.ImmersiveSystemAccentLight2Brush)}"><TextBlock Text="ImmersiveSystemAccentLight2Brush"/></Border><Border Background="{Binding Path=(fw:AccentColors.ImmersiveSystemAccentLight3Brush)}"><TextBlock Text="ImmersiveSystemAccentLight3Brush" /></Border></StackPanel><StackPanel Orientation="Horizontal"Margin="5"><Border Background="{Binding Path=(fw:AccentColors.ImmersiveSystemAccentDark1Brush)}"><TextBlock Text="ImmersiveSystemAccentDark1Brush"Foreground="White"/></Border><Border Background="{Binding Path=(fw:AccentColors.ImmersiveSystemAccentDark2Brush)}"><TextBlock Text="ImmersiveSystemAccentDark2Brush"Foreground="White"/></Border><Border Background="{Binding Path=(fw:AccentColors.ImmersiveSystemAccentDark3Brush)}"><TextBlock Text="ImmersiveSystemAccentDark3Brush"Foreground="White"/></Border></StackPanel><StackPanel Orientation="Horizontal"Margin="5"><Border Background="{x:Static fw:AccentColors.ImmersiveSystemAccentBrush}"><TextBlock Text="x:Static"/></Border><Border Background="{Binding Path=(fw:AccentColors.ImmersiveSystemAccentBrush)}"><TextBlock Text="Binding" /></Border></StackPanel>

f:id:minami_SC:20180221233148g:plain

ResourceDictionaryEXクラス

今回の更新の一番の目玉はコレ。
OSのLight/Darkのテーマごとに別々のResource定義を切り替える機能を追加しました。

アクリルなウィンドウ表示をするAcrylicWindowクラスなどでは、標準でこの機能を使ったスタイルに修正しています。
こんな風にOSのテーマ設定に応じて一部コントロールやウィンドウのデフォルト色設定が自動で切り替わります。

f:id:minami_SC:20180403010222g:plain

<fw:AcrylicWindow x:Class="FluentWpfTest.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:FluentWpfTest"xmlns:fw="clr-namespace:SourceChord.FluentWPF;assembly=FluentWPF"mc:Ignorable="d"Title="MainWindow"Height="300"Width="400"><Grid><TextBlock Text="Hello World!!"FontSize="32"HorizontalAlignment="Center"VerticalAlignment="Center"/></Grid></fw:AcrylicWindow>

アプリのテーマ設定~ResourceDictionaryEx.GlobalThemeプロパティ~

このプロパティを設定することで、アプリのテーマ設定を切り替える事ができます。

設定値内容
Defaultこの値を設定すると、OSのLight/Darkテーマ設定に応じて、アプリのテーマが自動で切り替わります(デフォルト値)
Lightアプリ内では常にLightテーマを使用します
Darkアプリ内では常にDarkテーマを使用します

こんな風に、Appクラスのコンストラクタとかで設定すればOKです。
App.xaml.cs

publicpartialclass App : Application
    {
        public App()
        {
            SourceChord.FluentWPF.ResourceDictionaryEx.GlobalTheme = SourceChord.FluentWPF.ElementTheme.Default;
        }
    }

テーマごとのリソース定義~ResourceDictionaryEx.ThemeDictionariesプロパティ~

こんな風にThemeDictionariesプロパティ内に、OSのテーマ設定ごとのThemeDictionaryを定義することで、テーマごとに自動で切り替わるリソースを簡単に定義できます。

f:id:minami_SC:20180403010251g:plain

<fw:AcrylicWindow x:Class="FluentWpfTest.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:FluentWpfTest"xmlns:fw="clr-namespace:SourceChord.FluentWPF;assembly=FluentWPF"mc:Ignorable="d"Title="MainWindow"Height="300"Width="400"><fw:AcrylicWindow.Resources><fw:ResourceDictionaryEx><SolidColorBrush x:Key="bgBrush">White</SolidColorBrush><fw:ResourceDictionaryEx.ThemeDictionaries><fw:ThemeDictionary ThemeName="Light"><Style TargetType="{x:Type Button}"><Setter Property="Background"Value="LightBlue" /></Style></fw:ThemeDictionary><fw:ThemeDictionary ThemeName="Dark"><Style TargetType="{x:Type Button}"><Setter Property="Background"Value="LightPink" /></Style></fw:ThemeDictionary></fw:ResourceDictionaryEx.ThemeDictionaries></fw:ResourceDictionaryEx></fw:AcrylicWindow.Resources><Grid><Button Content="Button"HorizontalAlignment="Center"VerticalAlignment="Center"Width="75"/></Grid></fw:AcrylicWindow>

ThemeDictionaryクラスは、ResourceDictionary派生のクラスとなってます。Themeプロパティで対象のテーマ名を指定する以外は、普通のResourceDictionaryと同じように使えます。

今後の予定

これから、以下のような更新をしていこうと考えてます。

Light/Dark用テーマの拡充

今回のバージョンアップで、ResourceDictionaryExクラスを使って、テーマごとのリソース切替ができるようになりました。
ですが、こういう仕組みは作りましたが、実際に切り替えるテーマ自体はまだあまり作り込めていません。

ということで、これから少しずつ各テーマごとのデザインを、もう少し作り込んでいきたいと思っています。

RS4のFluent Design Systemへの追従

今月初頭には、RS4ことWindows10 Spring Creators Updateが配信される、なんて話題がちらほら聞こえてきています。

RS4では、Fluent Designの各種エフェクトも色々とリファインされてきているので、RS4のエフェクトを見ながら再現度を高めていこうと思います。

Wikiの拡充

だいぶ機能が増えてきたので、使い方をREADMEに全部書くのもつらくなってきました。
ということで、Wikiにドキュメントを書いていこうと思ってます。
が、なかなか筆不精で進まない・・・orz

こちらも気の向いたときに書き進めていこうと思います。

今日のところはこの辺まで。

Electron+TypeScriptなプロジェクトの雛形を更新~Electron2.0.0+TypeScript2.8.3~

$
0
0

以前作ったElectron+TypeScriptのサンプルコードを、それぞれの最新バージョンにアップデートしました。

それぞれ、以下のバージョンに更新しました。

  • electron v2.0.0
  • typescript v2.8.3

今回もコードには変更を加えず、ライブラリ類のバージョン更新だけしてます。

ちなみに、electronがv2.0.0とメジャーバージョンが上がっています。
electron v2以降ではバージョニングのルールを変更し、今後はのアップデート時にはSemantic Versioningに沿ってバージョン番号を付けていくとのことです。 https://electronjs.org/blog/electron-2-semantic-boogaloo

ChromiumやNode.jsのメジャーバージョン更新でelectronのメジャーバージョンも上げていくとのことなので、今後はelectronのバージョンもChromeみたいに頻繁に上がっていくことになりそうですね。

Windows10 April 2018 Updateに更新してみました

$
0
0

配信が始まっていたので、さっそく更新してみました。

今回も、特に何もせずすぐにWindowsUpdateで通知されてたので、そのまま更新しました。 もしかしたら、以前に更新アシスタントなどを使ってアップデートした環境には早めに配信とかしてるのかな。。

スタートメニューや、設定アプリ、通知など、様々な部分にFluent Design Systemが適用された部分がだいぶ増えてきました。 f:id:minami_SC:20180504121143p:plainf:id:minami_SC:20180504121159p:plain

ただ、各画面やアプリごとで、Fluent DesignのRevealエフェクトの表現がそれぞれ微妙に違ったりします。
(Revealのボタン枠の太さとか細かい部分ですが・・)

そんな感じで、まだまだUIのチグハグ感は少し残ってます。
この辺はOS標準のアプリ類で足並みをそろえて、ルック&フィールを統一していって欲しいな、って感じです。

タイムラインとか、その他のOSの新機能はまだ活用できてないんで、その辺はこれから少しづつ試してみようかと思います。


FluentWPF 0.3.2をリリースしました

$
0
0

ここの所、色々立て込んでいて、ぜんぜんこの辺のライブラリをメンテできず、気づけばissueやプルリクをため込んでしまってました。
で、やっと少し対応する余裕ができたので、いただいたプルリクをマージしてFluentWPF0.3.2をリリースしました。

変更内容

  • クリーンインストールした直後のWindows10環境で落ちる不具合を修正
    • プルリクもらった内容(#12)です。
    • OSインストール後、一度もテーマ変更してない場合は、テーマ設定のレジストリ値が空で、それを見に行って落ちてたっぽい。。
  • ResourceDictionaryEx.GlobalThemeプロパティを設定しても、Default設定から変わらない不具合を修正
    • 常にDefault指定のOSのテーマ設定と連動した動作になっていた。。
    • ResourceDictionaryEx.GlobalTheme = ElementTheme.Light;などと設定することで、常にLight指定やDark指定での動作をできるようにしました。

今回は、取り急ぎ色々な不具合を修正しただけの変更です。
機能追加は、また今後のバージョンアップで対応したいと思ってます。

余談

気づけばGitHubでのスターも150程ついてました!!
自分で思ってた以上に反響があってうれしい限りです。

今年のBuildでは、XAML Islandsなんて話も出て、今後はWPFアプリでもUWP用コントロールを使う手段の提供がされてくるのかな、、なんて予感もします。
ですが、そういうのが普通に使えるようになるのは、まだしばらく先でしょうし、 今のところ、このライブラリもそこそこ需要がありそうなんで、今後もちまちまと更新をしていこうと思ってます。

OpenCvSharpでGrabCutを使った領域抽出

$
0
0

久しぶりに、OpenCVネタ。

OpenCvSharpを使って、grubcutでの領域抽出をやってみました。
OpenCVに用意されているGrabCut関数を使うと、画像中の前景/背景領域を簡単に抽出できます。

GrabCutは、「InitWithRect」「InitiWithMask」という二種類の方法で、抽出領域の指定ができます。
それぞれの方法を試してみました。

全コードは、↓のリポジトリに上げてます。

矩形の範囲指定での領域抽出

GrabCut関数の引数でGrabCutModes.InitWithRectを用いると、前景となるオブジェクトが含まれる部分を矩形で指定して抽出を行います。

privatestaticvoid GrabCutWithRect()
        {
            using (var img = new Mat(@"Images/1.jpg"))
            using (var mask = new Mat(img.Size(), MatType.CV_8UC3))
            {
                // 領域指定でGrabCutを実行
                var bmModel = new Mat();
                var fgModel = new Mat();
                Cv2.GrabCut(img, mask, new Rect(115, 20, 630, 625), bmModel, fgModel, 5, GrabCutModes.InitWithRect);

                // 前景(1)/おそらく前景(3)とラベリングされた部分⇒1、それ以外は0のマスク画像を作る
                var lut2 = newbyte[256];
                lut2[0] = 0; lut2[1] = 1; lut2[2] = 0; lut2[3] = 1;
                Cv2.LUT(mask, lut2, mask);

                // 前景部分を抽出
                var foreground = new Mat(img.Size(), MatType.CV_8UC3, new Scalar(0, 0, 0));
                img.CopyTo(foreground, mask);
                Cv2.ImShow("GrabCut(InitWithRect)", foreground);
            }
        }

マスク画像を使った領域抽出

今度は、InitWithMaskです。
このオプションでは、マスク用の画像を用いた抽出を行います。 マスク画像では、各ピクセル値で以下のように指定します。

意味
0背景
1おそらく背景
2前景
3おそらく前景

こういう、0,1,2,3だけの値で構成された画像を、ペイントなどのアプリで書くのはとても面倒です。
⇒というか、0~3の色の違いでは、ディスプレイ上ではほとんど区別がつきません。。。

ということで、まず以下のようなマスク画像を用意しました。
f:id:minami_SC:20181008234737p:plain

で、これをプログラムで読み込んでから、以下のようにピクセル値を置換してからGrabCut関数に渡しています。

  • 0・・・たぶん背景の部分⇒2
  • 255・・・たぶん前景の部分⇒3

コードは以下のような感じ。

privatestaticvoid GrabCutWithMask()
        {
            using (var img = new Mat(@"Images/1.jpg"))
            using (var mask = new Mat(@"Images/1_mask.png", ImreadModes.GrayScale))
            {
                var lut = Enumerable.Repeat<byte>(2, 256)
                                    .ToArray();
                // マスク画像として用意したbmpの各ピクセル値を以下のように変換する// 黒(0)      ⇒おそらく背景(2)// 白(255)    ⇒おそらく前景(3)
                lut[0] = (byte)2;
                lut[255] = (byte)3;
                Cv2.LUT(mask, lut, mask);

                // マスク画像を用いてGrabCutを実行
                var bmModel = new Mat();
                var fgModel = new Mat();
                Cv2.GrabCut(img, mask, Rect.Empty, bmModel, fgModel, 5, GrabCutModes.InitWithMask);

                // 前景(1)/おそらく前景(3)とラベリングされた部分⇒1、それ以外は0のマスク画像を作る
                var lut2 = newbyte[256];
                lut2[0] = 0; lut2[1] = 1; lut2[2] = 0; lut2[3] = 1;
                Cv2.LUT(mask, lut2, mask);

                // 前景部分を抽出
                var foreground = new Mat(img.Size(), MatType.CV_8UC3, new Scalar(0, 0, 0));
                img.CopyTo(foreground, mask);
                Cv2.ImShow("GrabCut(InitWithMask)", foreground);
            }
        }

実行すると、それぞれの方法での抽出結果が各ウィンドウに表示されます。

この画像が
f:id:minami_SC:20181008234623j:plain

こうなる!!
f:id:minami_SC:20181008234644j:plain

このマスク画像作成用のUIでも別途作れば、 お手軽に画像切り抜きアプリなども作れそうですね。

今日のとこは、この辺までで。

Electron+TypeScriptなプロジェクトの雛形を更新~Electron3.0.3+TypeScript3.1.1~

$
0
0

以前作ったElectron+TypeScriptのサンプルコードを、それぞれの最新バージョンにアップデートしました。

以下のバージョンに更新してます。

  • electron v3.0.3
  • typescript v3.1.1

今回もコードには変更を加えず、ライブラリ類のバージョン更新だけしました。

electronもTypeScriptも、メジャーバージョンが上がっているので、対応いるかと思ってたんですが、 npmパッケージのバージョンを上げただけで、難なく動作しました。

あと、久しぶりにelectron-packagerを動作させてみたら、コマンドライン引数の指定方法が若干変わってました。
このelectronのバージョン指定は、--versionではなく、--electron-versionになったようですね。
この辺のnpmスクリプトも、あわせて修正しておきました。

FluentWPF 0.4.0をリリースしました

$
0
0

久しぶりに更新しました。

Release v0.4.0 · sourcechord/FluentWPF · GitHub

今回の更新の一番の目玉は、AcrylicWindowのアクリル効果をUWPと同じようなちゃんとしたアクリル効果に対応した点です。(Win10 1809以降のみ)

変更内容

  • AcrylicWindowのアクリル効果を改善
    • UWPと同じようなしっかりボケた感じのAcrylic効果に対応しました。(Win10 1809以降の環境のみ)
  • Button
    • RevealButtonStyle/RevealAccentButtonStyle適用時の、ボタンDisable時の表示を改善
    • IsEnabeld="False"としても、UIの無効表示がわかりにくかった点を修正しました。
  • その他
    • ロゴ画像を作成
      • 適当にロゴ画像を作って、GitHubのREADMEやNugetパッケージの画像として設定しました。

やったこと

AcrylicWindowのアクリル効果改善

FluentWPFでは、ウィンドウのアクリル化をSetWindowCompositionAttributeという非公開APIを使って実現してます。
で、Windows10(1803)から、このAPIのオプションでUWPと同じようなアクリル効果が使えるようになった・・・のですが。
WPFのWindowChromeのカスタマイズをかけた状態で、このAPIの新規オプションを使うと、ウィンドウ背景黒くなったり、UIの再描画がおかしくなったり、、と色々奇妙な動作をしていました。

せっかく新規オプションでUWP風のアクリル効果ができるようになったのに、FluentWPFにこの機能を取り込むことができずにいました。
まぁ、非公開APIを使って色々やってるんで、あまり文句は言えませんね。

この表示オプションですが、先日のWindows10(1809)環境では、WPFでWindowChrome弄った状態でもちゃんと表示できるようになってました。
ということで、OSバージョンをチェックし、1809以降であればこのUWPと同じアクリル効果をつけるようにしてます。

FluentWPF0.3.2と、0.4.0で比較するとこの通り。

FluentWPF0.3.2FluentWPF0.4.0
f:id:minami_SC:20181014101031p:plain:w250f:id:minami_SC:20181014101041p:plain:w250

AcrylicWindowはデフォルトで、薄い白のTintColorをかけてます。このTintColorを消すと↓みたいな表示になります。 f:id:minami_SC:20181014101051p:plain
今までよりも、しっかりとブラーがかかっています。

背景がよりボケてくれるので、ウィンドウ内のコンテンツの視認性がよくなってます!!

BrushAnimationクラスの作成

FluentWPFでは、Revealな各種エフェクトをXAMLの各種スタイルやアニメーションを駆使して再現してます。

で、こういう見た目の変化やアニメーションを、SetterやStoryboardなどを使って書いてきました。
アニメーションの作成には、XAMLのStoryBoardなどを活用すると色々便利なのですが、WPFXAMLにはBrush用のアニメーションが無く、ブラシをStoryboardで変化させることができませんでした。
これが地味にキツイ・・・(UWPにはBrushAnimationあるのに・・・)

ってことで、以下のページを参考に、BrushをAnimationするクラスを用意しました。
https://stackoverflow.com/questions/8096852/brush-to-brush-animation

こんな感じのクラスを作ってます。
https://github.com/sourcechord/FluentWPF/blob/master/FluentWPF/Animations/BrushAnimation.cs
これを使って、Storyboardでブラシを変化できるようにして、ボタンDisalbe時の表示切替などを作りました。

これから、各種コントロールFluent Design風のスタイルを拡充しようと思ってるので、色々使い道はあるかな・・と思ってます。

ロゴ画像の追加

せっかくなので、もうちょっとライブラリの体裁を整えてみようと思い、ロゴ画像を作ってGitHubのREADMEやNugetパッケージの画像として付けてみました。
こういう部分作ると、なんか急にそれっぽくなって、ちょっと気分いいですね♪

f:id:minami_SC:20181014102245p:plain
f:id:minami_SC:20181014102320p:plain

ロゴ画像の作成

Fluent Design System発表時のムービーに出てきた、いろんな素材の立方体みたいなのをイメージして、3Dオブジェクトの立方体を並べて作りました。
(立方体並べるだけなら、3Dモデリングソフトやグラフィック系のソフトのスキルがあまり無くても作れるかな、、、と思ったりでw)

最初はフリーの定番3DモデリングソフトのBlenderでも使おうと思い、色々いじってました。
ですが、レンダリングしたときの質感を思ったように調整できず、、、かといってちゃんとBlenderの使い方を学ぶのもメンドイし、、、

そう思ってたとこで、そういえばWindows10標準でも、色々と3D系のアプリがあることを思い出しました。
3DBuilderとか、Paint3Dとか入ってますよね。

今回は、3DBuilderで立方体を並べて、それをPaint3Dに持っていって、PNG画像として保存しました。
(3DBuilder単体では、3Dモデルの形状ファイルしか作成できず、pngやjpg画像の保存はできないようです)
f:id:minami_SC:20181014101519p:plain

正直、今までこんなソフトどこで使うんだ、、、と思ってたりしましたが、意外なとこで活用できました。
3DBuilder、できることは限られてますが、だからこそのシンプルな操作性で、使ってみると意外と面白かったです。

適当に作った割には、それっぽいロゴ画像になったかな、、と。
ただ、もうちょっとアクリル感のある素材にしたいと思ったけど、3DBuilderやPaint3Dでは質感の調整はあまりできませんね。

気が向いたら、久しぶりにPOV-Rayとか使って、もっとしっかりと作り込んだ画像作ってみようかと思います。

FluentWPF 0.4.1をリリースしました

$
0
0

今回はちょっとしたバグフィックスなど、軽めの更新です。

Release v0.4.1 · sourcechord/FluentWPF · GitHub

変更内容

  • AcrylicWindow

    • Windows7や8.x環境でも、ウィンドウのタイトルバー右側のアイコンが表示されるよう対応
  • Button

    • RevealButtonStyle/RevealAccentButtonStyle適用時の、ボタンDisable時の表示を改善
    • IsEnabeld="False"としても、UIの無効表示がわかりにくかった点を修正

AcrylicWindowタイトルバーのボタン表示

こんな風に、Windows7環境でも、ちゃんとタイトルバーの各種ボタンが描画されるようになりました。
f:id:minami_SC:20181023083946p:plain

今までは、この辺のボタンはWindows10に含まれるSegoe MDL2 Assetsというフォントを使って描画してました。
ですが、これらのフォントはWin7Windows8.xには含まれておらず、そのような環境ではアイコン表示が化けてしまいます。

てことで、ボタンのアイコンを、Segoe MDL2 Assetsを使った文字ではなく、XAMLのPathでベクター図形として描くよう変更しました。

ただ、Windows7環境での表示は、まだあまりキレイではないですね。。。
Win7だったらAeroGrass効果をかける、、などなど、今後のアップデートで少しずつ改良していきたいと思います。

Viewing all 153 articles
Browse latest View live