2009-10-11 26 views
18

嗨有沒有人知道是否有任何內置的類從綁定表達式解析綁定對象,它的DataItem和屬性路徑?如何使用WPF解析bindingexpression中的綁定對象?

我正在嘗試編寫一個Blend 3行爲的文本框,它會自動調用綁定到文本框Text屬性的對象上的方法。

該文本框綁定到viewmodel類的屬性。我想要做的是從綁定表達式中解析viewmodel類,然後對此進行調用。

我第一次檢索行爲的關聯對象綁定表達式,像這樣:

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

已經做到了這一點,如果我們看一下綁定表達式,我們可以看到它必須通過數據上下文的參照綁定表達式的DataItem屬性。

此外,我們有綁定表達式的父綁定上綁定的屬性的相對路徑。

所以,我們可以得到這樣的信息:(?再)

var bindingExpression = GetTextBinding(); 
object dataContextItem = bindingExpression.DataItem; 
PropertyPath relativePropertyPath = bindingExpression.ParentBinding.Path; 

現在,這個屬性路徑可能是一個深度嵌套的和複雜的路徑,這是我非常希望,以避免執行第的。我搜索了.NET文檔,並用反射器反彈了所有程序集,但都無濟於事 - 我無法找到肯定必須存在的東西 - 必須有一些類來執行數據項目路徑的解析(數據上下文)。

有人知道這可能存在嗎?任何關於解決綁定對象的替代方法的建議?請注意,我試圖得到綁定的對象,這是綁定屬性的(在這種情況下,字符串) - 我可以很容易地獲得綁定值,但它是我需要的父對象。

在此先感謝您的幫助! 菲爾

回答

23

下面是一個擴展方法的快速實現,它將完成您正在尋找的任務。我也找不到與此相關的任何內容。如果由於某些原因無法找到該值,下面的方法將始終返回null。當路徑包含[]時,該方法將不起作用。我希望這有幫助!

public static T GetValue<T>(this BindingExpression expression, object dataItem)    
{ 
    if (expression == null || dataItem == null) 
    { 
     return default(T); 
    } 

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

    object 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; 
      break; 
     } 
     currentObject = property.GetValue(currentObject, null); 
     if (currentObject == null) 
     { 
      break; 
     } 
    } 

    return (T)currentObject; 
} 
+0

感謝zhech,我給一個嘗試。 – Phil 2009-10-19 02:44:43

+5

My2cents,是否有你傳入對象dataItem的原因?爲什麼不改變方法簽名來取代一個參數,而是從BindingExpression中獲取dataItem? – Terrance 2012-04-27 16:50:13

+0

這看起來不像它會用索引器解析屬性路徑,還是它? – 2014-01-02 15:07:13

8

只是爲了進一步的信息,的PropertyPath分辨率由稱爲PropertyPathWorker內部MS類,生活在PresentationFramework MS.Internal.Data下處理。如果你在Reflector中打開它,你會發現它非常複雜,所以我不建議嘗試複製它的功能。它與整體綁定架構緊密結合。

支持所有屬性路徑語法(包括附加的依賴屬性和層次遍歷)的最穩健的方法可能是使用DependencyProperty創建一個虛擬的DependencyObject。然後,您可以創建一個從'所有者'路徑到虛擬依賴項屬性的綁定,創建一個新的BindingExpression,然後調用表達式的UpdateTarget。從表面上看,這是一種相當沉重的方式,看起來像一個簡單的任務,但我認爲在解決綁定屬性路徑的方式中有很多隱藏的陷阱。

+0

謝謝丹,這是很好的信息。 – Phil 2009-12-30 16:18:36

+1

源代碼會更好。 :) – 2014-07-30 15:43:47

7

我相信這個其他StackOverflow solution posted here也可能適合你。

複製代碼塊以供參考,閱讀原文,瞭解Thomas Levesque提供的更多詳細信息。

public static class PropertyPathHelper 
{ 
    public static object GetValue(object obj, string propertyPath) 
    { 
     Binding binding = new Binding(propertyPath); 
     binding.Mode = BindingMode.OneTime; 
     binding.Source = obj; 
     BindingOperations.SetBinding(_dummy, Dummy.ValueProperty, binding); 
     return _dummy.GetValue(Dummy.ValueProperty); 
    } 

    private static readonly Dummy _dummy = new Dummy(); 

    private class Dummy : DependencyObject 
    { 
     public static readonly DependencyProperty ValueProperty = 
      DependencyProperty.Register("Value", typeof(object), typeof(Dummy), new UIPropertyMetadata(null)); 
    } 
} 
16

對於人們對未來誰無意中發現了這個問題:

當.NET 4.5變爲可用它都會有一些對BindingExpression新的特性,大大簡化你在找什麼。

ResolvedSource - 實際綁定到的對象,當您有像「grandparent.parent.me.Name」這樣的綁定源時很有用。這將返回'我'的對象。

ResolvedSourcePropertyName - 綁定到的ResolvedSource屬性的名稱。在上面的情況下,「名稱」。

同樣,會有目標目標名稱屬性。

通過BindingExpression上的這些幫助屬性,您可以使用一些更簡短的反射,這種反射更可能在極端情況下(索引器)工作。

+0

你知道是否有強制綁定表達式來更新這些屬性?當處理控件數據上下文發生變化並從綁定表達式獲取源時,我遇到了一種特殊情況,但這些屬性在屬性更改和數據上下文更改事件之後似乎保持爲空。 – 2015-05-15 03:33:46

+0

@ AlexHopeO'Connor我可以用多種方式解釋你的問題。我建議開始一個新的問題,而不是在這裏添加。 – 2015-05-15 12:45:33

2

由於Dan Bryant已經指出,PropertyPath分辨率與整體綁定架構緊密結合。
如果您需要與WPF完全相同的分辨率,您應該使用Thomas Levesque對this問題的回答。

但是,如果你只是需要一般路徑分辨率,你可以使用我開發的nuget packagePather.CSharp

它基本上與zhech的答案類似,但更復雜。

其主要方法是Resolver類的Resolve。作爲字符串傳遞目標對象路徑返回所需的結果。
一種示例:

IResolver resolver = new Resolver(); 
var target = new { Property1 = new { Property2 = "value" } }; 
object result = r.Resolve(target, "Property1.Property2"); 

它也支持經由索引或通過鍵字典訪問收集訪問
這些範例路徑爲:

"ArrayProperty[5]" 
"DictionaryProperty[Key]"