2009-10-11 5 views
18

Witam, czy ktoś wie, czy istnieją jakieś wbudowane klasy do rozwiązania związanego obiektu z obiektu bindingexpression i jego DataItem i ścieżka właściwości?Jak rozwiązać związany obiekt z bindingexpression z WPF?

Próbuję zapisać zachowanie Blend 3 dla pól tekstowych, które automatycznie wywołują metody na obiekcie powiązanym z właściwością Textbox pola tekstowego.

Pole tekstowe jest powiązane z właściwością w klasie viewmodel. To, co chcę zrobić, to rozwiązać klasę viewmodel z wyrażenia wiążącego, a następnie wywołać to.

ja najpierw pobrać wyrażenia wiązania z powiązanego obiektu zachowanie jest tak:

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

Uczyniwszy to, jeśli spojrzymy na wyrażeniu wiązania, widzimy, że ma odniesienie do kontekstu danych poprzez właściwość DataItem powiązania wyrażenia.

Ponadto mamy względną ścieżkę właściwości, która jest związana z powiązaniem macierzystym wyrażenia wiążącego.

Tak, możemy uzyskać te informacje: (? Re)

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

Teraz ta droga nieruchomość mogłaby zostać głęboko zagnieżdżone i złożone ścieżka, którą chciałbym bardzo chciałbym uniknąć konieczności wdrożenia rozdzielczość z. Przeszukałem dokumentację .NET i odbiłem się od zgromadzeń z reflektorem, wszystko bezskutecznie - nie mogę znaleźć tego, co na pewno musi istnieć - musi istnieć jakaś klasa, która wykonuje rozdzielczość ścieżki dla dataitem (kontekst danych).

Czy ktoś wie, gdzie to może istnieć? Wszelkie sugestie dotyczące alternatywnych sposobów rozwiązania związanego obiektu?

Uwaga, próbuję dostać się do obiektu związanego, który jest rodzicem z powiązanej właściwości (ciąg w tym przypadku) - Oczywiście mogę łatwo uzyskać wartość powiązaną, ale jest to rodzic, którego potrzebuję .

Z góry dziękuję za pomoc! Phil

Odpowiedz

23

Poniżej znajduje się szybkie wdrożenie metody rozszerzenia, która zrobi dokładnie to, czego szukasz. Nie mogłem znaleźć nic z tym związanego. Poniższa metoda zawsze zwróci wartość null, jeśli z jakiegoś powodu nie można znaleźć wartości. Metoda nie będzie działać, jeśli ścieżka zawiera []. Mam nadzieję, że to pomoże!

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

Dzięki zhech, że dam szansę. – Phil

+5

My2cents, czy jest jakiś powód, dla którego przechodzisz w obiekcie dataItem? Dlaczego nie wystarczy zmienić sygnatury metody, aby uzyskać jeden parametr zamiast dwóch i uzyskać element dataItem z BindingExpression? – Terrance

+0

To nie wygląda na to, że rozwiąże ścieżki właściwości za pomocą indekserów, czy nie? –

8

Tylko dla dalszych informacji, rozdzielczość PropertyPath jest obsługiwany przez wewnętrzne klasy MS nazwie PropertyPathWorker, która mieszka w PresentationFramework pod MS.Internal.Data. Jeśli otworzysz go w Reflectorze, możesz zauważyć, że jest to dość skomplikowane, więc nie poleciłbym próbować duplikować jego funkcjonalności. Jest ściśle powiązany z ogólną architekturą bindowania.

Najbardziej niezawodny sposób obsługi wszystkich składni ścieżki własności - w tym dołączonych właściwości zależności i przejścia hierarchicznego - jest prawdopodobnie utworzenie atrapa DependencyObject z DependencyProperty. Następnie możesz utworzyć powiązanie ze swojej ścieżki "właściciel" do właściwości zależności atrapowej, utworzyć nową funkcję BindingExpression, a następnie wywołać funkcję UpdateTarget wyrażenia. Jest to raczej ciężki sposób na osiągnięcie tego, co na pierwszy rzut oka wygląda jak proste zadanie, ale myślę, że istnieje wiele ukrytych wątków w sposobie rozstrzygania ścieżek własności dla wiązania.

+0

Dzięki Dan, to dobra informacja. – Phil

+1

Byłoby lepiej z kodem źródłowym. :) –

7

Wierzę, że ten drugi StackOverflow solution posted here może również pracować dla ciebie.

Skopiowany blok kodu w celach informacyjnych, przeczytaj oryginalny wpis, aby uzyskać więcej informacji od Thomasa 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

Dla ludzi, którzy w przyszłości natknąć się na to pytanie:

Kiedy .NET 4.5 będzie dostępny będzie miał szereg nowych właściwości na BindingExpression znacznie uprościć, czego szukasz.

ResolvedSource - Obiekt, który jest rzeczywiście związany, pomocne, gdy masz źródło wiążące, takie jak "grandparent.parent.me.Name". Zwróciłoby to obiekt "ja".

ResolvedSourcePropertyName - Nazwa właściwości w ResolvedSource, do której jest przypisany. W powyższym przypadku "Nazwa".

Podobnie będą właściwości Target i TargetName.

Dzięki tym właściwościom pomocniczym w BindingExpression można użyć krótszego i znacznie bardziej uproszczonego odbicia, które jest bardziej prawdopodobne w sytuacjach ekstremalnych (indeksatory).

+0

Czy wiesz, czy mimo to wymusić wyrażenie wiążące, aby zaktualizować te właściwości?Znajduję się w szczególnej sytuacji, w której klonuję wiązanie, gdy kontekst danych kontrolnych zmienia się i pobiera źródło z wyrażenia wiążącego, jednak właściwości te wydają się pozostawać puste, dopóki nie zmieni się zarówno właściwość, jak i kontekst danych zmienił zdarzenia. –

+0

@ AlexHopeO'Connor Potrafię interpretować pytania na wiele sposobów. Zalecam rozpoczęcie nowego pytania zamiast dodawać tutaj. –

2

Jak zauważył Dan Bryant, rozdzielczość PropertyPath jest ściśle powiązana z ogólną architekturą wiążącą.
Jeśli potrzebujesz dokładnie takiej samej rozdzielczości, jak robi to WPF, powinieneś prawdopodobnie użyć odpowiedzi Thomasa Levesque na pytanie this.

Jednakże, jeśli potrzebujesz ogólnej rozdzielczości ścieżki, możesz użyć tego, co stworzyłem.

Jest zasadniczo podobny do odpowiedzi Zhecha, ale bardziej wyrafinowany.

Jego główną metodą jest Resolve na klasie Resolver. Przekazywanie obiektu docelowego i jako ciągu zwraca żądany wynik.
Przykład:

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

Obsługuje również dostęp zbiórki pośrednictwem indeksu lub słowniku dostępu poprzez klucz.
Przykład ścieżki dla nich są:

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