2013-04-01 15 views
7

Jestem całkiem nowym użytkownikiem XAML, ale czerpię przyjemność z nauki. Rzeczą, z którą naprawdę walczę jest wiązanie właściwości elementu w DataTemplate.XAML: Wiązanie właściwości w DataTemplate

Stworzyłem prosty przykład WPF, aby (mam nadzieję) wyjaśnić mój problem.

W tym przykładzie próbuję powiązać właściwość Visibility z CheckBox w DataTemplate z właściwością w moim modelu widokowym. (Używając tego scenariusza wyłącznie do nauki/demonstracji.)

Mam prosty model danych o nazwie Item, ale ma on niewielkie znaczenie w tym przykładzie.

class Item : INotifyPropertyChanged 
{ 

    // Fields... 
    private bool _IsRequired; 
    private string _ItemName; 

A dość prosty model widoku o nazwie ItemViewModel.

class ItemViewModel : INotifyPropertyChanged 
{ 
    private ObservableCollection<Item> _Items; 
    private bool _IsCheckBoxChecked; 
    private bool _IsCheckBoxVisible; 

    public ObservableCollection<Item> Items 
    { 
     get { return _Items; } 
     set { _Items = value; } 
    } 


    public bool IsCheckBoxChecked 
    { 
     get { return _IsCheckBoxChecked; } 
     set 
     { 
      if (_IsCheckBoxChecked == value) 
       return; 
      _IsCheckBoxChecked = value; 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs("IsCheckBoxChecked")); 
       PropertyChanged(this, new PropertyChangedEventArgs("IsCheckBoxVisible")); 
      } 
     } 
    } 


    public bool IsCheckBoxVisible 
    { 
     get { return !_IsCheckBoxChecked; } 
     set 
     { 
      if (_IsCheckBoxVisible == value) 
       return; 
      _IsCheckBoxVisible = value; 
      if (PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs("IsCheckBoxVisible")); 
     } 

(Konstruktorzy i INotifyPropertyChanged realizacja pominięte dla zwięzłości.)

Kontrole określone w MainPage.xaml następująco.

<Window.Resources> 
    <local:VisibilityConverter x:Key="VisibilityConverter"/> 
</Window.Resources> 

<Window.DataContext> 
    <local:ItemViewModel/> 
</Window.DataContext> 

<Grid> 
    <StackPanel> 
     <CheckBox x:Name="checkBox" Content="Hide CheckBoxes" FontSize="14" IsChecked="{Binding IsCheckBoxChecked, Mode=TwoWay}" /> 
     <ListView ItemsSource="{Binding Items}" HorizontalContentAlignment="Stretch" > 
      <ListView.ItemTemplate > 
      <DataTemplate> 
       <Grid> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="*"/> 
         <ColumnDefinition Width="Auto"/> 
        </Grid.ColumnDefinitions> 
        <TextBlock Text="{Binding ItemName}"/> 
         <CheckBox Grid.Column="1" Visibility="{Binding IsCheckBoxVisible, Converter={StaticResource VisibilityConverter}}" > 
          <CheckBox.DataContext> 
           <local:ItemViewModel/> 
          </CheckBox.DataContext> 
         </CheckBox> 
        </Grid> 
      </DataTemplate> 
     </ListView.ItemTemplate> 
    </ListView> 
     <StackPanel Orientation="Horizontal" Margin="4,4,0,0"> 
     <TextBlock Text="IsCheckBoxVisible:"/> 
      <TextBlock Text="{Binding IsCheckBoxVisible}" Margin="4,0,0,0" FontWeight="Bold" /> 
     </StackPanel > 
     <Button Content="Button" Visibility="{Binding IsCheckBoxVisible, Converter={StaticResource VisibilityConverter}}" Margin="4,4,4,4"/> 
    </StackPanel> 

</Grid> 

pole wyboru „Ukryj pola wyboru” jest zobowiązany do IsCheckBoxChecked i służy do aktualizacji IsCheckBoxVisible. Dodałem także kilka dodatkowych elementów sterujących poniżej DataTemplate, aby udowodnić (samemu), że wszystko działa.)

Zaimplementowałem także konwerter wartości Jeffa Wilcoxa. (Dziękuję.) http://www.jeff.wilcox.name/2008/07/visibility-type-converter/

Kiedy uruchomić aplikację, sprawdzając i odznaczając pole „Ukryj”, kontrole poza funkcją DataTemplate jak oczekiwano, ale, niestety, Checkbox wewnątrz szablonu danych pozostaje niezmieniona.

miałem sukces:

IsVisible="{Binding IsChecked, Converter={StaticResource VisibilityConverter}, ElementName=checkBox}" 

Ale nie tylko próbuje naśladować inną kontrolę, ale podejmować decyzje w oparciu o wartości.

NAPRAWDĘ doceniam każdą pomoc lub poradę, którą możesz zaoferować.

Dziękuję.

+0

Czy występują błędy wiązania w oknie wyników debugowania w programie Visual Studio? Zazwyczaj są one dobrym wskaźnikiem tego, co dzieje się źle. – ChrisF

+0

Chris. Dziękuję za odpowiedź. Sprawdzono okna wyjściowe i, jak podejrzewasz, wystąpiły błędy. Nie może "znaleźć" IsCheckBoxVisible. Zastosowana poprawka zgodnie z odpowiedzią Duncana poniżej i wszystko dobrze teraz. Dziękuję Ci. – Dowse

Odpowiedz

15

Podczas korzystania z DataTemplate, DataContext jest obiektem szablonowym danych, w tym przypadku Item. Tak więc DataContext CheckBox w DataTemplate to Item, a nie Twój ItemViewModel. Możesz to zobaczyć pod swoim numerem <TextBlock Text="{Binding ItemName}"/>, który wiąże się z właściwością klasy Item. Wiązanie z IsCheckBoxVisible próbuje znaleźć właściwość o nazwie IsCheckBoxVisible na Item.

Istnieje kilka sposobów obejścia tego, ale zdecydowanie najłatwiej jest to zrobić:

Na Oknie (w XAML), daje to i x: Name.Np:

<Window [...blah blah...] 
     x:Name="MyWindow"> 

zmienić wiązanie się wyglądać następująco:

<CheckBox Grid.Column="1" 
      Visibility="{Binding DataContext.IsCheckBoxVisible, ElementName=MyWindow, Converter={StaticResource VisibilityConverter}}"> 

Używamy okna jako źródła dla wiązania, to patrząc na jego właściwości DataContext (który powinien mieć swój ItemViewModel, a następnie ściągając właściwość IsCheckBoxVisible.

Inną opcją, jeśli chcesz coś bardziej wyszukane, jest użycie obiektu proxy odwołać swój DataContext. Zobacz this article on DataContextProxy.

+1

Duncan. Dziękuję za szybką odpowiedź. Próbowałem twojej sugestii i działało jak czar. Myślałem, że dodanie oddzielnego znacznika dla tego pola wyboru będzie działać, ale niestety, nie. Jeszcze raz Ci dziękuję. Da Wam Danowi atricle przeczytać w link, który podałeś. (Próbowałem głosować na twoją odpowiedź, ale moja niska reputacja przeszkadza mi to zrobić.) – Dowse

+0

Cieszę się, że mogę pomóc! :-) Nie jest to całkowicie istotne, ale tak na marginesie, z twojego komentarza: ręczne ustawienie Kontekstu danych elementu (z wyjątkiem Okna lub innego katalogu głównego) jest czymś, z czym chcesz być bardzo ostrożnym i często jest znakiem, że "Robię coś źle. Wyobrażam sobie, że twoja próba była podobna do '': jeśli tak, to powód, dla którego to nie zadziałałoby, jest taki, że definiujesz ItemViewModel w Xaml, tak jak tworzysz * * jeden, więc będziesz miał inną instancję. Możesz obejść to, ale rozwiązanie, które opisałem, jest lepsze. –