Help us understand the problem. What is going on with this article?

WPFのデータ変換

More than 5 years have passed since last update.

(これはQiitaに慣れる記事です。)

WPFいいですよねWPF。
みなさんバインディングしてますか!!!

一バインダーとしてバインディング機能の中のデータ変換について焦点を当ててみます。(WPF始めて間もない人向けだと思ってる)

WPFのデータバインディング

ViewModelとViewを関連付けるデータバインディングの主要部分は System.Windows.Data 名前空間にあります。が、C#のコードからは中のクラスを意識することはあまりないと思います。

そんなバインディングですが、バインディングソースとして存在する値を表記を変えてユーザーに伝えたい場合があります。

その1. StringFormatを使う

文字列を付加するような、複雑さを伴わない変換は手軽に実現できます。
例えば、「コレクションの要素数を表示したい」場合。
この場合、値は何らかのコレクション.Countプロパティで取得できますが、そのまま表示されてもユーザーにとっては何を表しているのか分からないでしょう。
BindingBaseクラスに定義してあるStringFormatプロパティに書式を流し込めば、いい感じにしてくれます。

<TextBlock Text="{Binding Items.Count, StringFormat={}{0} items}"/>

出力例: 16 items
{0}はstringクラスのFormatメソッドをお使いの方ならご存知の書式指定項目ですが、{}はのちに続く文字列へのエスケープ的役割を担っています。とりあえず文法を無視しそうな部分につけておけばOK(だと思ってる)。

その2. コンバーターを使う

データソースの値をこねくり回す場合の方法です。
例えば、「ファイルサイズを分かりやすく表示したい」場合。
.NETでのファイル関連はSystem.IO.FileInfoクラスあたりで取得できます。
サイズを示すLengthプロパティはlong型で、バイト数を返します。これをそのままバインディングすると、16000なんて味気ない表示になりますね。

using System.Windows.Data

namespace BindingTest.Converters
{
   class FileSizeConverter : IValueConverter
    {
        static readonly string[] Suffix = new string[] { "", "K", "M", "G", "T" };
        static readonly double Unit = 1024;

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (!(value is long)) throw new ArgumentException("long型じゃないよ。", "value");
            double size = (double)((long)value);

            int i;
            for (i = 0; i < Suffix.Length - 1; i++)
            {
                if (size < Unit) break;
                size /= Unit;
            }

            return string.Format("{0:" + (i == 0 ? "0" : "0.0") + "} {1}B", size, Suffix[i]);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

    }
}

出力例: 15.6 KB
一気に複雑になりましたが、

  • System.Windows.Data内のIValueConverterインターフェースを実装するクラスを作ります。
  • Convertメソッドでデータソース->表示データ
  • ConvertBackメソッドで表示データ->データソースへ変換を行います。
  • 両メソッドとも、引数valueはobject型なので、型判定をして適切な型にキャストしてやります。
  • それぞれ返り値もobject型なので、違う型への変換も可能です。

このクラスでは後者のメソッドは使わないため、バインディング先でMode=TwoWayに設定されるなどして呼ばれた際には例外を投げるようにしてあります。
XAML内で利用する時は、

<Window xmlns:c="clr-namespace:BindingTest.Converters">
    <!-- ViewModel -->
    <Window.Resources>
        <c:FileSizeConverter x:Key="FileSizeConverter"/>
    </Window.Resources>
    <TextBlock Text="{Binding Length, Converter={StaticResource FileSizeConverter}}"/>
</Window>

という感じで、(だいぶ端折った)
コンバーターを利用する際には定義した要素のx:Key属性で指定した値を指定します。

以上、Qiitaに慣れるためのデータソース変換記事でした。
これらを駆使したデータ変換で良いWPFライフを!

System.Windows.Controls.BooleanToVisibilityConverterのように組み込みで用意されているコンバーターもありますので一度調べてみることをおすすめします。

参考

http://msdn.microsoft.com/ja-jp/library/system.windows.data(v=vs.110).aspx
https://twitter.com/atst1996/status/527463457398853634

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away