MahApps.Metro 2.xへの移行作業

この記事では、スクリーンキャプチャツールBurageSnapにおけるMahApps.Metro 1.3.0から2.4.3への移行作業を紹介する。BurageSnapでは以下の小さなフットプリントを実現するために、MahApps.Metroを利用している。

テーマの修正

最初にテーマの設定を公式ドキュメントのMigration to v2.0に従って変更した。

Old New

スタイルの修正

それから、以下のMetroWindowのスタイル設定における4つのエラーを修正する必要があった。2.xのMetroWindowはこれらのプロパティを持っていない。

<Style x:Key="WindowStyle" TargetType="mah:MetroWindow">
...
    <Setter Property="TitlebarHeight" Value="24"/>
    <Setter Property="TitleCaps" Value="False"/>
    <Setter Property="WindowMinButtonStyle" Value="{StaticResource WindowButtonStyle}"/>
    <Setter Property="WindowCloseButtonStyle" Value="{StaticResource WindowButtonStyle}"/>
...

ウィンドウタイトル

TitlebarHeightは単純にTitleBarHeightに置き換えられた。TitleCapsTitleCharacterCasingに置き換えられたが、値はCharcterCasing 型になっている。これらの設定を以下のように修正した。

<Setter Property="TitleBarHeight"Value="24">
<Setter Property="TitleCharacterCasing" Value="Normal"/>

ウィンドウボタン

WindowMinButtonStyleWindowCloseButtonStyleのスタイルプロパティは、最小化ボタンと閉じるボタンを小さくするために使ってたが2.xで削除された。

代わりに、MetroWindowの内側のWindowButtonCommandsが対応するプロパティを持っている。 Lightテーマの場合は、それぞれLightMinButtonStyleLightCloseButtonStyleである。別のスタイルの内側のスタイルを定義する際には、以下のようにStyle.Resourcesを使用する。

ボタンのラベル

デフォルトのスタイルではボタンのラベルが大文字化と太字化されるが、それを無効化する以下のButtonStyleでもエラーが発生した。MetroButtonスタイルとButtonHelperクラスは2.xには存在しない。

<Style x:Key="ButtonStyle" TargetType="Button" BasedOn="{StaticResource MetroButton}">
    <Setter Property="mah:ButtonHelper.PreserveTextCase" Value="True"/>
    <Setter Property="FontWeight" Value="Normal"/>
</Style>

これらはそれぞれMahApps.Styles.ButtonControlsHelperに置き換えられた。ただしControlsHelperPreserveTextCaseではなくContentCharacterCasingを持つ。上のエラーは以下のように修正した。

次は

MahApps.Metroの移行作業はこれで終わりである。今度はPrismを6.2から8.0に移行させる必要がある。MahApps.Metro 2.xは8.0より古いPrismと互換性がない。2.xが依存するXamlBehaviors.WPFと、古いPrismが依存するWindows.Interactivityが共存できないからだ。この移行手順は別の記事で紹介する。

UnityアプリケーションをWindowsアプリケーションから制御する

以下のようなWindowsアプリケーションから、UnityアプリケーションをNamedPipeを介して制御する方法を紹介する。なおソースコード全体はGitHubのリポジトリに置いてある。

"UnityアプリケーションをWindowsアプリケーションから制御する" の続きを読む

C#でロックフリーなメモリープールを自作する

基本的にシングルスレッドでしか使わないライブラリを、速度を落とさずにスレッドセーフにするために、ロックフリーなメモリープールを自作した話を紹介する。この記事はC# その2 Advent Calendar 2020の18日目の記事である。

"C#でロックフリーなメモリープールを自作する" の続きを読む

[Unity] Physics.OverlapCapsuleの使い方

Capsule and Cube Collider

このようにCapsule Colliderに重なってる2つのColliderを取得したいときは、Physics.OverlapCapsuleを使うとよい。このメソッドにCapsule Colliderの位置と大きさを与えると、重なっているColliderがすべて返る。RigidbodyをKinematic TriggerにしてOnTriggerEnterをハンドルして取得することもできるが、こちらのほうが手軽である。

"[Unity] Physics.OverlapCapsuleの使い方" の続きを読む

厳格なJSONパーザーの作り方

僕の作ったJSONパーザーのDynaJsonはとても厳格にできている。RFC 8259に準拠しているものはすべて受理するし、そうでないものは二つの例外を除きすべて受理しない。

受理する例外は、ケツカンマと02-02のような0で始まる数字である。前者を受理するのは実用性のためであり、後者を受理するのはDynamicJsonとの互換性のためである。

JSONの文法はとても単純だが、不用意にパーザーを実装するとRFCに準拠したJSONを受理しなかったり、非準拠のものをエラーにできなかったりする。パーザーを実装する際の地雷ポイントはParsing JSON is a Minefieldによくまとまっている。

"厳格なJSONパーザーの作り方" の続きを読む

Docker for WindowsでWindowsの任意のフォルダをコンテナにマウントする

普通にdockerを使っている場合は、docker run -v /source:/destinationとするとコンテナホストの/sourceをコンテナの/destinationにマウントして、コンテナからアクセスできる。

では、Docker for WindowsでC:\Sourceをコンテナの/destinationにマウントしたいときはどうするか。VMホストのC:\Sourceをコンテナの中に直接マウントすることは当然できない。

まず最初に、 docker-machineでVMを作成するときにC:\Sourceを共有フォルダとして設定する。共有フォルダはVirtualBox deriverの--virtualbox-share-folderオプションで以下のように指定できる。

docker-machine create --driver virtualbox --virtualbox-share-folder=C:\Source:Source

"Docker for WindowsでWindowsの任意のフォルダをコンテナにマウントする" の続きを読む