7792


TextBoxコントロールなどで、`Text="{Binding
Hoge}"`などとバインディングの記述をしますが、自分で作ったユーザーコントロールのプロパティに対してバインドされたプロパティのPropertyInfoを取得することはできますか？

やりたいことは、下記の通りです。

前提１．バインドするビューモデルクラスには入力値検証のための各種Validator属性が付けられている  
前提２．Validator属性には上限文字数などのパラメータが与えられている

目的．バインドされたプロパティの上限文字数を見て、TextBoxの`Width`を変更したい

文字数とWidthだけではないんですが、とにかくバインド対象プロパティの情報を得て、ユーザーコントロールの見た目や振る舞いを変更したいと考えています。  
ユーザーコントロール側でPropertyInfoさえ取得できれば後はどうにでもなるのですが、何か方法はあるでしょうか？


CC BY-SA 3.0
2015-03-11T05:18:32.023
7756
2015-03-11T11:02:42.700
8078
question
wpf xaml
XAMLでバインドされているプロパティのPropertyInfoを取得したい


大雑把に言うと技術的には

  1. `BindingOperations.GetBinding`で`Binding`を得る
  2. `Binding.Path`が複合パスか確認
  3. 複合パスでなければ`DataContext`(もしくは`RelativeSource`その他)からプロパティ情報を得る。
  4. 複合パスであればパスを分割し、上位パスを適当なプロパティにバインドしてプロパティを持つコンポーネントを得る

という手順で評価できます。なお上記の手順は`BindingBase`の種別や`PropertyPath`文法と言った多くの考慮事項を省いています。

またC#のメタプログラミングでは一般的に`PropertyInfo`より`PropertyDescriptor`が優先されるため、そちらで属性を確認したほうが良いと思われます。

C#

[code]

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Console.WriteLine(GetPropertyInfo(txt1));
            Console.WriteLine(GetPropertyInfo(txt2));
        }
    
        private static readonly DependencyProperty EvaluationResultProperty =
            DependencyProperty.RegisterAttached("EvaluationResult", typeof(object), typeof(MainWindow), new PropertyMetadata(null));
    
        private PropertyInfo GetPropertyInfo(TextBox textBox)
        {
            var b = BindingOperations.GetBinding(textBox, TextBox.TextProperty) as Binding;
            if (b == null || b.Path == null)
            {
                return null;
            }
    
            var p = b.Path.Path;
    
            if (string.IsNullOrEmpty(p))
            {
                return null;
            }
    
            var i = p.LastIndexOf('.');
            if (i < 0)
            {
                return textBox.DataContext.GetType().GetProperty(p);
            }
            else
            {
                var fe = new FrameworkElement();
                fe.DataContext = textBox.DataContext;
    
                var nb = new Binding(p.Substring(0, i));
                fe.SetBinding(EvaluationResultProperty, nb);
    
                var dc = fe.GetValue(EvaluationResultProperty);
    
                return dc.GetType().GetProperty(p.Substring(i + 1));
            }
        }
    }
    
[/code]

XAML

[code]

    <Window
        x:Class="WpfApplicationTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:WpfApplicationTest"
        Title="MainWindow"
        Height="400"
        Width="400"
        Loaded="Window_Loaded">
        <Window.DataContext>
            <my:ViewModel />
        </Window.DataContext>
        <StackPanel>
            <TextBox
                Name="txt1"
                Text="{Binding Piyo}" />
            <TextBox
                Name="txt2"
                Text="{Binding Hoge.Fuga}" />
        </StackPanel>
    </Window>
    
[/code]


CC BY-SA 3.0
2015-03-11T11:02:42.700
7792
2015-03-11T11:02:42.700
5750
7756
answer