none
自分で作成したアタッチプロパティをXAMLのバインドパスとして設定したい。 RRS feed

  • 質問

  • http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1208052&SiteID=1

    にも書いたのですが、反応が無いので、こちらにも・・・。

    やりたい事は、自分で定義したアタッチプロパティ(Window1.MyString2)があるのですが、その設定値をBindingで取得したいだけです。

    C#



    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }
        public static string GetMyString2(DependencyObject obj)
            {   return (string)obj.GetValue(MyString2Property);  }
        public static void SetMyString2(DependencyObject obj, string value)
            {   obj.SetValue(MyString2Property, value);          }
        public static readonly DependencyProperty MyString2Property =
            DependencyProperty.RegisterAttached("MyString2",
                typeof(string), typeof(Window1),
                new UIPropertyMetadata(null));
    }
    public class MyTextBox : TextBox
    {
        static MyTextBox()
        {
            DefaultStyleKeyProperty.OverrideMetadata(
                typeof(MyTextBox),
                new FrameworkPropertyMetadata(typeof(MyTextBox)) );
        }
        protected override void OnTextChanged(TextChangedEventArgs e)
        {
            base.OnTextChanged(e);
            MyString1 = Text;
            Window1.SetMyString2( this, Text );
        }
        public string MyString1
        {
            get { return (string)GetValue(MyString1Property); }
            set { SetValue(MyString1Property, value); }
        }
        public static readonly DependencyProperty MyString1Property =
            DependencyProperty.Register("MyString1",
                typeof(string), typeof(MyTextBox),
                new UIPropertyMetadata(null));
    }


     

    XAML


    <Window x:Class="MyTest.Window1"
      xmlns="
    http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="
    http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="clr-namespace:MyTest"
      Title="MyTest" Height="300" Width="300">
      <Window.Resources>
        <Style TargetType="{x:Type local:MyTextBox}">
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate TargetType="{x:Type local:MyTextBox}">
                <Grid>
                  <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                  </Grid.ColumnDefinitions>
                  <TextBox Grid.Column="0"
                      Text="{Binding Text, RelativeSource={x:Static RelativeSource.TemplatedParent}}"/>
                  <Border Grid.Column="1" BorderBrush="Blue" BorderThickness="1">
                    <TextBlock Name="block1"
                      Text="{Binding MyString1, RelativeSource={x:Static RelativeSource.TemplatedParent}}"/>
                  </Border>
                  <Border Grid.Column="2" BorderBrush="Green" BorderThickness="1">
                    <TextBlock Name="block2"
                      Text="{Binding (local:Window1.MyString2), RelativeSource={x:Static RelativeSource.TemplatedParent}}"/>
                  </Border>
                </Grid>
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </Style>
      </Window.Resources>
      <StackPanel>
        <local:MyTextBox/>
      </StackPanel>
    </Window>

     

     

    2007年2月22日 5:15

回答

  •  FC-Shiro さんからの引用

    MyTextBoxに設定してある、Window1.MyString2 アタッチプロパティにバインドしたい。

    すみません、完全にご質問の内容を取り違えてました。
    ただ、私は

     FC-Shiro さんからの引用

    バインドで、{Binding (Grid.Row), RelativeSource={x:Static RelativeSource.TemplatedParent}} と言う書き方は、ちゃんとGrid.Rowアタッチプロパティをバインドすることが出来る

    ということ自体知らなかったです(^^;
    おまけに、{Binding (Grid.Row), ...} と括弧でくくらないといけないことも知らなかったです。(最初、{Binding Grid.Row, ...} と書いて、なんで動かないのか悩んじゃいました)

    が、ちょっと試してたら

    {Binding Path=(local:Window1.MyString2), RelativeSource={x:Static RelativeSource.TemplatedParent}}

    というように Path= を明示してあげたら動くことを発見しました。
    Path= のあるなしで挙動が変わるのはちょっと意外です。( "(local:Window1.MyString2)" がBinding クラスのコンストラクタに渡されるか、Path プロパティにセットされるかの違いなんでしょうが、ひょっとすると Path= がないと XAML パーサが local: を勝手に解釈しようとしてちゃんと Binding クラスに渡されないとか、そういった理由なのかもしれないと妄想してます。あくまで妄想ですが)

    2007年2月23日 2:57

すべての返信

  • 自分自身である Window1 クラスの MyString2 プロパティ (Dependency Property) にバインドしたい、ということでよろしいですか?
    その場合、

    <TextBox Text="{Binding Path=MyString2, RelativeSource={RelativeSource AncestorType={x:Type local:Window1}}}"></TextBox>

    と書けばいいと思います。
    これは、親に向かって local:Window1 型を探し、みつかったらそれをソースとする、ということです。

    2007年2月22日 9:42
  • 回答ありがとうございます。

     Shinichi Aoyagi さんからの引用

    自分自身である Window1 クラスの MyString2 プロパティ (Dependency Property) にバインドしたい、ということでよろしいですか?

    違います。

    MyTextBoxに設定してある、Window1.MyString2 アタッチプロパティにバインドしたい。

    です。

    アタッチプロパティなので、Grid.RowやDockPanel.Dockと同様なプロパティです。(GridやDockPanelにDependencyPropertyの定義があるけど、他のDependencyObjectに設定出来るプロパティ)

    MyTextBoxは、TextBoxを派生しており、その中のTextプロパティの変更のタイミングでMyTextBoxのWindow1.MyString2 アタッチプロパティに値をコピーしております。

    バインドで、{Binding (Grid.Row), RelativeSource={x:Static RelativeSource.TemplatedParent}} と言う書き方は、ちゃんとGrid.Rowアタッチプロパティをバインドすることが出来るのですが、自分で作成したアタッチプロパティだとバインドされないのです。

    2007年2月22日 10:11
  •  FC-Shiro さんからの引用

    MyTextBoxに設定してある、Window1.MyString2 アタッチプロパティにバインドしたい。

    すみません、完全にご質問の内容を取り違えてました。
    ただ、私は

     FC-Shiro さんからの引用

    バインドで、{Binding (Grid.Row), RelativeSource={x:Static RelativeSource.TemplatedParent}} と言う書き方は、ちゃんとGrid.Rowアタッチプロパティをバインドすることが出来る

    ということ自体知らなかったです(^^;
    おまけに、{Binding (Grid.Row), ...} と括弧でくくらないといけないことも知らなかったです。(最初、{Binding Grid.Row, ...} と書いて、なんで動かないのか悩んじゃいました)

    が、ちょっと試してたら

    {Binding Path=(local:Window1.MyString2), RelativeSource={x:Static RelativeSource.TemplatedParent}}

    というように Path= を明示してあげたら動くことを発見しました。
    Path= のあるなしで挙動が変わるのはちょっと意外です。( "(local:Window1.MyString2)" がBinding クラスのコンストラクタに渡されるか、Path プロパティにセットされるかの違いなんでしょうが、ひょっとすると Path= がないと XAML パーサが local: を勝手に解釈しようとしてちゃんと Binding クラスに渡されないとか、そういった理由なのかもしれないと妄想してます。あくまで妄想ですが)

    2007年2月23日 2:57
  • ありがとうございます。

     Shinichi Aoyagi さんからの引用

    Binding Path=(local:Window1.MyString2), RelativeSource={x:Static RelativeSource.TemplatedParent}}

    というように Path= を明示してあげたら動くことを発見しました。
    Path= のあるなしで挙動が変わるのはちょっと意外です。( "(local:Window1.MyString2)" がBinding クラスのコンストラクタに渡されるか、Path プロパティにセットされるかの違いなんでしょうが、ひょっとすると Path= がないと XAML パーサが local: を勝手に解釈しようとしてちゃんと Binding クラスに渡されないとか、そういった理由なのかもしれないと妄想してます。あくまで妄想ですが)

    "Path="を入れないといけないと言うのは完全な盲点でした。(目が点になりました)
    しかし、コンストラクタとプロパティで同じものなのに別な動作をするというのは・・・。

    ちょっと調べてみました。

    コンストラクタで指定した場合には、PropertyPathオブジェクトを内部で自分で作成しているようですが、
    Pathプロパティの場合には、PropertyPathConverter経由でのPropertyPathオブジェクト作成となって
    いるようです。 その中で、PropertyPathオブジェクトに、ITypeDescriptorContextのオブジェクトが渡
    っています。それが local: の解決が出来るかどうかの差になっているようですね。

    XAMLも、書き方1つでずいぶんと見た目以上に動作が変わるなぁ。と実感しました。

    2007年2月23日 5:11