Reputation: 140753
I continue my understanding of MVVC with the code of MSDN and I have a question.
In the .xaml they have a list of commands displayed to the screen.
<Border
Grid.Column="0"
Style="{StaticResource MainBorderStyle}"
Width="170"
>
<HeaderedContentControl
Content="{Binding Path=Commands}"
ContentTemplate="{StaticResource CommandsTemplate}"
Header="Control Panel"
Style="{StaticResource MainHCCStyle}"
/>
</Border>
From here, I understand that the DataContext is set (not shown here) and it will display the collection of Commands. What I do not understand is the CommandsTemplate that you can see below:
<DataTemplate x:Key="CommandsTemplate">
<ItemsControl IsTabStop="False" ItemsSource="{Binding}" Margin="6,2">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Margin="2,6">pou
<Hyperlink Command="{Binding Path=Command}">
<TextBlock Text="{Binding Path=DisplayName}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
How does the binding is created? How this code tell to check the property Command and DisplayName from the object inside the collection? Is it from the ItemsSource? If yes, I do not understand why it's only at {Binding}. Anyone can explain me please how the DataTemplate binding work from a ContentTemplate?
Upvotes: 6
Views: 32000
Reputation: 4994
Example:
XAML
<Window x:Class="WpfApplication2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" Loaded="Window_Loaded">
<Window.Resources>
<DataTemplate x:Key="CommandsTemplate">
<ItemsControl IsTabStop="False" ItemsSource="{Binding}" Margin="6,2">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Margin="2,6">pou
<Hyperlink Command="{Binding Path=Command}">
<TextBlock Text="{Binding Path=DisplayName}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<Grid>
<Border Width="170">
<HeaderedContentControl
Content="{Binding Path=Commands}"
ContentTemplate="{StaticResource CommandsTemplate}"
Header="Control Panel"/>
</Border>
</Grid>
</Window>
C#
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window {
public Window1() {
InitializeComponent();
Commands.Add(new Commander() { DisplayName = "DN1" });
Commands.Add(new Commander() { DisplayName = "DN2" });
Commands.Add(new Commander() { DisplayName = "DN3" });
this.DataContext = this;
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
}
private ObservableCollection<Commander> commands = new ObservableCollection<Commander>();
public ObservableCollection<Commander> Commands {
get { return commands; }
set { commands = value; }
}
}
public class Commander {
public ICommand Command { get; set; }
public string DisplayName { get; set; }
}
Upvotes: 2
Reputation: 4994
As you said, the DataContext is set to the ViewModel class so the control that you mentioned in XAML will be able to access the public properties of that ViewModel.
For example:
private ObservableCollection<Commander> commands = new ObservableCollection<Commander>();
public ObservableCollection<Commander> Commands {
get { return commands; }
set { commands = value; }
}
The structure of Commander class.
public class Commander {
public ICommand Command { get; set; }
public string DisplayName { get; set; }
}
That VM has the property called Commands which might be ObservableCollection. This property can be accessible from XAML.
You can imagine that HeaderedContentControl is a container. The content of that HeaderedContentControl is a DataTemplate "CommandsTemplate" that has a ItemsControl and it bind to the Commands property of VM.
Content="{Binding Path=Commands}"
And then, you can to bind ItemControl with Commands again but that ItemControl is inside the content that bind to Commands. So you don't need to specify the path again. You can just use
ItemsSource="{Binding}" instead of ItemsSource="{Binding Commands}".
Two textblocks are inside ItemControl so they are at the same level as Commander class of Commands ObservableCollection. That's why you can access Text="{Binding Path=DisplayName}" directly.
Hope it helps.
Upvotes: 9
Reputation: 46555
The ItemsSource binding to {Binding} binds directly to the DataContext of the ItemsControl (which will look up the chain until it finds a set DataContext). In this case it has been set in the HeaderedContentControl
Each item inside the ItemsControl will then have its DataContext set to an element in the list.
The <ItemsControl.ItemTemplate>
is setting the template for each Item inside the list, not for the ItemsControl itself. So that {Binding Path=Command}
and {Binding Path=DisplayName}
will look at those properties on the elements inside the list.
Upvotes: 1