Jak korzystać RelativeSource
z powiązań WPF i jakie są różne przypadki użycia?
.net
wpf
xaml
data-binding
relativesource
David Schmitt
źródło
źródło
AncestorType
.FindAncestor
, przedAncestorType
, pojawia się następujący błąd: „RelativeSource nie jest w trybie FindAncestor”. (W VS2013, wersja wspólnotowa){Binding Path=DataContext.SomeProperty, RelativeSource=...
. Dla mnie jako początkującego było to nieco nieoczekiwane, gdy próbowałem powiązać z obiektem DataContext rodzica w DataTemplate.Domyślnym atrybutem
RelativeSource
jestMode
właściwość. Pełny zestaw prawidłowych wartości znajduje się tutaj ( z MSDN ):PreviousData Umożliwia powiązanie poprzedniego elementu danych (nie formantu zawierającego element danych) z listy wyświetlanych elementów danych.
TemplatedParent Odnosi się do elementu, do którego stosuje się szablon (w którym istnieje element związany z danymi). Jest to podobne do ustawiania TemplateBindingExtension i ma zastosowanie tylko wtedy, gdy Powiązanie znajduje się w szablonie.
Self Odnosi się do elementu, na którym ustawia się wiązanie, i pozwala powiązać jedną właściwość tego elementu z inną właściwością tego samego elementu.
FindAncestor Odnosi się do przodka w łańcuchu macierzystym elementu związanego z danymi. Możesz użyć tego do powiązania z przodkiem określonego typu lub jego podklas. Jest to tryb, którego używasz, jeśli chcesz określić AncestorType i / lub AncestorLevel.
źródło
Oto bardziej wizualne wyjaśnienie w kontekście architektury MVVM:
źródło
{Binding Message}
(nieco prostsze ...)Path=DataContext.Message
aby wiązanie zadziałało. Ma to sens, biorąc pod uwagę, że można tworzyć powiązania względne do szerokości / wysokości / itp. kontroli.Bechir Bejaoui ujawnia przypadki użycia RelativeSources w WPF w swoim artykule tutaj :
źródło
ListView
. Rodzic ma jeszcze 2ListView
poziomy poniżej. To pomogło mi dopuścić do przeniesienia danych do każdego kolejnego VM każdegoListView
„sDataTemplate
W
RelativeSource
wiązaniu WPF ujawnia trzyproperties
do ustawienia:1. Tryb: To
enum
może mieć cztery wartości:2. AncestorType: kiedy tryb
FindAncestor
określa następnie typ przodka3. AncestorLevel: kiedy tryb jest
FindAncestor
wtedy na jakim poziomie przodka (jeśli są dwa takie same typy rodzicavisual tree
)Oto link referencyjny .
źródło
Nie zapomnij TemplatedParent:
lub
źródło
Warto zauważyć, że dla tych, którzy natkną się na myślenie o Silverlight:
Silverlight oferuje tylko ograniczony podzbiór tych poleceń
źródło
Utworzyłem bibliotekę, aby uprościć składnię powiązań WPF, w tym ułatwić korzystanie z RelativeSource. Oto kilka przykładów. Przed:
Po:
Oto przykład uproszczenia wiązania metod. Przed:
Po:
Bibliotekę znajdziesz tutaj: http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html
Zauważ, że w przykładzie „ZANIM”, którego używam do wiązania metody, kod został już zoptymalizowany przy użyciu tego,
RelayCommand
który ostatnio sprawdziłem, nie jest natywną częścią WPF. Bez tego przykład „PRZED” byłby jeszcze dłuższy.źródło
Kilka przydatnych fragmentów:
Oto jak to zrobić, głównie w kodzie:
W dużej mierze skopiowałem to z Binding Relative Source w kodzie Behind .
Ponadto strona MSDN jest całkiem dobra pod względem przykładów: Klasa RelativeSource
źródło
Właśnie opublikowałem inne rozwiązanie dostępu do DataContext elementu nadrzędnego w Silverlight, które działa dla mnie. Używa
Binding ElementName
.źródło
Nie przeczytałem każdej odpowiedzi, ale chcę tylko dodać tę informację w przypadku względnego powiązania przycisku polecenia źródłowego.
Gdy używasz źródła względnego z
Mode=FindAncestor
, powiązanie musi wyglądać następująco:Jeśli nie dodasz DataContext do swojej ścieżki, w czasie wykonywania nie będzie można pobrać właściwości.
źródło
To jest przykład użycia tego wzorca, który działał dla mnie na pustych siatkach danych.
źródło
Jeśli element nie jest częścią drzewa wizualnego, RelativeSource nigdy nie będzie działać.
W takim przypadku musisz wypróbować inną technikę, której pionierem jest Thomas Levesque.
Ma rozwiązanie na swoim blogu pod [WPF] Jak powiązać z danymi, gdy DataContext nie jest dziedziczony . I działa absolutnie genialnie!
W mało prawdopodobnym przypadku, gdy jego blog jest wyłączony, załącznik A zawiera kopię lustrzaną jego artykułu .
Nie komentuj tutaj, skomentuj bezpośrednio na jego blogu .
Dodatek A: Odbicie posta na blogu
Właściwość DataContext w WPF jest niezwykle przydatna, ponieważ jest automatycznie dziedziczona przez wszystkie elementy podrzędne elementu, do którego ją przypisujesz; dlatego nie musisz ustawiać go ponownie dla każdego elementu, który chcesz powiązać. Jednak w niektórych przypadkach DataContext nie jest dostępny: dzieje się tak w przypadku elementów, które nie są częścią drzewa wizualnego lub logicznego. Powiązanie właściwości z tymi elementami może być bardzo trudne…
Zilustrujmy prostym przykładem: chcemy wyświetlić listę produktów w DataGrid. W siatce chcemy mieć możliwość pokazywania lub ukrywania kolumny Cena na podstawie wartości właściwości ShowPrice ujawnionej przez ViewModel. Oczywistym podejściem jest powiązanie Widoczności kolumny z właściwością ShowPrice:
Niestety zmiana wartości ShowPrice nie ma wpływu, a kolumna jest zawsze widoczna… dlaczego? Jeśli spojrzymy na okno Output w Visual Studio, zauważymy następujący wiersz:
Możemy spróbować poprawić powiązanie, aby uzyskać pożądany wynik, na przykład ustawiając RelativeSource na samą siatkę danych:
Lub możemy dodać CheckBox związany z ShowPrice i spróbować powiązać widoczność kolumny z właściwością IsChecked, podając nazwę elementu:
Ale żadne z tych obejść nie wydaje się działać, zawsze uzyskujemy ten sam wynik…
W tym momencie wydaje się, że jedynym realnym podejściem byłaby zmiana widoczności kolumny z tyłu kodu, czego zwykle wolimy unikać, gdy używamy wzorca MVVM… Ale nie zamierzam się tak szybko poddawać, a przynajmniej nie podczas gdy istnieją inne opcje do rozważenia 😉
Rozwiązanie naszego problemu jest w rzeczywistości dość proste i wykorzystuje klasę Freezable. Głównym celem tej klasy jest zdefiniowanie obiektów, które mają stan modyfikowalny i tylko do odczytu, ale interesującą cechą w naszym przypadku jest to, że obiekty Freezable mogą dziedziczyć DataContext, nawet jeśli nie znajdują się w drzewie wizualnym lub logicznym. Nie znam dokładnego mechanizmu, który umożliwia takie zachowanie, ale wykorzystamy go, aby nasze wiążące działanie…
Chodzi o to, aby utworzyć klasę (nazwałem ją BindingProxy z powodów, które powinny wkrótce stać się oczywiste), która dziedziczy Freezable i deklaruje właściwość zależności danych:
Następnie możemy zadeklarować wystąpienie tej klasy w zasobach DataGrid i powiązać właściwość Data z bieżącym DataContext:
Ostatnim krokiem jest określenie tego obiektu BindingProxy (łatwo dostępnego w StaticResource) jako źródła powiązania:
Zauważ, że ścieżka wiązania została poprzedzona przedrostkiem „Data”, ponieważ ścieżka jest teraz względna do obiektu BindingProxy.
Powiązanie działa teraz poprawnie, a kolumna jest poprawnie wyświetlana lub ukryta na podstawie właściwości ShowPrice.
źródło