mikeo_410


 Styleとバインディング

  プロパティ自体は、プロパティとして記述するか、StyleのSetterでアクセスするかで、宣言の仕方が違いました。
  次に、Styleで値をバインディングする場合を見ます。Styleとプロパティで差があるのかどうかはわかりません。

  XAMLとビハインドコード

  ウイザードが作るXAMLとビハインドコードの場合を見ます。

  1. <Grid Loaded="Grid_Loaded">
  2.     <Grid.Resources>
  3.         <Style TargetType="Button">
  4.             <Setter Property="Content" Value="{Binding BindingValue1}"/>
  5.         </Style>
  6.     </Grid.Resources>
  7.     <StackPanel>
  8.         <Button/>
  9.         <Button Content="{Binding BindingValue2}"/>
  10.     </StackPanel>
  11. </Grid>

  バインドする値は、以下のように宣言しました。

  1. string _BindingValue1;
  2. public string BindingValue1
  3. {
  4.     get { return _BindingValue1; }
  5.     set
  6.     {
  7.         _BindingValue1 = value;
  8.         if(PropertyChanged!=null)
  9.             PropertyChanged.Invoke(this, 
  10.                 new PropertyChangedEventArgs("BindingValue1"));
  11.     }
  12. }
  13. string _BindingValue2;
  14. public string BindingValue2
  15. {
  16.     get { return _BindingValue2; }
  17.     set
  18.     {
  19.         _BindingValue2 = value;
  20.         if (PropertyChanged != null)
  21.             PropertyChanged.Invoke(this, 
  22.                 new PropertyChangedEventArgs("BindingValue2"));
  23.     }
  24. }

  Loadedイベントで、値をセットします。

  1. private void Grid_Loaded(object sender, RoutedEventArgs e)
  2. {
  3.     DataContext = this;
  4.     BindingValue1 = "VALUE1";
  5.     BindingValue2 = "VALUE2";
  6. }

  DataContext に this を代入しないと上手く行きません。
  このことは、以下のようにペアの関係に無関係にバインディングできることを示しています。

  1. public class XXX
  2. {
  3.     public string BindingValue1 { get; set; }
  4.     public string BindingValue2 { get; set; }
  5.     public XXX()
  6.     {
  7.         BindingValue1 = "XXX1";
  8.         BindingValue2 = "XXX2";
  9.     }
  10. }

  以下のようにバインドできます。

  1. private void Grid_Loaded(object sender, RoutedEventArgs e)
  2. {
  3.     DataContext = new XXX();
  4. }

  また、DataContext は、XAMLでも記述できます。この場合、コードでは何も設定しなくてもXXXクラスのコンストラクタで設定した値がボタンに表示されます。

  1. <Grid xmlns:u="clr-namespace:WpfApplication1" Loaded="Grid_Loaded">
  2.     <Grid.Resources>
  3.         <u:XXX x:Key="xxx"/>
  4.         <Style TargetType="Button">
  5.             <Setter Property="Content" 
  6.                     Value="{Binding Source={StaticResource xxx},
  7.                                     Path=BindingValue1}"/>
  8.         </Style>
  9.     </Grid.Resources>
  10.     <StackPanel DataContext="{Binding Source={StaticResource xxx}}">
  11.         <Button/>
  12.         <Button Content="{Binding BindingValue2}"/>
  13.     </StackPanel>
  14. </Grid>

個別のXAMLファイルとコードの場合

  XAMLファイルとコードを別々に作成した場合にはどうなるのか見ます。
  TEST2.xaml を以下の内容で作成します。

  1. <ContentControl 
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  4.     <Grid>
  5.         <Grid.Resources>
  6.             <Style TargetType="Button">
  7.                 <Setter Property="Content" 
  8.                         Value="{Binding BindingValue1}"/>
  9.             </Style>
  10.         </Grid.Resources>
  11.         <StackPanel>
  12.             <Button x:Name="B1"/>
  13.             <Button x:Name="B2" Content="{Binding BindingValue2}"/>
  14.             <Button x:Name="B3">
  15.                 <Button.Style>
  16.                     <Style TargetType="Button">
  17.                         <Setter Property="Content"
  18.                                 Value="{Binding BindingValue3}"/>
  19.                     </Style>
  20.                 </Button.Style>
  21.             </Button> 
  22.         </StackPanel>
  23.     </Grid>
  24. </ContentControl>    

  TEST3.cs を以下の内容で作成します。

  1. using System;
  2. using System.Windows;
  3. using System.Windows.Controls;
  4. using System.Windows.Markup;
  5. using System.Diagnostics;
  6. namespace WpfApplication1
  7. {
  8.     public class TEST3 : ContentControl, IComponentConnector
  9.     {
  10.         public TEST3()
  11.         {
  12.             BindingValue1 = "BBB1";
  13.             BindingValue2 = "BBB2";
  14.             BindingValue3 = "BBB3";
  15.             Uri resourceLocater
  16.                 = new Uri("/WpfApplication1;component/TEST2.xaml",
  17.                           System.UriKind.Relative);
  18.             Application.LoadComponent(this, resourceLocater);
  19.             Loaded += new RoutedEventHandler(TEST3_Loaded);
  20.         }
  21.         public string BindingValue1 { get; set; }
  22.         public string BindingValue2 { get; set; }
  23.         public string BindingValue3 { get; set; }
  24.         void TEST3_Loaded(object sender, RoutedEventArgs e)
  25.         {
  26.             DataContext = this;
  27.         }
  28.         void IComponentConnector.InitializeComponent()
  29.         {
  30.             Debug.WriteLine("IComponentConnector.InitializeComponent()");
  31.         }
  32.         public void Connect(int connectionId, object target)
  33.         {
  34.             Debug.WriteLine("Connect " + target);
  35.         }
  36.     }
  37. }

  これをMainWindowでインスタンスして表示します。

  1. private void Grid_Loaded(object sender, RoutedEventArgs e)
  2. {
  3.     TEST3 test3 = new TEST3();
  4.     stackpanel1.Children.Add(test3);
  5. }

  MainWindow.xaml には以下のように、stackpanel1 と名前を付けた StackPanel を起きます。

  1. <Grid Loaded="Grid_Loaded">
  2.     <StackPanel Name="stackpanel1">
  3.     </StackPanel>
  4. </Grid>

  実行すると左図を表示します。
  XAMLとビハインドコードのペアと同様に考えて良さそうです。

  やはり、DataContext の設定が必要です。
  Loadedイベントで、DataContext の設定の前後でボタンのContentsの内容を見ると、DataContext の設定の前には値が設定されていません。

  DataContextの設定で、ボタンのContentsの値が変わりますが、この値はButtonインスタンス内にあるのか、Contentsプロパティの参照先が変更されたのかは区別がつきません。

参照

問題を整理すると、

  1. XAMLを分割して記述する方法
  2. 記述1つから複数のインスタンスを得る方法

と、言うことになります。

カスタムコントロールのXAMLとコード
Styleとプロパティ
Styleとバインディング
DataContextとインスタンス
XAML記述とVisualの変換
1つのStyle記述から複数のインスタンス

FrameworkElementFactory(コードでTemplateを作る)


mikeo_410@hotmail.com