ページ

2011年10月30日日曜日

◆WPF FirstBinding

[WPF]レイアウトに飽きてきたのでバインディングしてみる

サンプルは基本的に上記サイトからそのまま引用させてもらっている。

<XAML>

<Window x:Class="DockPanel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>

<Label Content="値:" Grid.Row="0" Grid.Column="0" />
<Label Name="valueLabel" Content="ここに値が来ます" Grid.Row="0" Grid.Column="1" />
<Label Content="概要:" Grid.Row="1" Grid.Column="0" />
<Label Name="descriptionLabel" Content="ここに概要が来ます" Grid.Row="1" Grid.Column="1" />
<StackPanel Grid.Row="2" Grid.Column="1" Orientation="Horizontal" >
<Button Name="incrButton" Content="インクリメント" Margin="2" Click="incrButton_Click" />
<Button Name="decrButton" Content="デクリメント" Margin="2" Click="decrButton_Click" />
<Button Name="dumpButton" Content="Dump" Margin="2" Click="dumpButton_Click" />
</StackPanel>

</Grid>
</Window>

<ソース>


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DockPanel
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
Counter _counter;
BindingExpressionBase _valueBindingExpression;

public MainWindow()
{
InitializeComponent();

//カウンタを作る
_counter = new Counter(){Description="サンプルカウンター"};
InitializeBinding();
}

private void InitializeBinding()
{
Binding valueBinding = new Binding("Value");
_valueBindingExpression = BindingOperations.SetBinding(
valueLabel, Label.ContentProperty, valueBinding);

Binding descriptionBinding = new Binding("Description");
BindingOperations.SetBinding(
descriptionLabel, Label.ContentProperty, descriptionBinding);

// カウンタをDataContextに!
this.DataContext = _counter;
}

class Counter
{
public int Value { get; private set; }
public string Description { get; set; }

public void Incr()
{
Value++;
}
public void Decr()
{
Value--;
}
}

private void incrButton_Click(object sender, RoutedEventArgs e)
{
_counter.Incr();
_valueBindingExpression.UpdateTarget();

}

private void decrButton_Click(object sender, RoutedEventArgs e)
{
_counter.Decr();
_valueBindingExpression.UpdateTarget();

}

private void dumpButton_Click(object sender, RoutedEventArgs e)
{
// カウンタの中身を確認
MessageBox.Show(string.Format("{0}: {1}", _counter.Value, _counter.Description));
}
}
}

バインディングの構文
image


データソースとしてここでは、DataContextに指定したCounterオブジェクトを使用している。
そのDataContextのプロパティ名でBindingオブジェクトを作ってSetBindingするというパターンのようだ。


ソース値の変更を反映するには、値を変更したタイミングでUpdateTargetメソッドを呼んであげる。


Updateを自動的に行うにはデータソースのクラスに
INotifyPropertyChangedインタフェースを実装する。


このインタフェースは以下のイベントの実装を要求する。
event PropertyChangedEventHandler PropertyChanged


イベントを追加したCounterクラスを以下に引用する。

        class Counter:INotifyPropertyChanged
{
private int value;
public int Value
{
get { return value; }
set
{
this.value = value;
OnPropertyChanged("Value");
}
}

private string description;
public string Description
{
get { return description; }
set
{
this.description = value;
OnPropertyChanged("Description");
}
}

public void Incr()
{
Value++;
}
public void Decr()
{
Value--;
}

public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}

プロパティが沢山あったら書くのが面倒くさそう。
ほとんどが定型的な処理なので何かしらVSのサポートがあったもよさそうなものだが・・・。
(WPFが浸透して行かない理由の1ではなかろうか。)


個人的には文字列指定の多用も好きになれない。(リフレクションでゴネゴネするらしいが)

0 件のコメント:

コメントを投稿

私が最近チェックした記事