2010-04-18 14 views
5

Próbuję uzyskać moją pierwszą aplikację WPF działającą przy użyciu MVVM, a ja mam mały problem wiążący.WPF: Ustawianie DataContext UserControl z Binding nie działa w XAML

Konfiguracja jest, że mam widok & ViewModel, które posiada dane użytkownika (rodzica) i spróbować zachować rzeczy proste Wrzuciłem fragment tego widoku w osobnym widoku & ViewModel (dziecka). Widok podrzędny definiowany jest jako UserControl.

Problem, który mam, polega na ustawianiu DataContext widoku podrzędnego (UserControl). Mój rodzic ViewModel ma właściwość, która odsłania dziecko ViewModel, jak tak:

class ParentViewModel: INotifyPropertyChanged 
{ 
    public ChildViewModel childViewModel { get; set; } 
    //... 
} 

W XAML dla mojego widzenia dominującej (która jest DataContext zestaw do ParentViewModel), staram się ustawić DataContext widoku dziecięcej w następujący sposób:

<views:ChildView 
    x:Name="ChildView" 
    DataContext="{Binding childViewModel}"/> 

To jednak nie działa. DataContext widoku podrzędnego jest ustawiony na ten sam obiekt DataContext, co widok nadrzędny (tzn. ParentViewModel), tak jakbym go w ogóle nie ustawiał. Próbowałem również ustawić DataContext w widoku podrzędnym, który również nie działa:

<UserControl x:Class="DietRecorder.Client.View.ChildView" 
    DataContext="childViewModel" 

Znalazłem kilka sposobów obejścia tego. Z punktu widzenia dziecka, mogę związać wszystko o tym ChildViewModel w ścieżce:

<SomeControl Visibility="{Binding Path=childViewModel.IsVisible}"> 

ale nie chcę widok dziecko mieć ten poziom świadomości hierarchii. Ustawianie DataContext w kodzie również działa - jednak muszę to zrobić po okazaniu widoku rodzica, inaczej DataContext tylko zostaną nadpisane gdy zgłoszę show():

parentView.Show(); 
parentView.ChildView.DataContext = parentViewModel.childViewModel; 

Kod ten sprawia również, że czuję się nieswojo, co z naruszeniem LOD i wszystkim.

To tylko DataContext, który wydaje się być problemu - można powiązać inne rzeczy dziecka, na przykład próbowałem wiązania fontSize do własności int tylko, aby go przetestować:

<views:ChildView 
    x:Name="ChildView" 
    FontSize="{Binding Path=someVal}"/> 

i że działa w porządku.

Ale jestem pewien, że powiązanie DataContext powinno działać - widziałem podobne przykłady tego typu rzeczy. Czy przegapiłem coś oczywistego tutaj? Czy istnieje powód, dla którego to nie zadziała? Czy gdzieś jest błąd w pisowni? (Zmieniłem nazwę rzeczy na twoją korzyść, więc i tak nie będziesz w stanie mi pomóc).

Wszelkie przemyślenia mile widziane.

Edit

ponownie Przegląd ten kod, wydaje się, mam gdzieś popełnił błąd, co ilustruje poniższy XAML w widoku macierzystego ma teraz wydaje się działać:

<views:ChildView 
    x:Name="ChildView" 
    DataContext="{Binding childViewModel}"/> 

jestem nie wiem, dlaczego nie mogłem go uruchomić oryginalnie, lub co mogłem zmienić, aby działało. Być może był to problem INOTifyPropertyChanged, jak sugeruje jedna z odpowiedzi. No cóż, w przód iw górę ...

Odpowiedz

2

Podejrzewam, że tak jest, ponieważ właściwość childViewModel nie podnosi zdarzenia PropertyChanged. Po dokonaniu oceny powiązania jest możliwe, że ta właściwość ma wartość NULL (w takim przypadku obiekt DataContext po prostu wróci do obiektu macierzystego). Gdy obiekt childViewModel zostanie utworzony później, żadne zdarzenie PropertyChanged nie zostanie podniesione, a powiązanie nigdy nie zostanie poinformowane, że istnieje teraz obiekt DataContext.

Spróbuj podnieść zdarzenie PropertyChanged w właściwości childViewModel.

Cheers, Laurent

+0

Dobre myślenie, ale bez radości, obawiam się. Myślałem, że może to mieć coś wspólnego z zamówieniem, ale viewModel podrzędny powinien być dostępny, gdy dojdzie do powiązania - i działa, gdy ustawię rozmiar czcionki za pomocą właściwości int, co dzieje się w tym samym czasie, a to nie robi ". t użyć PropertyChanged. –

2

szukałem tej samej rzeczy i znalazłem jeden sposób to zrobić. Zasadniczo związany DataContext dziecka do DataContext jakiegoś nadrzędnego (okna) za pomocą

DataContext="{Binding ElementName=_topLevel, Path=DataContext.childViewModel}" 

gdzie mam ustawić x:Name="_topLevel" na jakiejś kontroli macierzystego (okna).

Próbowałem użyć RelativeSource/FindAncestor zamiast elementu ElementName, ale nie zadziałało - ale to była prawdopodobnie moja wina.

Czuję się jak włamać się do mnie, ale lepiej niż wiązania do modelu widoku najwyższego poziomu.

+0

Chociaż tego nie próbowałem, to powinno zadziałać, więc dam ci +1 za wysiłek po tym wszystkim - ale to rozwiązanie ma ten sam problem co jedno z rozwiązań, które zasugerowałem powyżej, czyli że dziecko wie o rodzicu. Jest to po prostu nieprzyjemny zapach lub prawdziwy problem, w zależności od tego, czy używasz dziecka w różnych widokach rodzica, czy nie. Podczas sprawdzania kodu dla tej odpowiedzi, odkryłem, że teraz działa, chociaż nie mam pewności, dlaczego - patrz edycja dla szczegółów. –

2

To nie jest odpowiedź na pytanie, ale może pomóc innym w tych samych okolicznościach.

Uderzyłem dokładnie ten problem i okazało się, że podejście

parentView.ChildView.DataContext = parentViewModel.childViewModel; 

pracował (choć znalazłem, że pracował wcześniej robi show()), ale miał takie same skrupułów o tym jak oryginał pytający więc próbowaliśmy

DataContext="{Binding ElementName=_topLevel, Path=DataContext.childViewModel}" 

podejście, które również wydawało się działać. Ale potem spróbowałem ponownie wrócić do oryginalnego kodu i oryginalnego XAML, a teraz nagle zadziałało. Odzwierciedla to zachowanie pierwotnego pytającego, gdzie autor pomyślał, że popełnili gdzieś błąd, ponieważ wydawało się, że XAML zaczyna działać bez oczywistego powodu.

Jedyną zmianą jaką widzę jest to, że Visual Studio wyświetla teraz przykładowe dane w UserControl w czasie projektowania, więc zbuforowane niektóre próbki danych gdzieś i wydaje się, że to działa. Nie jestem pewien, która z tych dwóch zmian spowodowała to niestety.

Pojawienie się przykładowych danych sprawia, że ​​zastanawiam się, czy problem jest związany z użyciem d: DataContext, które mam w macierzystym i podrzędnym pliku XAML, ale to tylko spekulacja.

Powiązane problemy