こんにちは、働くC#プログラマーのさんさめです。
WPF/MVVMで開発していると、
時折発生して頭を悩ませることになるのが、
「Bindingで取得した文字と固定の文字を
組み合わせて表示したい」
というケースです。
検索した時によく出てくるのは、
Binding.StringFormatを使って、
固定の文字列と組み合わせて表示する方法です。
しかし、StringFormatを使う方法以外にも
やりようはいくつかあります。
- Runを複数置く
- コンバーターを使う
- ViewModelに専用のプロパティを増やす
本記事では、
StringFormatを使う方法も含めた
4つの方法の特徴と、どんな時におススメか
について解説します。
StringFormatを指定する
最初に解説するのは、
Binding.StringFormatプロパティを使って、
Binding文字列と固定文字列を結合する方法です。
使い方は以下のようになります。
<TextBlock Text="{Binding MethodStringFormat, StringFormat=その1 「{0}」を使う}" />
{0}という部分にBindingで得た文字列が入ります。
この時、StringFormatの意味通り書式設定をすることができます。
例えば、数値をBindingする時に
{0:0000}と記述すれば、
数値が3桁以下の場合でも
必ず4桁で表示されるようになります。
ちなみに、上記サンプルのように、
文字列の最初にいきなりBinding文字列を
使いたい場合は、一度「{}」を記述してから
{0}を置く必要があります。
数値と固定文字列の結合はStringFormatがおススメ
StringFormatの特徴から考えられる
おススメできるユースケースは、
数値と固定文字列を結合するケースです。
数値はどんな値が来るか
事前に予想できないことも多いです。
そのため、書式指定によって
あらかじめ表示方法を定めておくと、
レイアウトが崩れにくく、
アプリの見た目や分かりやすさを保つことができます。
また、StringFormatは
「その結合をしたい箇所が1か所しか無い」
という時もおススメです。
Binding記述時に
そのまま続けて書くだけで良く、
記述量も比較的少ないため、
サッと書けて、他人が見た時にも
そこにどんな文字が表示されるのが想像しやすいです。
Runを複数配置する
2つ目の方法は、Runを複数配置するという方法です。
使い方は以下のようになります。
<TextBlock>
<Run FontWeight="Bold" Text="その2 「" />
<Run Text="{Binding MethodMultiRun, Mode=OneWay}" />
<Run Foreground="Green" Text="」を使う" />
</TextBlock>
StringFormatの方法と比べると、
少し記述量が多いですね。
また、Run.TextプロパティにBindingを記述する際は、
Mode=OneWayを忘れないようにしましょう。
うっかりOneWay指定をしないまま
ゲッターのみのプロパティにBindingすると、
実行時例外を起こします。
StringFormatを使う方法との最も大きな違いは、
個別にフォントサイズや文字色などを変更できることです。
FontWeight=”Bold”で重要個所を太字にしたり、
Foreground=”Red”で強調してみたり、
といったことが個別にできるわけですね。
これはStringFormatではできないアプローチです。
より読みやすい文章を追求したい場合はRunの複数配置がおススメ
ところで、固定の文字列というのは、
実はアプリケーションユーザーにとって、
段々読まれなくなります。
なぜなら、毎回同じ文言がでるので、
そのうち形で覚えてしまうからです。
初めて触るユーザーに
説明的な意味を持たせる上では重要ですが、
必ずしも
可変な文字と同様の目立ちやすさ
である必要はないということですね。
ユーザー体験を極限まで追及する場合は、
そもそもRunではなくTextBlock自体を複数配置したり、
アイコンの使用などを検討すべきかもしれません。
でも、そこまで実装を凝るのは大変です。
そんな時、ちょっと気を利かせたい、と思った場合には
Runの複数配置がおススメです。
コンバーターを使う
3番目の方法は、
IValueConverterを実装したクラスを用意し、
Binding時に適用するという方法です。
少し事前知識が必要なため、
IValueConverterを良く知らないという方は、
【WPF】Binding入門3。Converterでデータを変換
をご覧ください。
今回は、Bindingした文字列に
接頭辞と接尾辞を付けてくれる
コンバーターを用意してみました。
public class MyStringConverter : IValueConverter
{
public string Prefix { get; set; }
public string Suffix { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return $"{Prefix}{value}{Suffix}";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
そしてxaml側では、以下のように使用します。
<Window.Resources>
<local:MyStringConverter
x:Key="MyConverter"
Prefix="その3 「"
Suffix="」を使う" />
</Window.Resources>
<StackPanel Margin="4">
<TextBlock Text="{Binding MethodConverter, Converter={StaticResource MyConverter}}" />
</StackPanel>
コンバーターを使う方法の特徴は、
なんと言っても使いまわしが効くことです。
StringFormatやRunを使う方法では、
同じルールで結合したい場合でも、
その都度Bindingする時に記述する必要がありますが、
コンバーターを使う方法では、
やることはConverter=…の部分を書くだけです。
コピペミスや修正漏れのリスクを減らすことができます。
汎用的に使いたい場合はコンバーターの使用がおススメ
コンバーターの実装の仕方にもよりますが、
結合ルールがはっきりしていて、
汎用的に使えるめどが立っている場合は、
コンバーターを作って使う方法がおススメです。
xamlをまたいで同一の結合規則を利用したい場合や、
やたら沢山文字列結合を使いたい場所がある時に、
その真価を発揮してくれることでしょう。
ViewModelに専用のプロパティを新設する
方法その4はちょっと毛色が異なり、
ViewModel側で解決してしまおうというアプローチです。
プロパティ自体が増えているので、
当然View側には普通にBindingを書くだけで良くなります。
<TextBlock Text="{Binding MethodVmProperty}" />
結合はC#側でやってしまおうという発想ですね。
ただし、この方法を採用する場合、
PropertyChangedを担うプロパティが
別な場合がほとんどだと思います。
この時、ちゃんと新設したプロパティの
PropertyChangedも呼んであげないと
変更内容がViewに反映されません。
public string AgeStr => $"{Age}歳";
public int Age
{
get => age;
set
{
if (SetProperty(ref age, value))
{
// AgeStrの変更通知を忘れないように!
OnPropertyChanged(nameof(AgeStr));
}
}
}
初心者の内は忘れがちなので注意しましょう。
また、C#側の記述量は
どうしても増えてしまいますね。
xamlが苦手な人はプロパティの新設がおススメ
ViewModelにプロパティを新設する方法の利点は、
何と言ってもxamlの習熟コストが低いことです。
xamlの難しい結合方法を知らなくとも、
C#側でゴリゴリに書いてしまえば
とりあえずは動いてしまうのです。
また、同じ結合規則が何度も出てくる場合、
xamlにその都度StringFormatなどを書くより、
プロパティを増やしてしまって使いまわした方が、
保守が圧倒的に楽になります。
これは、コンバーターを使う方法と
同様のメリットですね。
コンバーターを使う方法より事前準備が少なめなのも、
大事なポイントです。
汎用的に使いまわすようなものでもない場合は、
プロパティを増やしてしまうのが楽ちんですね。
パッと動くものをパッと作りたい。
そういう時にプロパティの新設はおススメです。
ユースケースによっておススメは結構異なる
4つの方法を解説しました。
独断でそれぞれの利点を表にしてみました。
手軽 | 使い回し | 特徴 | |
StringFormat | ◎ | × | 書式指定 |
Run | 〇 | × | 個別フォント変更 |
コンバーター | × | ◎ | 汎用性の塊 |
新プロパティ | △ | 〇 | xamlがシンプル |
こうしてみると、
どの方法にもオンリーワンの特徴があり、
「常におススメな方法は無い」
ということが分かります。
求められる仕様に合わせて、
柔軟にこれらの方法を使いこなしていくのが
WPF開発者としての腕の見せ所なのかもしれません。
色々使ってみて
自分に合う方法を模索するのも良いと思う
まとめ
まとめです。
- xamlでBindingと固定文字列を結合する方法はいくつかある
- StringFormatを指定
- Runを複数配置
- コンバーターを使う
- ViewModelに新しいプロパティを増やしてしまう
- それぞれの使い方や特徴を解説
- 求められる仕様によって最適な方法は変わる
最後までお読みいただき、ありがとうございました。
コメント