PG日誌

受託系 PG が C# の事を書いています

2017年にWPFでデスクトップアプリを新規作成する際に考慮すること

2017年4月現在、新規にWindows上で動作するクライアントアプリのベターな選択は何か?デスクトップアプリケーションを選んだ場合、作成する時に考慮しなくてはいけない事や、一番最初にやっておいた方がいい設定などを、業務アプリ屋目線で考察をしてみました。

デスクトップアプリを取り巻く環境

マイクロソフトはWindows10をリリースして以降、WPFのデスクトップアプリを完全に切り捨てに来ています。ただ、以下のOSのシェアの表の通り、半数は依然としてWindows7という状況にあってUWPをマイクロソフトがいくらゴリ押ししてるといっても、その動作環境たるWindows10が少数派の現状、どの事務用PC上でも動作するクライアントというものは事実上"デスクトップアプリ"一択であると言えます。従って、デスクトップアプリを作成し、余力があればUWPでもアプリを展開するという姿勢を取らざるを得ません。

2017年4月現在、WinのOSシェア内訳は以下の通り。

OS 割合
Windows 7 ≒ 50%
Windows 8.x 26%
Windows 10 7%

そして、企業内のWin7の新規調達はそろそろ無くなくなりつつあり、Win10に徐々に移り変わっているという状況です。つまり、2017年から、Win7のサポートが完全に切れる2020年まで(+α)は過渡期と言えそうです。

Windows7と8.x、10で見た目が全然違う問題をどうにかする

では、実際にWindonws7とそれ以降のOS上で動作するデスクトップアプリケーションを作成しようとなった場合、標準コントロールの外観がかなり違い、デザイン上のサポートを何らかの形で行う必要があると思います。具体的な違いは、

  • Win7はAero Glass系統で半透明のウインドウフレーム、立体的なボタン、緩やかなグラデーション
  • Win8以降はいわゆるフラットデザイン系

となり、主要な対応方針は

  1. 立体/フラット、両方のデザインを、違和感なく両立させる。
  2. 頑張って独自のデザインテンプレートを開発する
  3. 3rd製ライブラリでスタイルを統一する(MahApps, Modern UI)
  4. WPFの設定でどうにかする

などが挙がると思います。ただ、これから消えていくWin7に過剰に投資する事になる前2つはできれば選択したくないですし、企業がリリースするアプリが3rd製オープンソースのUIをそのまま拝借したデザインというのも少し違うかなと思います。

従って、最後のWPFの設定でどうにかできないかを割と真面目に検討したいと思います。なるべく頑張らずに低コストで妥協する方法を探したいと思います。*1

方針として「Windows7で、フラットデザイン風の表示されるようにする」方法で課題の解決を図ることにします。そうすることで少なくともウインドウフレーム以外の中身は、全OS共通でフラットデザインで表示されるようになるからです。


前置きが長くなりましたが、早速設定の話に入りたいと思います。まず、アプリの参照へ以下アセンブリを追加し、追加後に、"ローカルコピー"を"true"に設定します。

PresentationFramework.AeroLite

また、App.xamlを以下の通り編集します。

<Application x:Class="WpfAppDesign.App" ...{省略}...>
  <Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
         <ResourceDictionary
              Source="/PresentationFramework.AeroLite;component/themes/aerolite.normalcolor.xaml" />
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Application.Resources>
</Application>

これで、Win7側は、特に何もせずに配置したコントロールがすべてフラットデザイン風の見た目に変更されます。

適用前のWin7上のコントロールの表示は以下の通り。

f:id:Takachan:20170701173052p:plain

適用後の表示は以下の通りとなります。

f:id:Takachan:20170701173125p:plain

参考までにWin8で上記設定済みをアプリを起動したときの見た目です。

f:id:Takachan:20170701173152p:plain

Win10では以下の通り。

f:id:Takachan:20170701173206p:plain

デフォルトのスタイルを踏襲する

上記手順で、コントロールの外観が、フラットデザイン風に変更されましたが、XAML上でStyleの定義を追加すると、表示が元に戻ってしまいます。なので、スタイルを定義する際は、スタイル定義毎に、BaseOnプロパティの指定を行います。

例えば、TreeViewへスタイルを定義する場合以下のようになります。

<TreeView>
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Childs}">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Text}"/>
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>

    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}" 
               BasedOn="{StaticResource {x:Type TreeViewItem}}"> <!-- ★この部分 -->
            <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
        </Style>
    </TreeView.ItemContainerStyle>

BaseOnへ標準コントロールの型を指定しています。

BasedOn=“{StaticResource {x:Type TreeViewItem}}”

これで、デザインが独自のスタイル定義によって崩れることを防止できます。

メッセージボックスの見た目がおかしい問題

これも、Win7以前の環境固有の問題ですが、WPFのデスクトップアプリで、メッセージボックスを表示すると、AeroGlassが適用されていないクラシックテーマのような表示になってしまします。これを防止するために、WPF アプリへ、マニフェストを用いた視覚スタイルの適用を行います。

まず、WPFアプリケーションへ、「アプリケーションマニフェスト」を追加します。

プロジェクトエクスプローラ上のプロジェクトから「追加」> 新しい項目 > アプリケーション マニフェスト ファイル

を選択し、デフォルトの"app.manifest"のままファイルを追加します。次に、マニフェストファイルを開き、コメントアウトされている以下の項目をコメントインします。

<!-- Windows のコモン コントロールとダイアログのテーマを有効にします (Windows XP 以降) -->
<!-- この部分のコメントアウトを外す
<dependency>
  <dependentAssembly>
    <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        processorArchitecture="*"
        publicKeyToken="6595b64144ccf1df"
        language="*"
      />
  </dependentAssembly>
</dependency>
-->

その後、MessageBox.Show(…)を呼び出すと、Winodws7上で視覚スタイルが適用されます。(メインコントロールはフラットデザインなのに、メッセージボックスはAero Glassになってしまいますが、OpenFileDialogなどのダイアログ系は、すべてそうなるのでまぁ、、、諦めましょう。

適用前のWin7でのメッセージボックスの表示の見た目は以下の通り。

f:id:Takachan:20170701173304p:plain

適用後は以下になります。

f:id:Takachan:20170701173318p:plain

以上で頑張らないでWin7 - 8.x,10の見た目がある程度統一できたかと思います。

*1:ちなみに以降、圧倒的少数派のモバイル/タブレットWin端末と、無かった事にされた、Windows8は、ほとんど無視して話を進めています。