WPFでbindingexpressionからバウンドオブジェクトを解決するにはどうすればいいですか?

c# data-binding mvvm wpf

やあこんにちは誰もがbindingexpressionからバインドされたオブジェクトを解決するための作り付けのクラスがあり、それはDataItemとプロパティパスであるかどうかを知っていますか?

テキストボックスのTextプロパティにバインドされたオブジェクトのメソッドを自動的に呼び出す、テキストボックス用のBlend 3の動作を作成しようとしています。

テキストボックスはビューモデルクラスのプロパティにバインドされています。 私がやりたいことは、バインディング式からviewmodelクラスを解決し、それからこれを呼び出すことです。

最初に、振る舞いの関連オブジェクトからバインディング式を取得します。

private BindingExpression GetTextBinding(){return this.AssociatedObject.GetBindingExpression(TextBox.TextProperty);} }

これを行った後、バインディング式を見ると、バインディング式のDataItemプロパティを介してデータコンテキストへの参照があることがわかります。

さらに、バインディング式の親バインディングにバインドされているプロパティの相対パスがあります。

だから、我々はこの情報を得ることができます:

var bindingExpression = GetTextBinding();オブジェクトdataContextItem = bindingExpression.DataItem; PropertyPath relativePropertyPath = bindingExpression.ParentBinding.Path;

さて、このプロパティパスは潜在的に複雑にネストされた複雑なパスになる可能性があります。 私は.NETのドキュメントを検索し、リフレクタを使用してアセンブリを跳ね回しましたが、すべてが無駄になっています – 確実に存在するはずのものが見つからない – データ項目のパスの解決を実行するクラスが必要です。データコンテキスト)

誰がこれがどこに存在する可能性があるか知っていますか? バインドされたオブジェクトを解決するための代替方法について何か提案はありますか?

注意、私はboundプロパティ(この場合は文字列)の_parent_であるboundオブジェクトに到達しようとしています – 明らかにbound値に到達することができますが、それは私が必要とする親です。

ご協力ありがとうございます。 フィル

  19  6


ベストアンサー

以下は、あなたが探しているものだけを実行する拡張メソッドの簡単な実装です。 これに関連するものも見つかりませんでした。 何らかの理由で値が見つからない場合、以下のメソッドは常にnullを返します。 パスに[]が含まれていると、メソッドは機能しません。 これが助けになれば幸いです。

public static T GetValue(このBindingExpression式、オブジェクトdataItem){if(expression == null || dataItem == null){default(T)を返す。 }

string bindingPath = expression.ParentBinding.Path.Path; string [] properties = bindingPath.Split( '。');

オブジェクトcurrentObject = dataItem。 type currentType = null。

for(int i = 0; i <properties.Length; i){currentType = currentObject.GetType(); PropertyInfo property = currentType.GetProperty(properties [i]); if(property == null){currentObject = null;ブレーク; currentObject = property.GetValue(currentObject、null); if(currentObject == null){break; }}

currentObjectを返します。 }

23


この質問につまずく将来の人々のために:

NET 4.5が利用可能になると、あなたが探しているものを非常に単純化するためにBindingExpression上にいくつかの新しいプロパティがあるでしょう。
  • ResolvedSource * – 実際にバインドされているオブジェクト。 ‘grandparent.parent.me.Name’のようなバインディングソースがある場合に役立ちます。 これは ‘me’オブジェクトを返します。

  • ResolvedSourcePropertyName * – バインドされているResolvedSourceのプロパティの名前。 上記の場合、「名前」。

同様に、* Target 、および TargetName *プロパティがあります。

BindingExpressionのこれらのヘルパープロパティを使用すると、極端な状況(インデクサー)で動作する可能性が高い、より短くより単純なリフレクションを使用できます。

22


詳細については、PropertyPathの解決は、PropertyPathWorkerというMSの内部クラスによって処理されます。このクラスは、MS.Internal.Dataの下のPresentationFrameworkにあります。 Reflectorで開くと、非常に複雑に見えるので、その機能を複製しないことをお勧めします。 これは全体的なBindingアーキテクチャと密接に関係しています。

添付された依存関係プロパティや階層トラバーサルを含むすべてのプロパティパス構文をサポートする最も堅牢な方法は、おそらくDependencyPropertyを使用してダミーのDependencyObjectを作成することです。 その後、 ‘所有者’パスからダミーの依存関係プロパティへのバインディングを作成し、新しいBindingExpressionを作成してから、式のUpdateTargetを呼び出します。 表面的には単純なタスクのように見えるものを達成するためのかなり重い方法ですが、プロパティパスがバインディングのために解決される方法に多くの隠された問題があると思います。

9


私はこの他のStackOverflow ここに投稿された解決策もあなたのために働くかもしれないと思います。

参考のためにコードブロックをコピーし、Thomas Levesqueによる詳細については元の記事を読んでください。

public static class PropertyPathHelper {public static object GetValue(オブジェクトobj、string propertyPath){Binding binding = new Binding(propertyPath); binding.Mode = BindingMode.OneTime; binding.Source = obj; BindingOperations.SetBinding(_dummy、Dummy.ValueProperty、binding); _dummy.GetValue(Dummy.ValueProperty)を返します。 }

プライベート静的読み取り専用Dummy _dummy = new Dummy();

プライベートクラスDummy:DependencyObject {public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( "Value"、typeof(オブジェクト)、typeof(ダミー)、new UIPropertyMetadata(null)); }}

7


Dan Bryantがすでに述べたように、 `PropertyPath`解決は全体的なバインディングアーキテクチャと密接に関係しています。 WPFとまったく同じ解像度が必要な場合は、おそらく この質問に対するThomas Levesqueの回答を使用してください。

ただし、一般的なパス解決が必要な場合は、https://www.nuget.org/packages/Pather.CSharp[nuget package] Pather.CSharpを使用できます。私はまさにそれを開発しました。

それはzhechの答えに本質的に似ていますが、より洗練されています。

その主なメソッドは Resolver`クラスの Resolve`です。 * target object path を文字列として渡すと、目的の結果が返されます。 例:

IResolver resolver = new Resolver(); var target = new {Property1 = new {Property2 = "value"}};オブジェクト結果= r.Resolve(target、 "Property1.Property2");

インデックスを介した*コレクションアクセス*やキーを介した*辞書アクセス*もサポートしています。 これらのパスの例は次のとおりです。

"ArrayProperty [5]" "DictionaryProperty [キー]"

2


タイトルとURLをコピーしました