XAML: property binding in a DataTemplate

I am new to XAML but enjoy learning this. The thing I'm really struggling with is associating a property with an element in a DataTemplate .

I created a simple WPF example to (hopefully) explain my problem.

In this example, I am trying to associate the Visibility property of a CheckBox in a DataTemplate with a Property in my viewmodel. (Use of this script is for training / demonstration purposes only.)

I have a simple DataModel named Item , but it is not significant in this example.

 class Item : INotifyPropertyChanged { // Fields... private bool _IsRequired; private string _ItemName; 

And a pretty simple view model called 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")); } 

(The constructors and implementation of INotifyPropertyChanged are omitted for brevity.)

The controls described in MainPage.xaml are as follows.

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

The Hide CheckBoxes IsCheckBoxChecked box is linked to IsCheckBoxChecked and is used to update IsCheckBoxVisible . I also added a few additional controls under the DataTemplate to prove (for myself,) that everything works.)

I also used the Jeff Wilcox value converter. (Thanks.) Http://www.jeff.wilcox.name/2008/07/visibility-type-converter/

When I launch the application, checking and unchecking the "Hide checkbox" checkbox, it controls the outside of the DataTemplate function as expected, but, alas, the CheckBox inside the data template remains unchanged.

I had success:

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

But I'm not just trying to mimic another control, but make decisions based on value.

I would REALLY appreciate any help or advice you can offer.

Thanks.

+7
source share
1 answer

When you are in a DataTemplate, your DataContext is a data template, in this case Item . So the DataContext CheckBox in the DataTemplate is an Item , not your ItemViewModel . You can see this with <TextBlock Text="{Binding ItemName}"/> , which binds to the property of the Item class. The binding to IsCheckBoxVisible is trying to find a property called IsCheckBoxVisible on Item .

There are several ways around this, but the simplest is this:

In your window (in xaml) give it x: Name as well. For example:

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

Change the binding to look like this:

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

We use Window as a binding source, and then look at its DataContext property (this should be your ItemViewModel , and then pull out the IsCheckBoxVisible property.

Another option, if you want something more interesting, is to use a proxy object to link to your DataContext. See this article on DataContextProxy .

+15
source

All Articles