スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: スポンサー広告

異なる型同士でバインディングさせたい時もある。

UI系のコントロールが持つBackgroundプロパティは、背景色を示すプロパティではあるが、その型は、Color構造体ではなく、Brushというクラスである。
これは、単純なColor構造体では、グラデーションのかかった背景色なんかが実装できない為だろう。
XAML上では、Colorの値を指定すれば、裏でTypeConverterが働いて、Brushクラスのインスタンスに変換してくれる。しかし、DataContext側にColor型のプロパティを持たせて、それとデータバインディングをしようとしても、変換はしてくれない。こんなときに使うのが、コンバータクラス(Converter)だ。
コンバータ(クラス)は、System.Windows.Data.IValueConverterインターフェイスを実装するクラスの事。ある型から別の型に変換するためのクラス。今回だけでは説明しないけど、よく実装されるのが、

bool→Visibility
decimal?←→string

等々。今回は、Color←→Brushとするコンバータを実装する。
using System;
using System.Windows.Data;
using System.Windows.Media;

namespace TawamureDays.Converters {

/// <summary>
/// Color構造体から、Brushクラスインスタンスへ変換するコンバータ。
/// </summary>
[ValueConversion(typeof(Color), typeof(SolidColorBrush))]
public sealed class ColorToSolidBrushConverter : IValueConverter {

#region IValueConverter メンバ

/// <summary>
/// 値を変換します。
/// </summary>
/// <param name="value">バインディング ソースによって生成された値。</param>
/// <param name="targetType">バインディング ターゲット プロパティの型。</param>
/// <param name="parameter">使用するコンバーター パラメーター</param>
/// <param name="culture">コンバーターで使用するカルチャ。</param>
/// <returns>変換された値</returns>
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture) {

if (value == null) {
return new SolidColorBrush(Colors.Transparent);
}

try {
var color = (Color)value;
return new SolidColorBrush(color);

} catch {
return new SolidColorBrush(Colors.Transparent);
}
}

/// <summary>
/// 値を変換します。(未実装)
/// </summary>
/// <param name="value">バインディング ターゲットによって生成される値。</param>
/// <param name="targetType">変換後の型。</param>
/// <param name="parameter">使用するコンバーター パラメーター</param>
/// <param name="culture">コンバーターで使用するカルチャ。</param>
/// <returns>変換された値</returns>
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture) {
//何もしない
var brush = value as SolidColorBrush;

if (brush != null) {
return brush.Color;
}

return Colors.Transparent;
}

#endregion
}
}

ValueConversion属性は、設定しなくても動作する。
Convertメソッド:ソース→ターゲット
ConvertBackメソッド:ソース←ターゲット
でデータバインディングから呼び出される。
実装例:
<Window x:Class="TawamureDays.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tw="http://schemas.tawamuredays.jp/wpf/gui"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<tw:ColorToSolidBrushConverter x:Key="ColorToSolidBrushConverter"/>
</Window.Resources>
<Grid Background="{Binding BackColor, Converter={StaticResource ColorToSolidBrushConverter}}">
</Grid>
</Window>

ColorToSolidBrushConverterクラスインスタンスをWindowのリソースとして登録している。キー名は、クラス名を使っている。別になんでもいいけど、そのほうがわかりやすい。コードビハインドは↓のようになる。

/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window {

#region コンストラクタ

/// <summary>
/// コンストラクタ
/// </summary>
public MainWindow() {
InitializeComponent();
this.DataContext = this;
this.BackColor = Colors.Tomato;

return;
}

#endregion

#region プロパティ

/// <summary>
/// 背景色を取得|設定します。
/// </summary>
public Color BackColor {
get; set;
}

#endregion
}

MVVMパターンであれば、VMクラスのプロパティとして、BackColorを実装することになる。
実行すると↓のような感じになる。
20120903_1

ん。たしかにトマト色だな。
ConvertBackメソッドも実装しているので、ターゲット側で変更された場合も、その値がソース側に送られる事になる。
ただし、バインディングのモードが、「TwoWay」や「OneWayToSource」の場合に限るけど。
ConvertBackメソッドを実装できたのは、今回の型が可逆的な関係にあるからで、常にそうとは限らない。
例えば、リスト→リストのアイテム数のような変換では、リストのアイテム数(int)からその具体的な内容はわからない。
こういうときは、ConvertBackメソッドは実装できないので、

/// <summary>
/// 値を変換します。(未実装)
/// </summary>
/// <param name="value">バインディング ターゲットによって生成される値。</param>
/// <param name="targetType">変換後の型。</param>
/// <param name="parameter">使用するコンバーター パラメーター</param>
/// <param name="culture">コンバーターで使用するカルチャ。</param>
/// <returns>変換された値</returns>
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture) {
//何もしない
return Binding.DoNothing;
}
や、
/// <summary>
/// 値を変換します。(未実装)
/// </summary>
/// <param name="value">バインディング ターゲットによって生成される値。</param>
/// <param name="targetType">変換後の型。</param>
/// <param name="parameter">使用するコンバーター パラメーター</param>
/// <param name="culture">コンバーターで使用するカルチャ。</param>
/// <returns>変換された値</returns>
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
のようにする。前者は何も発生しない。後者は例外が発生する。特にエラーでなくても良いときは前者かな。
Converterは便利で、仕事でも色々作った。
(追記)
変換する度にSolidColorBrushのインスタンスを作っていると、インスタンス数がとんでもない事になったりするので、staticなDictionary<Color, Brush>型にでもキャッシュするほうがパフォーマンスにも良い。それと、SolidColorBrushは、Freezableなので、Freeseメソッドを実行しておくと、更にパフォーマンスに良い。
あと、コンバータクラスは、別のアセンブリ(*.dll)に実装して、
「http://schemas.tawamuredays.jp/wpf/gui」というURLで参照できるようにしてある。
アセンブリのPropertyInfo.cs内で、以下のように宣言する。

[assembly: System.Windows.Markup.XmlnsDefinition("http://schemas.tawamuredays.jp/wpf/gui",
"TawamureDays.Converters")]
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


サイドバー背後固定表示サンプル

当ブログに書かれたソースコードは流用自由です。

バグ、スペルミス等はありうる事です。

ご利用の際は自己責任でお願いしますm(_ _)m

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。