【WPF】UIがはみ出るときだけサイズ縮小したい【XAML】

Pocket

小ネタです。

もくじ

  1. やりたいこと: UIサイズはそのまま or 縮小
  2. Viewboxをそのまま使うとダメ
  3. IMultiValueConverterMultiBindingでサイズチェック
  4. まとめ

1. やりたいこと: UIサイズはそのまま or 縮小

本記事では次の条件を満たすようUIを表示することを考えます。

  • UIの親要素がサイズ不変
  • UIの子要素がサイズ可変
  • 子要素を見切れさせないように表示したい
  • 拡大表示はなるべく使わない

この条件が当てはまるユースケース例はこんな感じ。

  • ボタンに表示しているテキストを言語に応じて切り替えたい。
  • ただし、ボタン自体のサイズは変えたくない。
  • ボタンに表示しているテキストは見切れないで欲しい。

この要望に対応すべく、次のような挙動を実現したいです。

  • やりたいこと1: テキストが短く、表示幅におさまる→サイズそのまま
  • やりたいこと2: テキストが長く、表示幅を飛び出す→縮小して納める

実装は下のほうで示しますが、
想定しているボタンとしては下記3種類を考えます。

  • 上: (デフォルト)サイズ修正なし
  • 中: (ちょっと違う)つねに拡大/縮小
  • 下: (望ましい)必要なときだけ縮小

テキストが短い場合、上と下が正しい表示です。

テキストが長い場合、中と下が正しい表示になっています。

2. Viewboxをそのまま使うとダメ

WPFの標準機能として、決まったエリアからはみ出さずUIを表示するにはViewboxを使ってStretchプロパティをUniformにすればいいんですが、これだと

  • やりたいこと1: テキストが短く、表示幅におさまる→サイズそのまま

がクリアできず、テキストが短いときは文字が拡大されてしまいます。
上で示した画像で言うと「中」の状態がコレです。

試すと分かりますが、拡大/縮小が多用されたUIはガチャガチャ感が物凄いです。
もう一工夫してこの問題をどうにかしよう、というのが本記事の狙いです。

3. IMultiValueConverterMultiBindingでサイズチェック

要件に応えるにはViewboxStretchをサイズに応じて切り替えればいいです。
つまり、以下2つのサイズを比較する、というのが基本の処理になります。

  • 子要素 = Viewboxの中身UIの幅、高さ
  • 親要素 = 全体を囲っている表示エリアの幅、高さ

多数のパラメータからStretch値を決める必要があるので、
ここではIMultiValueConverterを実装して比較処理を実装します。
やや細かいですが、実際には各サイズだけでなくPaddingも考慮します。

コードにある通り、サイズの比較結果に応じてStretchの値を切り替えています。

  • 子要素が大きい場合→縮小しないと収まらないのでStretch.Uniform
  • それ以外の場合→サイズそのままでよいためStretch.None

このコンバーターを使うXAML側はMultiBindingを使い、
実際の各要素の幅、高さとPaddingを渡します。
以下のXAMLでは比較として3つのButtonを載せており、
3つ目のButtonが目的の挙動を実現しています。

4. まとめ

やり方が分かってればコンバータとTemplateを一回実装しておくだけなので、
「まあこんなもんか」という感じでした。
最善手ではない気もしてるので、ご意見等ありましたらコメントお願いします。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です