Mam, ListBox
który wiąże się z kolekcją podrzędną w ViewModel. Elementy listy są stylizowane na tabliczce danych na podstawie właściwości w nadrzędnym modelu ViewModel:
<Style x:Key="curveSpeedNonConstantParameterCell">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=DataContext.CurveSpeedMustBeSpecified,
ElementName=someParentElementWithReferenceToRootDataContext}"
Value="True">
<Setter Property="Control.Visibility" Value="Hidden"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
Otrzymuję następujący błąd wyjściowy:
System.Windows.Data Error: 39 : BindingExpression path error:
'CurveSpeedMustBeSpecified' property not found on
'object' ''BindingListCollectionView' (HashCode=20467555)'.
BindingExpression:Path=DataContext.CurveSpeedMustBeSpecified;
DataItem='Grid' (Name='nonConstantCurveParametersGrid');
target element is 'TextBox' (Name='');
target property is 'NoTarget' (type 'Object')
Więc jeśli zmienię wyrażenie powiązania, aby "Path=DataContext.CurrentItem.CurveSpeedMustBeSpecified"
działało, ale tylko tak długo, jak kontekst danych nadrzędnej kontrolki użytkownika to BindingListCollectionView
. Jest to niedopuszczalne, ponieważ reszta formantu użytkownika wiąże się automatycznie z właściwościami elementu CurrentItem
on BindingList
.
Jak mogę określić wyrażenie wiążące wewnątrz stylu, aby działało niezależnie od kontekstu danych nadrzędnych będącego widokiem kolekcji lub pojedynczym elementem?
Możesz użyć,
RelativeSource
aby znaleźć element nadrzędny, na przykład:Zobacz to pytanie SO, aby uzyskać więcej informacji na temat
RelativeSource
.źródło
Mode=FindAncestor
, aby działał, ale to działa i jest znacznie lepsze w scenariuszu MVVM, ponieważ pozwala uniknąć kontroli nazewnictwa.Binding="{Binding Path=DataContext.CurveSpeedMustBeSpecified, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:YourParentElementType}}}"
RelativeSource a ElementName
Te dwa podejścia mogą przynieść ten sam wynik,
RelativeSrouce
Ta metoda wyszukuje formant Window typu (w tym przykładzie) w drzewie wizualnym, a gdy go znajdzie, w zasadzie można uzyskać dostęp do niego
DataContext
przy użyciuPath=DataContext....
. Zalety tej metody polegają na tym, że nie musisz być przywiązany do nazwy i jest to rodzaj dynamiki, jednak zmiany wprowadzone w drzewie wizualnym mogą wpłynąć na tę metodę i prawdopodobnie ją uszkodzić.ElementName
Ta metoda odnosi się do stałej statycznej,
Name
więc tak długo, jak twój zasięg może to zobaczyć, wszystko w porządku. Powinieneś trzymać się konwencji nazewnictwa, aby oczywiście nie łamać tej metody.Podejście jest dość proste i wystarczy określić aName="..."
dla twojego Window / UserControl.Chociaż wszystkie trzy typy (
RelativeSource, Source, ElementName
) mogą robić to samo, ale zgodnie z następującym artykułem MSDN, każdy z nich lepiej jest używany w swojej dziedzinie specjalizacji.Instrukcje: określanie źródła powiązania
Znajdź krótki opis każdego z nich oraz link do bardziej szczegółowych informacji w tabeli na dole strony.
źródło
Szukałem, jak zrobić coś podobnego w WPF i otrzymałem takie rozwiązanie:
Mam nadzieję, że to zadziała dla kogoś innego. Mam kontekst danych, który jest automatycznie ustawiany na ItemsControls, a ten kontekst danych ma dwie właściwości:
MyItems
-co jest kolekcją- i jedno polecenie „CustomCommand”. PonieważItemTemplate
używa aDataTemplate
,DataContext
górne poziomy nie są bezpośrednio dostępne. Następnie obejściem, aby uzyskać kontroler domeny rodzica, jest użycie ścieżki względnej i filtrowanie wedługItemsControl
typu.źródło
problem polega na tym, że DataTemplate nie jest częścią elementu, do którego został zastosowany.
oznacza to, że jeśli łączysz się z szablonem, wiążesz się z czymś, co nie ma kontekstu.
jednak jeśli umieścisz element wewnątrz szablonu, wtedy gdy ten element zostanie zastosowany do rodzica, uzyska on kontekst i powiązanie będzie działać
więc to nie zadziała
ale to działa doskonale
ponieważ po zastosowaniu arkusza danych groupbox jest umieszczany w nadrzędnym i będzie miał dostęp do jego kontekstu
więc wszystko, co musisz zrobić, to usunąć styl z szablonu i przenieść go do elementu w szablonie
zwróć uwagę, że kontekstem dla itemscontrol jest element, a nie element sterujący tj. ComboBoxItem dla ComboBox, a nie sam ComboBox w takim przypadku powinieneś zamiast tego użyć kontrolek ItemContainerStyle
źródło
Tak, możesz to rozwiązać za pomocą
ElementName=Something
sugestii Juve.ALE!
Jeśli element podrzędny (w którym używasz tego rodzaju powiązania) jest kontrolką użytkownika, która używa tej samej nazwy elementu, co określona w kontrolce nadrzędnej, wówczas powiązanie trafia do niewłaściwego obiektu !!
Wiem, że ten post nie jest rozwiązaniem, ale pomyślałem, że każdy, kto używa elementu ElementName w powiązaniu, powinien to wiedzieć, ponieważ jest to możliwy błąd w czasie wykonywania.
źródło