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

質問
-
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>
回答
-
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 クラスに渡されないとか、そういった理由なのかもしれないと妄想してます。あくまで妄想ですが)
すべての返信
-
-
回答ありがとうございます。
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アタッチプロパティをバインドすることが出来るのですが、自分で作成したアタッチプロパティだとバインドされないのです。
-
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 クラスに渡されないとか、そういった理由なのかもしれないと妄想してます。あくまで妄想ですが) -
ありがとうございます。
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つでずいぶんと見た目以上に動作が変わるなぁ。と実感しました。