2013年3月3日日曜日

DataBinding(その3)

DataConverterについて
データをBindする途中でデータを変換する機能 

具体的には、「System.Windows.Data.IValueConverter」実装クラスを
Bindingインスタンスの「Converter」プロパティに指定することで実現する。
「IValueConverter」インターフェースのコードは以下の通り

   1: [System.Windows.Data.IValueConverter]::System.Object Convert(System.Object, System.Type, System.Object, System.Globalization.CultureInfo)
   2: [System.Windows.Data.IValueConverter]::System.Object ConvertBack(System.Object, System.Type, System.Object, System.Globalization.CultureInfo)

サンプル画面
image

実際動かして確認してみる。
PowershellだけでWPF表示(Powershell3.0でも2.0でも稼働)
.NetFrameworkは3.0以上が必要
WPFの約束としてPowershellはSTAモードで動く必要あり
以下コードを
①Powershellコンソールにコピペして実行
②ISEで実行する時はすでにSTAモードなので適時修正して実行
注意:ブラウザによってはコピペで行頭に余分な空白が出来てしまうことあり
C:\temp> □'@ ← ここの行の行頭に空白あると動かない


   1: #------------------------------------------------------ 
   2: if ($host.Version.Major -eq 3) {
   3:     powershell.exe
   4: } else {
   5:     powershell.exe -version 2 -sta
   6: }
   7:  
   8: if ($host.Version.Major -eq 3) {
   9:     add-type -assembly WindowsBase,PresentationCore,PresentationFramework,System.Xml,System.xaml
  10: } else {
  11:     add-type -assembly WindowsBase,PresentationCore,PresentationFramework
  12: }
  13:  
  14: $xaml = @'
  15: <Window
  16:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  17:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  18:     xmlns:local="clr-namespace:TwoWayConverter;assembly=TwoWayConverter"
  19:     Title="TwoWayConverter" Height="220" Width="275">
  20:  
  21:     <StackPanel>
  22:         <TextBox Margin="10">
  23:             <TextBox.Text>
  24:                 <Binding ElementName="sldrSlider" Path="Value">
  25:                     <Binding.Converter>
  26:                         <local:DisplayTwoDecPlaces/>
  27:                     </Binding.Converter>
  28:                 </Binding>
  29:             </TextBox.Text>
  30:         </TextBox>
  31:         <Slider Name="sldrSlider" TickPlacement="TopLeft" Margin="10"/>
  32:     </StackPanel>
  33: </Window>
  34: '@
  35:  
  36: $code = @'
  37: using System;
  38: using System.Windows.Data;
  39: namespace TwoWayConverter
  40: {
  41:     //[ValueConversion( typeof( double ), typeof( string ) )]
  42:     public class DisplayTwoDecPlaces : IValueConverter
  43:     {
  44:         public object val;
  45:         public Type   typ;
  46:         public object par;
  47:         public System.Globalization.CultureInfo cul;
  48:     
  49:         public object Convert( object value, Type targetType,
  50:         object parameter, System.Globalization.CultureInfo culture )
  51:         {
  52:             val = value;
  53:             typ = targetType;
  54:             par = parameter;
  55:             cul = culture;
  56:         
  57:             double dValue = (double) value;
  58:             return dValue.ToString( "F2" );
  59:         }
  60:         public object ConvertBack( object value, Type targetType,
  61:         object parameter,System.Globalization.CultureInfo culture )
  62:         {
  63:             double dValue;
  64:             double.TryParse( (string) value, out dValue );
  65:             return dValue;
  66:         }
  67:     }
  68: }
  69: '@
  70:  
  71: del C:\temp\work\TwoWayConverter.dll
  72: Add-Type $code -OutputAssembly "c:\temp\work\TwoWayConverter.dll" `
  73:          -ReferencedAssemblies @("WindowsBase","PresentationCore","PresentationFramework")
  74: add-type -Path C:\temp\work\TwoWayConverter.dll
  75:  
  76: $form = [System.Windows.Markup.XamlReader]::Parse($xaml)
  77:  
  78: $Form.ShowDialog() | out-null

Conver機能の設定状況を確認してみる
「TextBox」エレメントの「Text依存関係プロパティ」に紐付された「Bindingインスタンス」に設定されている。以下のように2行実行すると、



   1: $tb = $form.content.children[0]
   2: $tb.GetBindingExpression([System.Windows.Controls.TextBox]::TextProperty).ParentBinding

Bindingインスタンスを表示すると、「Converter」プロパティに設定されている



   1: ValidationRules             : {}
   2: ValidatesOnExceptions       : False
   3: ValidatesOnDataErrors       : False
   4: ValidatesOnNotifyDataErrors : True
   5: Path                        : System.Windows.PropertyPath
   6: XPath                       :
   7: Mode                        : Default
   8: UpdateSourceTrigger         : Default
   9: NotifyOnSourceUpdated       : False
  10: NotifyOnTargetUpdated       : False
  11: NotifyOnValidationError     : False
  12: Converter                   : TwoWayConverter.DisplayTwoDecPlaces    <--★これ!
  13: ConverterParameter          :
  14: ConverterCulture            :
  15: Source                      :
  16: RelativeSource              :
  17: ElementName                 : sldrSlider
  18: IsAsync                     : False
  19: AsyncState                  :
  20: BindsDirectlyToSource       : False
  21: UpdateSourceExceptionFilter :
  22: FallbackValue               : {DependencyProperty.UnsetValue}
  23: StringFormat                :
  24: TargetNullValue             : {DependencyProperty.UnsetValue}
  25: BindingGroupName            :
  26: Delay                       : 0

「Converter」の呼ばれ方状況を確認してみる


$form.content.Children[0].getBindingExpression([System.Windows.Controls.TextBox]::TextProperty).ParentBinding.Converter


以下のような値で、値が変化するたびに次々に呼ばれてるみたい



























Paramコメント
value4.759825328変換してほしい「double」型の値が渡される
targetTypeSystem.String   変換してほしい型は「String」でお願い..
parameter  
cultureen-US 

2013年2月3日日曜日

DataBinding(その2)

Mode(方向)とTrigger(きっかけ)について
   Binding によるデータの連携には、データの方向と更新タイミングの指定が必要

1.BindingのMode(方向)とは、データ更新の方向を指定すること

       [System.Windows.Data.BindingMode]  ←(Enum型)

 
名前 方向 内容
OneWay (S→T) 即更新
TwoWay (S→T) 即更新
   〃 (S←T) UpdataSourceTrigger値に依存
OneWayToSource (S←T) 同上(ソースが非依存関係プロパティのとき)
OneTime (S→T) 初期設定された時に1回のみ
Default (S→T) Element毎に定義されている(例:TextBoxはTwoWay)

2.BindingのTrigger(きっかけ)とは、データ更新のタイミングを指定すること

      [System.Windows.Data.UpdateSourceTrigger]    ←(Enum型)

名前 内容
Default ?
PropertyChanged ソース値が変化したとき
LostFocus ターゲット値が変化し、フォーカスを失ったとき
Explicit ソース値が変化し、明示的にBindingExpressionの
UpdateSource()が実行されたとき

3.改めて実際の例で、「TextBox」Bindingインスタンスに、Mode(方向)と
     Trigger(きっかけ)が設定されているか見てみることにする

実際の例

image

   1: #------------------------------------------------------ 
   2: if ($host.Version.Major -eq 3) {
   3:     powershell.exe
   4: } else {
   5:     powershell.exe -version 2 -sta
   6: }
   7:  
   8: if ($host.Version.Major -eq 3) {
   9:     add-type -assembly WindowsBase,PresentationCore,PresentationFramework,System.Xml,System.xaml
  10: } else {
  11:     add-type -assembly WindowsBase,PresentationCore,PresentationFramework
  12: }
  13:  
  14: $Xaml = @'
  15: <Window
  16:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  17:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  18:     Title="Markup Extensions" Height="220" Width="175">
  19:  
  20:     <Window.Resources>
  21:         <LinearGradientBrush x:Key="gradBrush" StartPoint="0,0" EndPoint="1,1"> 
  22:             <GradientStop Color="SteelBlue" Offset="0" />
  23:             <GradientStop Color="Silver" Offset="1"/>
  24:         </LinearGradientBrush>
  25:     </Window.Resources>
  26:  
  27:     <StackPanel Background="{StaticResource gradBrush}">
  28:         <TextBox Name="tbValue" Margin="10"
  29:                  Text="{Binding ElementName=sldrSlider, Path=Value, Mode=TwoWay}"/>
  30:         <Slider Name="sldrSlider" TickPlacement="TopLeft" Margin="10"/>
  31:         <Button Name="bnValue">Trigger</Button>
  32:     </StackPanel>
  33:  
  34: </Window>
  35: '@
  36:  
  37: $form = [System.Windows.Markup.XamlReader]::Parse($xaml)
  38:  
  39: $script = {
  40:     $bindExpression = $form.FindName("tbValue").GetBindingExpression(`
  41:                       [System.Windows.Controls.TextBox]::TextProperty)
  42:     $bindExpression.UpdateSource()
  43: }
  44:  
  45: $form.findName("bnValue").add_Click($script)
  46: $Form.ShowDialog() | out-null

「TextBox」の「Text依存関係プロパティ」につなげられている「Slider」の値を見る


> $form.findname("tbValue").GetBindingExpression  ( `
            [System.Windows.Controls.TextBox]::TextProperty).ParentBinding


      > Mode                              TwoWay ←★1
      > UpdateSourceTrigger    Default ←★2

このように、「Binding」インスタンスにMode(方向)とTrigger(タイミング)が保持されている。