2013-04-01 11 views
7

Sono abbastanza nuovo per XAML ma mi diverto ad apprenderlo. La cosa con cui sto davvero combattendo è l'associazione di una proprietà a un elemento in un DataTemplate.XAML: Binding di una proprietà in un DataTemplate

Ho creato un semplice esempio WPF per, (si spera), spiegare il mio problema.

In questo esempio, sto tentando di associare la proprietà Visibility di un CheckBox a un DataTemplate a una proprietà nel mio viewmodel. (Utilizzando questo scenario esclusivamente per l'apprendimento/demo.)

Ho un DataModel semplice denominato Item, ma è di scarsa importanza in questo esempio.

class Item : INotifyPropertyChanged 
{ 

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

E un modello di visualizzazione abbastanza semplice denominato 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")); 
     } 

(Costruttori e INotifyPropertyChanged implementazione omesse per brevità.)

controlli disposti in MainPage.xaml come segue.

<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> 

La casella di controllo 'Nascondi caselle di controllo' è destinata a IsCheckBoxChecked e viene utilizzato per aggiornare IsCheckBoxVisible. Ho anche aggiunto un paio di controlli extra sotto lo DataTemplate per dimostrare (a me stesso) che tutto funziona.)

Ho anche implementato il convertitore di valore di Jeff Wilcox. (Grazie). http://www.jeff.wilcox.name/2008/07/visibility-type-converter/

Quando eseguo l'applicazione, selezionando e deselezionando la 'Nascondi Casella', controlli fuori la funzione DataTemplate come previsto, ma, ahimè, il Checkbox all'interno del modello di dati rimane invariato.

Ho avuto successo con:

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

Ma io non sto solo cercando imitare un altro controllo, ma prendere decisioni sulla base di un valore.

Mi piacerebbe davvero ricevere qualsiasi aiuto o consiglio che si possa offrire.

Grazie.

+0

Si rilevano errori di associazione nella finestra di output di debug in Visual Studio? Di solito sono una buona indicazione di cosa sta andando male. – ChrisF

+0

Chris. Grazie per la tua risposta. Controllate le finestre di output e, come sospettavate, c'erano errori. Non è stato possibile trovare IsCheckBoxVisible. Correzione applicata come da risposta di Duncan qui sotto e tutto bene ora. Grazie. – Dowse

risposta

15

Quando si è in un DataTemplate, DataContext è l'oggetto di modello di dati, in questo caso uno Item. Pertanto, DataContext del CheckBox nel DataTemplate è un Item, non il ItemViewModel. Puoi vedere questo dal tuo <TextBlock Text="{Binding ItemName}"/>, che si collega a una proprietà nella classe Item. Il collegamento a IsCheckBoxVisible sta tentando di trovare una proprietà denominata IsCheckBoxVisible su Item.

Ci sono un paio di modi per aggirare questo, ma di gran lunga il più semplice è di fare questo:

alla tua finestra (in XAML), dare e x: Name.Ad esempio:

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

Cambia il tuo legame con questo aspetto:

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

stiamo usando la finestra come sorgente per la rilegatura, poi guardando la sua proprietà DataContext (che dovrebbe essere il vostro ItemViewModel, e poi tirando fuori la proprietà IsCheckBoxVisible.

Un'altra opzione, se volete qualcosa di più elaborato, è quello di utilizzare un oggetto proxy per fare riferimento il vostro DataContext. Vedi this article on DataContextProxy.

+1

Duncan. Grazie per la pronta risposta. Ho provato il tuo suggerimento e ha funzionato come un fascino. Ho pensato di aggiungere un tag separato per la casella di controllo, ma purtroppo, no. Ancora una volta grazie. Darà a Dan Wahlin's atricle una lettura nel link che hai fornito. (Ho provato a votare la tua risposta, ma la mia scarsa reputazione mi impedisce di farlo.) – Dowse

+0

Felice di poterti aiutare! :-) Non è del tutto pertinente, ma solo a parte, dal tuo commento: l'impostazione manuale del DataContext di un elemento (eccetto la Finestra o un'altra radice) è qualcosa con cui vuoi essere molto attento, ed è spesso un segno che tu Stai facendo qualcosa di sbagliato. Sto immaginando che il tuo tentativo fosse sulla falsariga di '': in tal caso, il motivo per cui non funzionerebbe è quando definisci ItemViewModel in xaml come se tu stessi * creando * uno, quindi avresti un'istanza diversa. Puoi aggirare questo problema, ma la soluzione che ho descritto è migliore. –

Problemi correlati