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

WPFでアクリルなコンテキストメニューを作ってみた

$
0
0

この記事は、C# Advent Calendar 2018の4日目の記事です。

C#というかWPFXAMLに特化したネタで失礼します。
Windows10ではOSデザインの刷新として、FluentDesignSystemが段階的に導入されてきてます。
そんなFluentDesignのルック&フィールにマッチするような、半透明のアクリル効果が効いたコンテキストメニューWPF向けに作ってみました。

アクリルなコンテキストメニュー

まずは、出来上がったコンテキストメニューの動作を、以下のgifアニメで見てください。
f:id:minami_SC:20181204231238g:plain
ほんのりと、背景が透けたメニューになっていることがわかるかと思います。

あと、メニュー左側のアイコンとかチェック状態を表示する部分で、ドロップシャドウを使ってうっすらと立体感を出してるのがこだわりポイント!!

ContextMenuAcrylicContextMenu
f:id:minami_SC:20181204231348p:plainf:id:minami_SC:20181204231357p:plain

こういうコンテキストメニューを、WPFアプリで簡単に使えるようにライブラリ化しました。

1年ほど前から、WPF向けにFluent DesignXAML上で力技で再現したFluentWPFというライブラリを公開しているのですが、この中にAcrylicContextMenuというコントロールを追加してます。

使い方

まずは、このAcrylicContextMenuの使い方から説明します。

1. WPFアプリのプロジェクトを作り、nugetでFluentWPFと検索し、パッケージをインストールします。f:id:minami_SC:20181204232409p:plain
2. XAML名前空間の宣言に、以下の記述を追加します。

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

3. 通常のContextMenuのかわりにAcrylicContextMenuを配置します。

<Grid Background="Transparent"><Grid.ContextMenu><fw:AcrylicContextMenu><MenuItem Header="MenuItem1"/><MenuItem Header="MenuItem2"/><MenuItem Header="MenuItem3"IsEnabled="False"/><MenuItem Header="MenuItem4"/><Separator /><MenuItem Header="MenuItem5"IsCheckable="True"IsChecked="True"/><MenuItem Header="MenuItem6"><MenuItem.Icon><Rectangle Margin="2"Fill="DarkRed"/></MenuItem.Icon></MenuItem><Separator /><MenuItem Header="MenuItem7"/><MenuItem Header="Sub"><MenuItem Header="SubMenuItem1"/><MenuItem Header="SubMenuItem2"/><Separator /><MenuItem Header="SubMenuItem3"IsCheckable="True"IsChecked="True"/><Separator /><MenuItem Header="Sub"><MenuItem Header="Item1"/><MenuItem Header="Item2"/></MenuItem></MenuItem></fw:AcrylicContextMenu></Grid.ContextMenu></Grid>

これで、以下のようなメニューが表示できます。
f:id:minami_SC:20181204231427p:plain

アクリルなコンテキストメニューの作り方

コンテキストメニューにアクリル効果を適用するために、ライブラリ内部でやっていることも説明したいと思います。

WPFコンテキストメニューは、元のウィンドウとは別のウィンドウハンドルを持ったものとして画面に描画されています。
f:id:minami_SC:20181204231617p:plain

コンテキストメニューを半透過にするには、このメニュー用の別ウィンドウに対して、「ウィンドウのアクリル化」処理を行う、ということが基本的な方針となります。

ウィンドウのアクリル化

ウィンドウにFluentDesignのアクリル効果を適用するには、Win32APIの非公開APIのSetWindowCompositionAttributeという関数を使用します。

このAPIでウィンドウを半透明にしたら、あとはウィンドウのAllowsTransparencyプロパティをTrueにしたり、背景色をTransparentにするなどして、WPFのUIレイヤーで描画する背景を透明にすれば出来上がり!!

細かい説明は、以前書いた↓の記事をご参照ください。
WPFでFluent Design Systemのアクリルっぽいウィンドウを作ってみる - SourceChord

コンテキストメニューのアクリル化

先ほど書いた通り、WPFコンテキストメニューは、WPFで描画している元のウィンドウとは別のウィンドウが新たに作られ、そのウィンドウ上にメニューの内容が表示されます。
WPFのメニューでアクリルな表示をするには、このメニューのウィンドウハンドルを用いて、SetWindowCompositionAttribute関数を呼び出せば良い、、、ということになります。

ContextMenu用のウィンドウが作られるタイミングは、OnOpenedというイベントで捕らえることができます。
このメソッドをオーバーライドして、SetWindowCompositionAttribute関数を呼び出すことで、コンテキストメニューをアクリル化します。

以下のようなContextMenu派生クラスを作り、、、

publicclass AcrylicContextMenu : ContextMenu
    {
        [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;
        }

        protectedoverridevoid OnOpened(RoutedEventArgs e)
        {
            base.OnOpened(e);

            var hwnd = (HwndSource)HwndSource.FromVisual(this);
            // ウィンドウハンドルを指定して、ウィンドウのアクリル化を行う。
            EnableBlur(hwnd.Handle);
        }

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

        internalstaticvoid EnableBlur(IntPtr hwnd)
        {
            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(hwnd, ref data);

            Marshal.FreeHGlobal(accentPtr);
        }
    }

XAML側でこんな風に使えば、アクリルな半透過効果がかかったコンテキストメニューを表示できます。

<Grid Background="Transparent"><Grid.ContextMenu><local:AcrylicContextMenu Background="Transparent"HasDropShadow="False"><MenuItem Header="MenuItem1" /><MenuItem Header="MenuItem2" /><MenuItem Header="MenuItem3" /><MenuItem Header="MenuItem4" /><Separator Background="#44000000"Foreground="#CC000000" /><MenuItem Header="MenuItem5" /><MenuItem Header="MenuItem6" /><Separator Background="#44000000"Foreground="#CC000000" /><MenuItem Header="MenuItem7" /></local:AcrylicContextMenu></Grid.ContextMenu></Grid>

f:id:minami_SC:20181204231813p:plain
実際には、もうちょっとスタイルの作り込みなども必要ですが、メニューにアクリル効果を適用するための手順について、なんとなく雰囲気はつかめるのではないでしょうか。

サブメニューのアクリル化

先ほどの手順を行えば、コンテキストメニューを最初に開いたときの表示はアクリル化ができます。
しかし、コンテキストメニューでは、サブメニューを持つこともあります。
サブメニューの部分は、また別のウィンドウハンドルを持ったものとなっており、別途アクリル化をしなければなりません。
f:id:minami_SC:20181204231836p:plain

そこで、WPF標準のMenuやContextMenuなどのスタイルを見てみると、このサブメニュー部分はPopupコントロールとして描画されていることがわかります。

Menuコントロール内で、サブメニュー表示を行う部分のスタイル定義を抜粋
<Border x:Name="templateRoot"BorderBrush="{TemplateBinding BorderBrush}"BorderThickness="{TemplateBinding BorderThickness}"Background="{TemplateBinding Background}"SnapsToDevicePixels="True"><Grid Margin="-1"><Grid.ColumnDefinitions><ColumnDefinition MinWidth="22"SharedSizeGroup="MenuItemIconColumnGroup"Width="Auto"/><ColumnDefinition Width="13"/><ColumnDefinition Width="*"/><ColumnDefinition Width="30"/><ColumnDefinition SharedSizeGroup="MenuItemIGTColumnGroup"Width="Auto"/><ColumnDefinition Width="20"/></Grid.ColumnDefinitions><ContentPresenter x:Name="Icon"Content="{TemplateBinding Icon}"ContentSource="Icon"HorizontalAlignment="Center"Height="16"Margin="3"SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"VerticalAlignment="Center"Width="16"/><Border x:Name="GlyphPanel"BorderBrush="#FF26A0DA"BorderThickness="1"Background="#3D26A0DA"Height="22"Margin="-1,0,0,0"Visibility="Hidden"VerticalAlignment="Center"Width="22"><Path x:Name="Glyph"Data="F1M10,1.2L4.7,9.1 4.5,9.1 0,5.2 1.3,3.5 4.3,6.1 8.3,0 10,1.2z"Fill="#FF212121"FlowDirection="LeftToRight"Height="11"Width="9"/></Border><ContentPresenter ContentTemplate="{TemplateBinding HeaderTemplate}"Content="{TemplateBinding Header}"Grid.Column="2"ContentStringFormat="{TemplateBinding HeaderStringFormat}"ContentSource="Header"HorizontalAlignment="Left"Margin="{TemplateBinding Padding}"RecognizesAccessKey="True"SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"VerticalAlignment="Center"/><TextBlock Grid.Column="4"Margin="{TemplateBinding Padding}"Opacity="0.7"Text="{TemplateBinding InputGestureText}"VerticalAlignment="Center"/><Path x:Name="RightArrow"Grid.Column="5"Data="M0,0L4,3.5 0,7z"Fill="#FF212121"HorizontalAlignment="Left"Margin="10,0,0,0"VerticalAlignment="Center"/><Popup x:Name="PART_Popup"AllowsTransparency="True"Focusable="False"HorizontalOffset="-2"IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}"PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}"Placement="Right"VerticalOffset="-3"><Border x:Name="SubMenuBorder"BorderBrush="#FF999999"BorderThickness="1"Background="#FFF0F0F0"Padding="2"><ScrollViewer x:Name="SubMenuScrollViewer"Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}}"><Grid RenderOptions.ClearTypeHint="Enabled"><Canvas HorizontalAlignment="Left"Height="0"VerticalAlignment="Top"Width="0"><Rectangle x:Name="OpaqueRect"Fill="{Binding Background, ElementName=SubMenuBorder}"Height="{Binding ActualHeight, ElementName=SubMenuBorder}"Width="{Binding ActualWidth, ElementName=SubMenuBorder}"/></Canvas><Rectangle Fill="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"HorizontalAlignment="Left"Margin="29,2,0,2"Width="1"/><ItemsPresenter x:Name="ItemsPresenter"KeyboardNavigation.DirectionalNavigation="Cycle"Grid.IsSharedSizeScope="True"SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"KeyboardNavigation.TabNavigation="Cycle"/></Grid></ScrollViewer></Border></Popup></Grid></Border>

しかし、標準のPopupコントロールはもちろんアクリルな半透過表示には対応してません。
ということで、アクリル効果の効いたサブメニューを作るには、別途アクリル効果に対応したPopupコントロールが必要になります。
詳細なコードについては省略しますが、今回AcrylicPopupという、アクリルな表示をするPopup派生コントロールを作ってみました。

こんな感じのコントロールです。

<fw:AcrylicPopup x:Name="popupAcrylic"PopupAnimation="None"Placement="Bottom"PlacementTarget="{Binding ElementName=toggleAcrylicPopup}"><Border Width="200"Height="75"BorderBrush="LightGray"BorderThickness="1"Background="{DynamicResource SystemAltMediumLowColorBrush}"><TextBlock Text="This is AcrylicPopup" /></Border></fw:AcrylicPopup>

f:id:minami_SC:20181204231856p:plain
AcrylicContextMenuのスタイル定義の中で、このAcrylicPopupクラスを標準Popupのかわりに用いることで、サブメニューまで含めてアクリル化しました。

最後に

今回、こんな感じでContextMenuから派生した、独自のコンテキストメニューを作ってみました。
WPFのContextMenuなどのコントロールは、メインのウィンドウとは異なるウィンドウハンドルを持った要素が出てくるため、コントロールのカスタマイズやスタイル定義などもちょっと面倒なコントロールと感じます。

ということで、こういう表示をお手軽に試してみたい場合には、記事冒頭で紹介した拙作のFluentWPFライブラリ、よかったら使ってみてくださいませ♪
XAML Islandsなんてのも出てきて、WPFからもUWPコントロールを使えるようになってきてますが、このライブラリも当面は開発も続けようと思ってます!!


FluentWPF 0.6.1をリリースしました

$
0
0

FluentWPF 0.6.0をリリースしました。
Release v0.6.1 · sourcechord/FluentWPF · GitHub

今回の変更内容は以下の通り。

  • 新機能
    • アクリル効果付きのメニュー・・・AcrylicMenuStyle
    • TextBox/PasswordBox用の添付プロパティ追加・・・Extensions.PlaceholderText, Extensions.Header
  • バグフィックス
    • AcrylicWindowのウィンドウ枠の色が、OSのテーマカラーに追従しない不具合を修正
    • ButtonRevealStyle使用時に起きるバインディングエラーを修正

アクリル効果付きのメニュー~AcrylicMenuStyle~

前回のAcrylicContextMenuに続き、Acrylicなメニューも追加しました。
こちらはカスタムコントロールではなく、スタイルとしての提供です。

こんなコードで、、、

<fw:AcrylicWindow x:Class="FluentWPFSample.Views.AcrylicMenuSample"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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:FluentWPFSample.Views"mc:Ignorable="d"Title="AcrylicMenuSample"Height="200"Width="350"><DockPanel><Menu DockPanel.Dock="Top"VerticalAlignment="Top"Style="{StaticResource AcrylicMenuStyle}"><MenuItem Header="MenuItem1"><MenuItem Header="MenuItem3" /><MenuItem Header="MenuItem4" /><MenuItem Header="Sub"><MenuItem Header="MenuItem3" /><MenuItem Header="MenuItem4" /></MenuItem></MenuItem><MenuItem Header="MenuItem2"><MenuItem Header="MenuItem3" /><MenuItem Header="MenuItem4" /><MenuItem Header="Sub"><MenuItem Header="MenuItem3" /><MenuItem Header="MenuItem4" /></MenuItem></MenuItem></Menu></DockPanel></fw:AcrylicWindow>

こんなメニューが作れます。
f:id:minami_SC:20181220233223g:plain

TextBox/PasswordBox向けの新機能

↓のプルリクでいただいた内容です。
TextBox and PasswordBox PlaceHolder and Header thru attached properties by fangeles02 · Pull Request #35 · sourcechord/FluentWPF · GitHub
UWPのTextBox/PasswordBoxなどと同じように、PlaceholderTextやHeaderプロパティを付けられるよう、添付プロパティを作っています。

TextBox/PasswordBoxに対し、以下の二つの添付プロパティを用意しました。

プロパティ名説明
Extensions.Headerstringコントロール上部に表示するヘッダー文字列を設定
Extensions.PlaceholderTextstringテキストが空欄の時に表示されるウォーターマーク表示の文字列を設定

こういうコードで、、、

<StackPanel><TextBox HorizontalAlignment="Left"Margin="5"Width="200"Style="{StaticResource TextBoxRevealStyle}"fw:Extensions.PlaceholderText="Placeholder"fw:Extensions.Header="Header"/><PasswordBox HorizontalAlignment="Left"Margin="5"Width="200"Style="{StaticResource PasswordBoxRevealStyle}"fw:Extensions.PlaceholderText="Password"fw:Extensions.Header="Password"/></StackPanel>

こうなります。
f:id:minami_SC:20181220233248g:plain

バグフィックス

細かいバグ修正もしてます。
今まで、OSのテーマカラー変更しても、ウィンドウ枠のボーダー色が追従してなかったのですが、ちゃんと追従するようにしました。
f:id:minami_SC:20181220233312g:plain

Visual Studio 2019をインストールしてみた

$
0
0

リリースされたんでさっそくインストールしてみました。
メモリ消費がだいぶ少なくなったり起動周りのパフォーマンス向上とか、地味にうれしい点が多いですね。

コンパイラの言語バージョンをC# 8.0(beta)とかにしておいて、
f:id:minami_SC:20190406183404p:plain
#nullable enable指定をつけておけば、null許容参照型の機能も使えます。
f:id:minami_SC:20190406182929p:plain

C#8.0はまだプレビュー扱いですが、今のうちに少しずつこういった機能にも慣れておこうかな、と思います。

あと、Xamarin.Formsもこんな風にプレビュー表示とプロパティ表示が出るようになってますね。
f:id:minami_SC:20190406185000p:plain
そろそろXamarinに本腰入れて取り組みたい、、、と思ったり。

Lighty 0.3.2をリリースしました

$
0
0

以前、WPFでウィンドウ内にLightBox表示のようなダイアログ表示をするライブラリを作ったのですが、久々の更新をしました。

バグ修正のプルリクいただいたんで、マージしてv0.3.2としてリリースしました。

修正内容

修正内容は以下の1点のみです。

  • ShowAsyncメソッドでダイアログ表示する際、背景部分をクリックしてもダイアログを閉じれない問題を修正

最近、全然更新できてなかったけど、他のライブラリもIssuesなどたまってきているので、色々対応していきたいなぁ、、、というところ。

Windows10 1903 insider previewでアクリル化のAPIがおかしい・・・

$
0
0

ちょっと前に、以下のようなIssueをもらったので、見ていました。

近々リリースされる予定のWindows10 1903環境で、FluentWPFのAcrylicWindowの動作がおかしいとのこと。
ウィンドウをドラッグすると、UIの応答が非常に悪くなり、ウィンドウの移動がマウス操作に追従しなくなるようです。

Hyper-V環境で試してみても、報告されてる現象はどうにもうまく再現しなかったので、
自分のサブPCをWin10 1903 Release Previewに更新して試してみたところ、Issueに書かれてた現象が再現できました。

以下のようなウィンドウドラッグ操作時にUI描画が非常に遅くなります。

f:id:minami_SC:20190517235308g:plain

  • マウスカーソルがウィンドウに追従してるんでGifアニメでは問題なく感じるかもしれませんが、実際は手元のマウス操作からワンテンポずれて移動してます
  • このドラッグ操作中、UI描画全体が遅くなっている感じで、Gifアニメ用の動画キャプチャもフレームが飛び飛びになりました・・・

Hyper-V環境のような、半透明効果が正しく適用されない環境では再現しない不具合だったようです。

原因?

FluentWPFでは、ウィンドウにアクリルな半透明化処理を加えるために、SetWindowCompositionAttributeというWin32の非公開APIを使用しています。
このAPIが、Windows10 1903ではどうやらうまく動いていないようです。
また、OS標準の絵文字ツールバーですが、こちらも同様にウィンドウをドラッグで移動すると、極端に応答が悪くなる現象が発生しています。
f:id:minami_SC:20190517235334g:plain

で、色々調べてみると、以下のリポジトリでも同様の問題が報告されてました。
Lag when moving window (draging window with mouse) in Windows10 1903 · Issue #2 · riverar/sample-win32-acrylicblur · GitHub

FeedbackHubにも、この現象の報告が上がってました。

https://aka.ms/AA4pzyf
https://aka.ms/AA4fmz7

現状はここに賛成票を送っておいて、修正されることを祈るしかないかなぁ。
ちょっと、どうしたもんか。。。

ちなみにSetWindowCompositionAttributeAPIで、AccentState.ACCENT_ENABLE_ACRYLICBLURBEHINDを使用すると前述のような不具合が出るのですが、ACCENT_ENABLE_BLURBEHINDを使うと今のところスムーズに表示されるっぽい。
このまま修正されずにWin10 1903がローンチされてしまったら、当面は1903環境ではACCENT_ENABLE_BLURBEHIND指定でのUI表示をするように対処するしかないかな。

Windows 10 May 2019 Updateに更新してみました

$
0
0

リリースされたんでアップデートしてみました。

Winキー+Shift+sキーのショートカットで、ウィンドウ単位のキャプチャができるようになってますね。
f:id:minami_SC:20190526232927p:plain

基本的にAlt+PrintScreenのショートカットで事足りてるんで、あんま使わないだろうけど、どこかで使うこともあるかな。

で、一番気になってた↓の件ですが、ここはやはり変わらず、そのままリリースされてました。
Windows10 1903 insider previewでアクリル化のAPIがおかしい・・・ - SourceChord

今のところ回避策はなさそうなので、FluentWPFではWin10 1903環境の時はUWPとは異なる古い半透過エフェクトを使うよう対策を入れようと思います。

FluentWPF 0.7.0をリリースしました

$
0
0

Release v0.7.0 · sourcechord/FluentWPF · GitHub

今回は、AcrylicWindow関係の機能強化とバグフィックスが主な更新内容です。
ウィンドウやタイトルバー周りのカスタマイズ性を向上させたので、いろんなデザイン作りやすくなったんじゃないかな。

新機能

AcrylicWindow

AcrylicWindowStyleプロパティの追加
AcrylicWindowStyle="Nomal"AcrylicWindowStyle="NoIcon"AcrylicWindowStyle="None"
f:id:minami_SC:20190602170434p:plainf:id:minami_SC:20190602170505p:plainf:id:minami_SC:20190602170447p:plain
TitleBarプロパティの追加

こんな風に、タイトルバーの描画内容をカスタマイズできます。

<fw:AcrylicWindow x:Class="FluentWPFSample.Views.AcrylicWindow4"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:fw="clr-namespace:SourceChord.FluentWPF;assembly=FluentWPF"xmlns:local="clr-namespace:FluentWPFSample.Views"mc:Ignorable="d"Title="AcrylicWindow4"Height="450"Width="800"><fw:AcrylicWindow.TitleBar><Grid><Grid.ColumnDefinitions><ColumnDefinition /><ColumnDefinition /></Grid.ColumnDefinitions><TextBlock Text="Custom TitleBar"VerticalAlignment="Center"Margin="8,0,0,0"/><StackPanel Grid.Column="1"Orientation="Horizontal"HorizontalAlignment="Right"WindowChrome.IsHitTestVisibleInChrome="True"><Button Content="Button"Width="60"Margin="5"/><Button Content="Button"Width="60"Margin="5"/></StackPanel></Grid></fw:AcrylicWindow.TitleBar><Grid></Grid></fw:AcrylicWindow>

f:id:minami_SC:20190602171012p:plain

また、↓のようにMenuと組み合わせると、
最近のVisualStudioやVisualStudioCodeみたいに、タイトルバー領域にメニューが入り込んだウィンドウとかもお手軽に作れます。

<fw:AcrylicWindow x:Class="FluentWPFSample.Views.AcrylicWindow4"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:fw="clr-namespace:SourceChord.FluentWPF;assembly=FluentWPF"xmlns:local="clr-namespace:FluentWPFSample.Views"mc:Ignorable="d"Title="AcrylicWindow4"Height="450"Width="800"TitleBarMode="Extend"><fw:AcrylicWindow.TitleBar><fw:DropShadowPanel ShadowMode="Outer"BlurRadius="8"ShadowOpacity="0.6"><Grid WindowChrome.IsHitTestVisibleInChrome="True"><Grid.ColumnDefinitions><ColumnDefinition /><ColumnDefinition /></Grid.ColumnDefinitions><Menu Style="{StaticResource AcrylicMenuStyle}"HorizontalAlignment="Left"VerticalAlignment="Center"><MenuItem Header="MenuItem1"><MenuItem Header="MenuItem3" /><MenuItem Header="MenuItem4" /><MenuItem Header="Sub"><MenuItem Header="MenuItem3" /><MenuItem Header="MenuItem4" /></MenuItem></MenuItem><MenuItem Header="MenuItem2"><MenuItem Header="MenuItem3" /><MenuItem Header="MenuItem4" /><MenuItem Header="Sub"><MenuItem Header="MenuItem3" /><MenuItem Header="MenuItem4" /></MenuItem></MenuItem></Menu><TextBox Grid.Column="1"HorizontalAlignment="Left"Margin="0,2,140,2"Width="200"Height="24"FontSize="12"Padding="2"BorderThickness="1"Style="{StaticResource TextBoxRevealStyle}"fw:Extensions.PlaceholderText="Placeholder"/></Grid></fw:DropShadowPanel></fw:AcrylicWindow.TitleBar><Grid></Grid></fw:AcrylicWindow>

f:id:minami_SC:20190602171129g:plain

.NET Core3への対応

FluentWPFでは、実行環境のOSバージョンを調べるために、System.Managementのdllを参照してこの中のManagementClassクラスなどを使用していました。

.NET Core環境では、そのままではこのクラスは利用できず、Windows.Compatabilityをインストールしてこの中のクラスへの参照に切り替えなければいけません。 ですが、今までの.NET Framework環境向けと、.NET Core環境向けで、それぞれに応じて参照を切り替えるとプロジェクトの構成が無駄に複雑になりそうでした。

そこで、ManagementClassクラスを使うのではなく、レジストリ値を参照してバージョン情報チェックを行うようにして、System.Managementへの依存を取り除きました。
これによって、今回のFluentWPF 0.7.0からは、.NET Core3.0環境のWPFプロジェクトでも、FluentWPFをインストールして使えるようになりました。
f:id:minami_SC:20190602171904p:plain

不具合対応

Windows10 1903環境で、AcrylicWindowが正常に表示されない問題を修正

先日以下の記事で書いた件です。
Windows 10 May 2019 Updateに更新してみました - SourceChord

Windows10 1903環境では、SetWindowCompositionAttribute関数を使ってUWP風のアクリル効果を適用すると、マウス操作でのウィンドウ移動が異常に遅くなったり、ウィンドウのコンテンツが描画されなくなったりと、色々とおかしな動作をします。

ということで、1903環境では、以前のFluentWPFでも使用していた、ぼかし効果が弱めの半透過エフェクトを使用するように修正しました。

現状、こうする以外の対処は難しそうです。
今後、OSのバージョンアップ時に、このAPIの動作が修正されたら、また対応を考えようと思います。

その他
  • AcrylicWindow最大化時に、ウィンドウのコンテンツが画面外にはみ出してしまう問題を修正

破壊的変更

AcrylicWindow.ShowTitleBarプロパティの削除

今まで、AcrylicWindowのタイトルバーやウィンドウ右上のボタンを消すために、ShowTitleBarというプロパティを用意してました。
ですが、今回追加したAcrylicWindowStyleと役割が被るので、このプロパティは削除しました。
ShowTitleBarを使っていた場所では、代わりにAcrylicWindowStyle="None"を使ってください。

MVVMでViewModelから別ウィンドウ表示をするサンプル~シンプルなTODOリスト~

$
0
0

以前、MVVMパターンで設計する際に、ダイアログ表示をどう行うか、、という内容で↓の記事のようなサンプルを書きました。

今回はコレの派生形として、任意のウィンドウをMVVMなパターンで表示するサンプルを書いてみました。

こんな感じの、よくあるTODOリストアプリです。
TODO項目の追加/編集を別ウィンドウで入力/編集する、というUIになっています。
f:id:minami_SC:20190609220554g:plain

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

概要

ViewModelからダイアログ表示をするにあたり、ViewModelから直接Viewを参照するのではなく、サービスクラスを作ってこのインスタンスを外部からDIする、という基本的な概念は前回のサンプルと同じです。

今回のサンプルでは、ウィンドウ表示処理をVMから指示するために、以下のようなインターフェースを定義しました。

IShowWindowService.cs

interface IShowWindowService<TViewModel>
    {
        bool? ShowDialog(TViewModel context);
    }

ShowWindowService.cs

class ShowWindowService<TWindow, TViewModel> : IShowWindowService<TViewModel>
        where TWindow : Window, new()
    {
        public Window Owner { get; set; }

        publicbool? ShowDialog(TViewModel context)
        {
            var dlg = new TWindow()
            {
                Owner = this.Owner,
                DataContext = context,
            };

            return dlg.ShowDialog();
        }

        publicvoid Show(TViewModel context)
        {
            var dlg = new TWindow()
            {
                Owner = this.Owner,
                DataContext = context,
            };

            dlg.Show();
        }
    }

サービスのIFはIShowWindowService<TViewModel>ですが、それを継承したサービス実装クラスはShowWindowService<TWindow, TViewModel>という形式にしています。

IShowWindowServiceインターフェースは、VMからも参照されるものとなるので、ここにView側の要素を含めたくないため、このような形となっています。

ViewModelへのサービスのインジェクション

今回のサンプルでは、MainWindowのコンストラクタでViewModelのインスタンスを作っています。
ですので、ここでMainWindowViewModelに対し、ダイアログ表示を行うためのサービスをコンストラクタを通してDIしています。

MainWindow.xaml.cs

public MainWindow()
        {
            InitializeComponent();

            // MainWindowViewModelに、コンストラクタ経由でIShowWindowServiceへの依存性を注入する。
            var showWindowService = new ShowWindowService<EditDialog, ToDoItemViewModel>()
            {
                Owner = this
            };
            this.DataContext = new MainWindowViewModel(showWindowService);
        }

サービスを用いた、ViewModelからのウィンドウ表示

ViewModelからは、インターフェース経由で別ウィンドウ表示を行います。
この際、ShowDialogメソッドの引数で、別ウィンドウ側でDataContextとして使用するオブジェクトを渡すようにしています。

MainWindowViewModel.cs

privatevoid AddItem()
        {
            // 追加要素のVMを作成する
            var newItemViewModel = new ToDoItemViewModel();
            var ret = this._showWindowService.ShowDialog(newItemViewModel);
            if (ret == true)
            {
                // ダイアログでOKが押された場合は、ToDoListに要素を追加する。this.ToDoList.Add(newItemViewModel);

                // 追加した項目を選択状態にするthis.SelectedItem = newItemViewModel;
            }
        }

今回のサンプルでの積み残し

このサンプルでは、EditDialogで「OK」「キャンセル」ボタン押下でのウィンドウを閉じる処理は、View側で直接書いています。

「OK」ボタン押下時にViewから直接ウィンドウを閉じるのではなく、ViewModel側で何らかのロジックやチェック処理を挟んでからウィンドウを閉じるようにするなら、何らかの形でViewModelからViewへの通知処理を付け加える必要がありますね。

その場合は、↓のような選択肢のいずれかでしょうか。

  • Viewの要素をInterfaceを通してVMに持たせて、IF経由でViewを操作する
  • VMでイベントを作り、そのイベントをViewから購読する
  • BlendSDKのEventTriggerとかを使ってViewに通知
  • PrismのInteractionTriggerとか、MvvmLightToolkitのMessengerなどの機構を通してVMからViewに通知

まぁ、Prismとか使ってるなら、そもそもここで書いたようなサービス経由での処理を使わずとも、ViewModelから別ウィンドウを開くような手段が用意されてるので、そっちを使った方がいいのかな。

ViewModelからViewへの通知については、最近BlendSDKのEventTriggerを使った方法がお気に入りなので、また別途サンプルを書こうと思います。


FluentWPF 0.8.0をリリースしました

$
0
0

https://github.com/sourcechord/FluentWPF/releases/tag/v0.8.0

今回の更新では、FluentWPFのプロジェクトファイル類を新しい形式のcsproj形式に変更しました。
これによって、.NET Core環境でのWPFアプリもフルサポートできるようになってます。

慣れると、新形式のcsprojは便利ですね。
f:id:minami_SC:20191104230056p:plain

こんな風に、一つのプロジェクトで複数のターゲット向けのビルドなどもできるようになります。
⇒この辺の経緯は、また別途書こうかと。

ということで、FluentWPFは.NET Core 3.0でネイティブに動作するようになりました。 WPF on .NET Core3.0なプロジェクトでFluentWPFを使用しても、ビルド時の警告が出ないようになってます。

新機能

SystemThemeクラス

Windows10 19H1より追加された、ライトテーマ(Windowsモードの設定内容)を取得するプロパティを追加しました。

SystemTheme.WindowsThemeというプロパティで、OSの色設定の「Windowsモード」に関する設定値を取得できます。   f:id:minami_SC:20191104230559g:plain

機能追加

Button要素のRevealエフェクト・カスタマイズ

ButtonのRevealエフェクトを色々カスタマイズできるようにしました。 それぞれ、以下のようなプロパティで、Revealエフェクトのボーダー幅や色などを変更できます。

プロパティ名内容
Backgroundボタンの背景色
Foregroundボタンの前景色
BorderBrushボーダー色
BorderThicknessボーダーの太さ
RevealElement.BorderOpacityボーダーの不透明度
RevealElement.MouseOverForegroundマウスオーバー時のボタン前景色
RevealElement.MouseOverBackgroundマウスオーバー時の背景色
RevealElement.MouseOverBorderOpacityマウスオーバー時のボーダーの不透明度
RevealElement.BorderRadiusボタンの角の丸み
RevealElement.PressBorderOpacityボタン押下時のボーダーの不透明度
RevealElement.PressTintBrushボタン押下時に背景色に被せる色味の調整

以下使用例
f:id:minami_SC:20191104230747g:plain

<StackPanel Orientation="Horizontal"><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"BorderBrush="Red"BorderThickness="1"fw:RevealElement.MouseOverBorderOpacity="0.5"fw:RevealElement.PressBorderOpacity="0.5"Style="{StaticResource ButtonRevealStyle}"/><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"Background="Transparent"Style="{StaticResource ButtonRevealStyle}"/><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"Style="{StaticResource ButtonAccentRevealStyle}"/><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"Background="Transparent"Style="{StaticResource ButtonAccentRevealStyle}"/><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"fw:RevealElement.MouseOverBackground="Coral"Style="{StaticResource ButtonAccentRevealStyle}"/></StackPanel><StackPanel Orientation="Horizontal"><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"Style="{StaticResource ButtonRoundRevealStyle}"/><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"BorderBrush="Red"BorderThickness="1"fw:RevealElement.MouseOverBorderOpacity="0.5"fw:RevealElement.PressBorderOpacity="0.5"Style="{StaticResource ButtonRoundRevealStyle}"/><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"Background="Transparent"Style="{StaticResource ButtonRoundRevealStyle}"/><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"Style="{StaticResource ButtonRoundAccentRevealStyle}"/><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"Background="Transparent"Style="{StaticResource ButtonRoundAccentRevealStyle}"/><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"fw:RevealElement.MouseOverBackground="Coral"Style="{StaticResource ButtonRoundAccentRevealStyle}"/></StackPanel>

角丸ボタン用のスタイル追加

今まで、RevealエフェクトをButtonに適用するために、ButtonRevealStyleButtonAccentRevealStyleというスタイルを用意していました。

今回、以下のような角が丸いボタンを作るためのスタイルを追加しました。

  • ButtonRoundRevealStyle
  • ButtonRoundAccentRevealStyle

これらのクラスを使うと角が丸いボタンを作れます。

<StackPanel Orientation="Horizontal"><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"Style="{StaticResource ButtonRoundRevealStyle}"/><Button Content="Button"HorizontalAlignment="Left"Margin="5"Width="75"Height="32"Style="{StaticResource ButtonRoundAccentRevealStyle}"/></StackPanel>

f:id:minami_SC:20191104233522g:plain

丸いボタンを作る

ちなみに、これらの角丸ボタン用のスタイルですが、ButtonのWidthとHeightを同じ値にして使用すると、↓のような丸いボタンになります。
f:id:minami_SC:20191104233953p:plain

<StackPanel Orientation="Horizontal"><Button HorizontalAlignment="Left"Margin="5"Width="32"Height="32"Style="{StaticResource ButtonRoundRevealStyle}"/><Button HorizontalAlignment="Left"Margin="5"Width="32"Height="32"Style="{StaticResource ButtonRoundAccentRevealStyle}"/></StackPanel>

で、こういう丸いボタンと、Segoe MDL2 Assetsフォントを組み合わせると、こんな風に、Windows10のGrooveミュージックアプリ風のデザインもお手軽に作れます。 こんな風にボタン並べると、Windows10のGrooveミュージックアプリ風なデザインも簡単に作れます。
f:id:minami_SC:20191104234804g:plain

<Grid fw:PointerTracker.Enabled="True"Background="#01FFFFFF"><Grid Height="70"VerticalAlignment="Bottom"HorizontalAlignment="Center"><Grid.Resources><Style TargetType="{x:Type Button}"BasedOn="{StaticResource ButtonRoundRevealStyle}"><Setter Property="Margin"Value="2" /><Setter Property="Width"Value="32" /><Setter Property="Height"Value="32" /><Setter Property="Background"Value="Transparent" /><Setter Property="FontSize"Value="20" /><Setter Property="FontFamily"Value="Segoe MDL2 Assets" /></Style></Grid.Resources><Grid.ColumnDefinitions><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions><Button Grid.Column="0"Content="&#xE8B1;"/><Button Grid.Column="1"Content="&#xE892;"/><Button Grid.Column="2"Content="&#xE768;"FontSize="28"Width="48"Height="48"fw:RevealElement.BorderOpacity="0.4"/><Button Grid.Column="3"Content="&#xE893;"/><Button Grid.Column="4"Content="&#xE72C;"/></Grid></Grid>

破壊的変更

前述したように、19H1から色設定に追加された「Windowsモード」項目の設定を扱えるようにするために、 SystemTheme.WindowsThemeというプロパティを追加しました。

このSystemThemeクラスでは、今までSystemTheme.Themeというプロパティで色設定の「アプリモード」の設定値を取得するプロパティを提供していました。
今回、WindowsThemeというプロパティを足したことで、ちょっとプロパティ名がわかりにくくなってしまったので、以下のようにプロパティ名を変更しています。

プロパティ名内容
SystemTheme.Theme⇒SystemTheme.AppTheme「アプリモード」の設定値
SystemTheme.WindowsThemeWindowsモード」の設定値

今回の更新は以上です。

ボタン系のコントロールは色々カスタマイズできるようになったけど、 まだまだWPF標準の各種コントロールでFluentDesign風なスタイルを提供できてないコントロールが多数あります。

今後の更新では、こういった各種標準コントロール類用のスタイルを追加していきたいと考えてます。

WPF用ライブラリ開発者向けの.NET Core事始め~.NET Core/.NET Framework両対応ライブラリの作成方法~

$
0
0

この記事はC# その2 Advent Calendar 201917日目の記事です。

.NET Core3.0からは、WPFやWinFormsなどのデスクトップアプリ開発もサポートされました。
WPFでのアプリ開発も、徐々に.NET Core環境に移行して行ってもいいかな、、という環境が整いつつあると感じます。

この記事では、WPF向けライブラリ作成という観点から、.NET Core時代のライブラリ作成方法を見ていこうと思います。

.NET Core環境用のWPF向けライブラリ用のプロジェクトテンプレート

VisualStudio 2019の新規プロジェクト作成用テンプレートには、以下のような項目が追加されています。
f:id:minami_SC:20191217224930p:plain

この.NET Core環境向けのWPFライブラリプロジェクトでは、プロジェクトファイルが新しい形式の.csprojファイルになっています。
新しい.csprojのファイル形式は、.NET Framework向けプロジェクトと比べて、以下のようなメリットがあります。

  • NuGetパッケージ作成が簡単
  • .net coreと.net framework両対応のライブラリを作れる

ここでは、「WPF User Control Library(.NET Core)」というテンプレートでプロジェクトを作成し、これらのメリットを順に見ていきます。

.NET Core環境用のWPFクラスライブラリプロジェクト

プロジェクトの新規作成ウィザードで、「WPF User Control Library(.NET Core)」を選び、プロジェクトを作成します。
すると、以下のようなプロジェクトが出来上がります。
f:id:minami_SC:20191217234438p:plain

今回は、ライブラリの内容は特に関係しないので、コードは編集しません。
このプロジェクトの設定を変えながら、色々試していきます。

Nugetパッケージの作成方法

.NET Core環境向けのWPFプロジェクトでは、プロジェクトのプロパティに「パッケージ」というタブが用意されています。
ここに、exe/dllのアセンブリ情報だけでなく、NuGetパッケージに設定する情報も入力できるようになっています。
f:id:minami_SC:20191217225025p:plain
また、ここで「ビルドでNuGetパッケージを生成」にチェックを入れると、ビルドする際にNuGetパッケージも一緒に作ってくれるようになります。

.NET Framework向けのライブラリを作る際は、.nuspecファイルを作ってそこにNuGet用の情報をxmlで書いていました。
プロジェクトの情報がcsprojとnuspecに分散してしまい、ちょっと煩雑だなと思うことも多かったです。

新しいcsproj形式では、この画面で一緒に記入できるのでとても簡単ですね。

そして、プロジェクトをビルドしてみると、ビルド生成物が置かれるフォルダに.nupkgファイルが出来上がります。
f:id:minami_SC:20191218002206p:plain

NuGetで公開したければ、このnupkgをnugetコマンドなどでアップロードすればOKです。

.NET Framework向けにもビルドしてみる

先ほどの手順で、簡単にNuGetパッケージを作ることができました。
ですが、このNuGetパッケージは.NET Core用のパッケージになっており、 旧来の.NET Framework向けのWPFアプリのプロジェクトからは参照することができません。

またプロジェクト設定を開いてみても、以下のように「対象のフレームワーク」が.NET Coreのみとなっており、 .NET Framework4.5などは選択肢として選ぶことができません。
f:id:minami_SC:20191217235034p:plain

csprojファイルの編集

新しいcsproj形式のプロジェクトファイルでも、ファイルをテキストとして直接編集することで、.NET 4.5向けなどに設定を変更することができます。
このライブラリのプロジェクトファイルを、テキストエディタで開いてみます。
以下のような内容となっており、TargetFrameworkという項目でnetcoreapp3.1が指定され、.NET Core3.1向けのビルド設定になってることがわかります。

<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop"><PropertyGroup><TargetFramework>netcoreapp3.1</TargetFramework><UseWPF>true</UseWPF><GeneratePackageOnBuild>true</GeneratePackageOnBuild></PropertyGroup></Project>

これを以下のように変更すると、.NET 4.5向けのビルドができるようになり、.NET4.5環境のWPFアプリでも参照できるライブラリとなります。

<TargetFramework>net45</TargetFramework>

.NET Framework向けにパッケージを作成した場合の問題点

この方法で、.NET 4.5向けに作成したライブラリは、.NET Core環境/.NET Framework環境のどちらのWPFアプリでも利用することができます。

しかし、.NET Core環境で参照した際に、以下のような警告メッセージが表示されるようになってしまいます。
f:id:minami_SC:20191217233849p:plain
f:id:minami_SC:20191217233907p:plain

一応、これでも.NET Core環境のWPFアプリで利用することはできます。
でも、どうせなら.NET Coreにちゃんと対応した形でビルドしたいですよね。

てことで、.NET Core環境向けのWPFライブラリの作り方を見ていきます。

.NET Coreと.NET Framework両対応のライブラリ作成

先ほどは、csprojファイルをテキストと開いて、TargetFrameworkという項目を編集しましたが、
TargetFrameworkという項目をTargetFrameworksという複数形の設定項目に変えると、ビルド対象として、複数のフレームワークを指定できるようになります。
f:id:minami_SC:20191217235104p:plain

csprojのTargetFramework/TargetFrameworks等の項目は、以下のページで説明されています。 https://docs.microsoft.com/ja-jp/dotnet/standard/frameworks

ビルド成果物が保存されるbinフォルダ以下には、それぞれのターゲットフレームワーク名のフォルダが出来上がります。
また、生成されたnupkgファイルをNuget Package Explorerで確認してみると、.NET4.5と.NET Core3.1それぞれのアセンブリが含まれていることが確認できます。
f:id:minami_SC:20191217233928p:plain

このようなNuGetパッケージにしておくと、パッケージ利用者側のプロジェクト構成に合わせて、適切なアセンブリが参照されるようになります。

.NET CoreでWPFが利用できる環境は整いましたが、まだしばらくの間は両方の環境が共存した状況が続くと思います。
ライブラリ作成者の観点では、「様々な環境で使えるライブラリを作りたい」と考えると思いますが、
そんな時には、このような方法で複数ターゲット向けのアセンブリを含んだライブラリを作るとよいのでは、と思います。


さいごに

以下宣伝。
WPFでFluentDesignなルック&フィールのUIを作るための、FluentWPFというライブラリを作っています。

WPFアプリでも、こんな風にアクリル効果の効いたウィンドウや各種ボタンなどのUIが作れます。
f:id:minami_SC:20171226020340g:plain:w300f:id:minami_SC:20190602171129g:plain:w500

このライブラリでも、今回の記事で紹介した方法で、.NET Coreと.NET Framework両対応なライブラリにしています。
もしよかったら、使ってみてくださいませ♪

PackageManagement+ChocolateyGetでパッケージ管理する手順

$
0
0

導入手順と、よく使いそうな操作をφ(..)メモメモ

参考リンク

GitHub - jianyunt/ChocolateyGet: ChocolateyGet provider allows to download packages from Chocolatey.org repository via OneGetPackageManagement+ChocolateyGet によるパッケージ管理 - Qiita

準備

PowerShellのコンソールを開いてまずは↓を実行

Set-ExecutionPolicy RemoteSigned -Scope Process

現在開いているコンソールでだけ、実行ポリシーを変更します。
※元からRemoteSignedなど、PowerShellの実行権限を変えてる場合は不要

導入手順

以下のコマンドでChocolateyGetのプロバイダをインストールします。

Install-PackageProvider ChocolateyGet -verbose

パッケージ管理

パッケージの検索
Find-Package -ProviderName ChocolateyGet -Name [パッケージ名]
パッケージのインストール

インストールは以下のコマンド。
管理者権限のコンソールじゃないと、インストール中にエラーとなるので注意。

Install-Package -ProviderName ChocolateyGet -Name [パッケージ名]
インストール済みパッケージの確認
Get-Package -ProviderName ChocolateyGet
インストール済みパッケージの更新

インストールのコマンドで、パッケージの更新もいけそう。
場合によっては、「-Force」オプション必要かも。
ちょっとこの辺は、まだ数こなしてないので、これで大丈夫かよくわからないです。。。

アンインストール

アンインストールは以下のコマンドで。

Get-Package [パッケージ名] -ProviderName ChocolateyGet -Verbose | Uninstall-Package -AdditionalArguments '-y --remove-dependencies' -Verbose

Uninstall-Package単体ではダメみたいで、ちょっと長めですね。

FluentWPF 0.9.0をリリースしました

$
0
0

前回の更新から、かなり間が空いてしまいました…
だいぶ久しぶりの更新となりますが、FluentWPF0.9.0をリリースしました。
今回の変更内容は以下の通り。

主な変更内容

  • ComboBox用のスタイル(ComboBoxRevealStyle )追加・・・#86
  • 不具合対応

f:id:minami_SC:20210308012611g:plain

更新が滞っている間に、プルリク(#86)を通して色々議論しながら対応していただいていたようです。
長いことあまり時間がとれず、放置状態となってしまってました。。。
(色々作り込んでくれてたのに、ほんと申し訳ない・・・)

このプルリクをベースに下記対応を加え、
一通りのComboBoxスタイル定義が出来上がったので、ここで正式リリースとしました。

  • ComboBoxのドロップダウン表示にアクリル効果追加
  • IsEditableの表示を修正
  • アクリル効果に関するStyle定義共通化などのリファクタリング

WindowsアプリのUIに関しては、WinUI3やMAUIなど色々と気になるものが多い昨今です。
WinUI3の動向もチェックしつつ、このライブラリもちょっとずつ更新していこうと思います。

FluentWPF 0.10.0をリリースしました

$
0
0

FluentWPF 0.10.0をリリースしました。
今回は、ウィンドウのアクリル効果の改善を中心に、結構手を入れています。

新機能

AcrylicWindowのアクリル効果改善

Windows10 1903以降でも、UWP風のアクリル効果を使えるように対応

FluentWPFでは、SetWindowCompositionAttributeという非公開Win32APIを使い、ウィンドウへのアクリル効果を適用しています。
しかし、Windows10 1903以降では、このAPIを使うとウィンドウ移動やリサイズ時に描画がカクつく問題がありました。 現時点でも、この問題は解決される見込みはありません(そもそも非公開APIですし・・・)
そこで、ウィンドウの移動やリサイズ中は、ぼかし効果の弱い別種表示に切り替えるようにして、この問題を回避しています。

f:id:minami_SC:20210812123954g:plain

アクリル効果の有効/無効切替

AcrylicWindow.Enabled指定でアクリル化した場合には、プログラム実行中にもアクリル効果の有効/無効を切り替えられるようにしました。

<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"xmlns:sys="clr-namespace:System;assembly=mscorlib"mc:Ignorable="d"Title="AcrylicWindow2"Height="450"Width="800"ResizeMode="CanResizeWithGrip"MaxWidth="950"MaxHeight="600"fw:AcrylicWindow.Enabled="{Binding IsChecked, ElementName=chkIsEnabled}"Icon="/Assets/Images/logo_icon.png"><Grid><CheckBox x:Name="chkIsEnabled"Content="AcrylicWindow.Enabled"HorizontalAlignment="Left"Margin="10,10,0,0"VerticalAlignment="Top"IsChecked="False"/></Grid></Window>

f:id:minami_SC:20210812124101g:plain

アクリル効果の種別手動設定・・・・AcrylicWindow.AcrylicAccentStateプロパティ

AcrylicWindow.AcrylicAccentStateというプロパティで、アクリル効果の種別を指定できるようにしました。
このプロパティで、SetWindowCompositionAttribute関数の引数に指定するパラメータを手動で指定できます。

<fw:AcrylicWindow x:Class="FluentWPFSample.Views.AcrylicWindow3"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:fw="clr-namespace:SourceChord.FluentWPF;assembly=FluentWPF"xmlns:sys="clr-namespace:System;assembly=mscorlib"xmlns:local="clr-namespace:FluentWPFSample.Views"mc:Ignorable="d"Title="AcrylicWindow3"Height="450"Width="800"ResizeMode="CanResizeWithGrip"fw:AcrylicWindow.AcrylicAccentState="BlurBehind">

(既定では「Default」という設定になっており、OSのバージョンに応じて最適な設定を使います。)

設定内容を変えると、それぞれ以下のような表示になります。 f:id:minami_SC:20210812124030g:plain

ウィンドウ最大化時の表示不具合修正

今まで、マルチディスプレイ環境にてFluentWPFでアクリル化したウィンドウを最大化すると、となりのディスプレイ領域にこんな風にぼかし効果の効いた領域がはみ出す、、という問題がありました。
今回のリリースで、この問題を修正してます。
f:id:minami_SC:20210812122904p:plain

これは、対応するのはかなり大変でした・・・
Windowsでは、ウィンドウを最大化するとHWNDレベルではディスプレイ領域外まではみ出した大きさのウィンドウになってます。
最大化表示するときには、各種UI表示用のフレームワークがウィンドウ領域外の部分はクリッピング表示することで、余計な部分が表示されないようになってます。

しかし、FluentWPFで使っているSetWindowCompositionAttribute関数を呼び出すと、このディスプレイ領域外の部分まで含めてアクリル効果がかかってしまい、この問題が起きてました。てことで、ウィンドウ最大化時のウィンドウサイズなどを色々制御することで、この問題に対応してます。

Win32APIを多用した、結構面倒な対応しているので、機会があれば今回対応した内容を別途記事にまとめようと思います。

アクリル効果付きのメッセージボックス(AcrylicMessageBox)

AcrylicMessageBoxというコントロールを追加しました。
WPF標準のMessageBoxと似たようなIFで、以下のようなStaticメソッド呼出しでアクリル効果付きのメッセージボックスを表示できます。

var result1 = AcrylicMessageBox.Show(this, "This is AcrylicMessageBox\nTest", "Title", MessageBoxButton.OK);
var result2 = AcrylicMessageBox.Show(this, "This is AcrylicMessageBox\nTest", "Title", MessageBoxButton.OKCancel);
var result3 = AcrylicMessageBox.Show(this, "This is AcrylicMessageBox\nTest", "Title", MessageBoxButton.YesNoCancel);
var result4 = AcrylicMessageBox.Show(this, "This is AcrylicMessageBox\nTest", "Title", MessageBoxButton.YesNo);

f:id:minami_SC:20210812121359p:plain

MahApps.Metroとの連携表示

FluentWPFでは、添付プロパティ設定でアクリル効果を有効化でき、MahApps.Metroなどその他のWPF向けUIフレームワークで作成したウィンドウとも共存できるような仕組みとしてました。(※下記記事参照)

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

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

ですが、MahApps.MetroとFluentWPF双方のバージョンアップに伴い、この方法では正しく連携できなくなってました。
今回AcrylicWindowなどの仕組みに色々手を入れながら、この問題も一緒に修正しています。

以下のようなコードで、MahApps.Metroで作ったウィンドウにアクリル効果を適用できます。

<mah:MetroWindow x:Class="MahAppsTest.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"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.AcrylicWindowStyle="None"BorderThickness="0"GlowBrush="Black"mc:Ignorable="d"><Grid><TextBlock Margin="5"Text="Hello World!!" /><Button Content="Button"Width="75"Height="35" /></Grid></mah:MetroWindow>

f:id:minami_SC:20210812214334p:plain

不具合修正

その他、以下のような不具合対応をしてます。

  • Fix the issue that AcrylicBrush doesn't be rendered correctly without Width/Height properties(#10)
  • Fix the issue that sometimes TextBlock doesn't follow system themes(#120)
  • Fix the issue that DisplayMemberPath doesn't work with ComboBoxRevealStyle(#123)
  • Fix the issue that app crashes when referenced AccentColors before Application.Current.MainWindow initialized(#107)

今後の予定

気付けばGitHubのスター数も1000を超えました。
たくさんの方に使ってもらえ、また多くのフィードバックもいただけるようになりました。
改めて見返してみると、なかなか感慨深いものですね。 f:id:minami_SC:20210812144428p:plain

今後の予定ですが、以下のような対応を進めようと思ってます。

  • Windows11対応
    • Win11環境でのアクリル有効化
      ※現時点では、Windows11環境ではアクリル効果が正しく反映されません。
      そのため、FluentWPF 0.10.0では、Win11環境ではアクリル効果を無効化してます。
    • Mica対応・・・Win11で追加されるMicaマテリアルに対応できないか調査
    • 各種Reveal系スタイルの改善
      各種標準コントロール用のスタイル追加や、Windows11でのFluentDesignに合わせたスタイル定義修正
  • GitHubリポジトリの整備
    • GitHub ActionsでのCI環境作成
    • ドキュメント整備(Wiki or README or GitHub Pages)
Viewing all 153 articles
Browse latest View live