SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

UWPアプリ開発の最前線

急速に進化するUWPアプリのUI
~Windows 10 1809の新コントロール/DataGrid/旧バージョンへのバックポート

UWPアプリ開発の最前線 第9回

1703向けアプリで1809の最新機能を使う

 それでは実際にバックポートしていきましょう。DataGridも使いたいので、プロジェクトのターゲットの最小バージョンは1703(15063)にします。1809の最新機能を使いたいので、ターゲットの最大バージョンは1809(17763)にします。

 まず、ページのXAMLの先頭に、Windows UI Libraryの名前空間を追加しておきます(次のコード)。

Windows UI Libraryの名前空間を追加する
<Page
  ……省略……
  mc:Ignorable="d"
  xmlns:mux="using:Microsoft.UI.Xaml.Controls"
  >

1809のメニューバー

 先ほど紹介したメニューバーのXAMLをコピー&ペーストし、MenuBarタグとMenuBarItemタグに名前空間の接頭辞mux:を追加します。その下のMenuFlyoutSubItemタグやMenuFlyoutItemタグなどは、Windows SDKのコントロールをそのまま使います(接頭辞mux:を付けません)。

 すると、キーボードアクセラレータの定義がエラーになってしまいます。1703ではサポートされていないので、使えないのです。また、最小バージョンを1607に下げると、メニュー項目のアイコンもサポートされなくなります。前述したように、残念ながらOSに依存する機能などでは対応していない部分もあるのです。

 1703ではサポートされていないキーボードアクセラレータを削ると、XAMLは次のコードのようになります(前と同じく、「Plain Text Document」メニューと「Save」メニューに関連する部分のみ抜粋)。

メニューバーのXAML(1703向けにバックポート)
<mux:MenuBar Background="AliceBlue" >
  <mux:MenuBarItem Title="File" AccessKey="F">
    <MenuFlyoutSubItem Text="New" AccessKey="N">
      <MenuFlyoutItem Text="Plain Text Document" AccessKey="P"
                      Command="{x:Bind _menuCommand}"
                      CommandParameter="Plain Text Document" />
      <!-- ……省略…… -->
    </MenuFlyoutSubItem>
    <!-- ……省略…… -->
    <MenuFlyoutItem x:Name="MenuSave" Text="Save" AccessKey="S" Icon="Save"
                    Command="{x:Bind _menuCommand}"
                    CommandParameter="Save" />
    <MenuFlyoutSeparator />
    <!-- ……省略…… -->
  </mux:MenuBarItem>
  <!-- ……省略…… -->
</mux:MenuBar>

 これで、1703でも次の画像のようにメニューバーが表示できました。ただし、キーボードアクセラレータは付いていません。

メニューバーを展開した様子
バックポートしたメニューバー(Windows 10 1703上で実行)

 最近のWindows 10で実行したときにはキーボードアクセラレータを出したいというときは、バージョンによって切り分けることになります。連載第1回で紹介した条件付きXAMLで可能なはずなのですが、上手く行きませんでした。そこで、ページのInitializeComponentメソッド呼び出しの後に、次のコードのSetupShortcutKeyメソッドの呼び出しを追加してやります。キーボードアクセラレータは1803からメニューに表示されるようになったので、それ以上のバージョンのときだけキーボードアクセラレータを付けるコードを実行します。

対応しているWindows 10ではキーボードアクセラレータを出す
using TKH = Microsoft.Toolkit.Uwp.Helpers;

// ……省略……

private readonly ushort _osBuild = TKH.SystemInformation.OperatingSystemVersion.Build;
private const ushort Ver1803 = 17134;

private void SetupShortcutKey()
{
  if (_osBuild >= Ver1803)
  {
    this.MenuSave.KeyboardAccelerators.Add(new KeyboardAccelerator
    { Modifiers = VirtualKeyModifiers.Control, Key = VirtualKey.S });
    this.MenuCopy.KeyboardAccelerators.Add(new KeyboardAccelerator
    { Modifiers = VirtualKeyModifiers.Control, Key = VirtualKey.C });
    this.MenuPaste.KeyboardAccelerators.Add(new KeyboardAccelerator
    { Modifiers = VirtualKeyModifiers.Control, Key = VirtualKey.V });
  }
}

 上のコードでは、Windows Community Toolkitを使ってWindows 10のビルド番号を取得しています。

 これで、次の画像のように、上位バージョンで実行したときはキーボードアクセラレータも動作します。

メニューバーを展開した様子
バックポートしたメニューバー(Windows 10 1803上で実行)

バージョンアダプティブなコーディング

 Microsoftのドキュメントには、ApiInformationクラスを使ってAPIの有無を調べるようにと書いてあります。上の例では、MenuFlyoutItemクラスがKeyboardAcceleratorsプロパティを持っているかどうかを調べて、それによって処理を切り分けるべきだ、となります。

 ところが、APIが存在することと、それが期待通りに機能するかどうかは別の話です。KeyboardAcceleratorsプロパティは1709(16299)から存在しますが、メニュー項目に自動的にショートカットキーが表示されるのは、1803からなのです。それで、ここではWindows 10のバージョンを見て処理を切り替えるというコードを書きました。

1809のドロップダウン系ボタン

 これはコピー&ペーストしたら、ドロップダウン系ボタンのタグとそれぞれのフライアウトのタグに接頭辞mux:を付けます。

 やはり非互換性によるエラーがいくつか出ますので、それを修正します。MenuFlyoutコントロールのPlacementプロパティの設定値や、フライアウト内に置いたGridViewコントロールのSelectedIndexプロパティ、同じくフライアウト内に置いたListViewコントロールなどがエラーになりました(最後のListViewコントロールが置けない問題は、Windows UI Library自体の不具合だと思われます)。

SplitButtonのドロップダウンを展開した様子
バックポートしたSplitButtonの「v」部分をクリックしたところ(Windows 10 1703上で実行)

 MenuFlyoutコントロールのPlacementプロパティで左端合わせ/右端合わせが出来なかったので、ドロップダウンの出る位置が前とは違っています。

RichEditBoxのコンテキストメニュー

 RichEditBoxコントロールはWindows UI Libraryで提供されていませんので、標準SDKのものをそのまま使うしかありません。次の画像のように、表示されるコンテキストメニューが違います。

以前のWindows10でRichEditBoxのコンテキストメニューを出した様子
RichEditBoxの古いコンテキストメニュー(Windows 10 1703上で実行)

 この古いタイプのコンテキストメニューには、ボタンを追加したりできません。カスタマイズするコードは、キーボードアクセラレータと同じくバージョンアダプティブに修正する必要があります(次のコード)。

対応しているWindows 10ではRichEditBoxのコンテキストメニューをカスタマイズする
private const ushort Ver1809 = 17763;

// ……省略……

if (_osBuild >= Ver1809)
{
  this.richEdit.Loaded += (s, e)
    => this.richEdit.ContextFlyout.Opening += ContextFlyout_Opening;
  this.richEdit.Unloaded += (s, e)
    => this.richEdit.ContextFlyout.Opening -= ContextFlyout_Opening;

  void ContextFlyout_Opening(object sender, object e)
  {
    // ……省略(前と同じ)……
  }
}

DataGrid

 Windows Community ToolkitのDataGridコントロール(バージョン4.0のもの)はWindows 10 1703で動作します。今回はバージョン5.0の機能を使っていなかったので、そのままコピー&ペーストするだけでちゃんと動きました(次の画像)。

DataGridで列の入れ替えやソートや編集を行っている様子
Windows Community ToolkitのDataGridコントロール(Windows 10 1703上で実行)

次のページ
まとめ

関連リンク

この記事は参考になりましたか?

UWPアプリ開発の最前線連載記事一覧

もっと読む

この記事の著者

biac(ばいあっく)

HONDA R&Dで自動車の設計をやっていた機械屋さんが、技術の進化スピードに魅かれてプログラマーに。以来30年ほど、より良いコードをどうやったら作れるか、模索の人生。わんくま同盟の勉強会(名古屋)で、よく喋ってたりする。2014/10~2019/6 Microsoft MVP (Windows Devel...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/11188 2018/11/20 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー