Reputation: 8338
It’s about the MSDN article of Josh Smith on MVVM and the sample application. I know there are lots of question on SO about this topic, and I’ve explored them all. Most of them are focused on MVVM, but my issue is, I think, more XAML related than MVVM.
The sample application contains the following XAML for the Workspaces area -
<Border Grid.Column="2" Style="{StaticResource MainBorderStyle}">
<ContentControl Content="{Binding Path=Workspaces}" ContentTemplate="{StaticResource ResourceKey=WorkspacesTemplate}"/>
</Border>
and the related resources are -
//Explains how to render the 'Workspace' content area in the main window
<DataTemplate x:Key="WorkspacesTemplate">
<TabControl Margin="4" ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"
ItemTemplate="{StaticResource ResourceKey=ClosableTabItemTemplate}"/>
</DataTemplate>
//Explains how to render a tab item with a close button
<DataTemplate x:Key="ClosableTabItemTemplate">
<DockPanel Width="120">
<Button Command="{Binding Path=CloseCommand}" Content="X" Cursor="Hand"
DockPanel.Dock="Right" Focusable="False" FontFamily="Courier"
FontSize="9" FontWeight="Bold" Margin="0,1,0,0" Padding="0"
VerticalContentAlignment="Bottom" Width="16" Height="16"/>
<ContentPresenter Content="{Binding Path=DisplayName}" VerticalAlignment="Center"/>
</DockPanel>
</DataTemplate>
What I still don't understand -
ItemsSource="{Binding}"
should bind the ItemsSource directly to the TabControl’s DataContext, rather than to any of the DataContext’s properties. But where exactly is the TabControl’s DataContext being set?Content="{Binding Path=Workspaces}"
creating a binding between ItemsSource of the TabControl and the Workspaces (the ObservableCollection of WorkspaceViewModel)?Content
property of a TabItem
receives a ViewModelBase-derived object to display. How ?!? Ok, through data binding. But that is just too much to abstract away, for me. In general I’m missing the way binding is flowing/working through these two resources behind the scene
to load the Views in the TabItems. To me it's like, what is causing what to be bound to what.
This legendary article and the sample application is something extremely useful for WPF/MVVM beginners. But it’s not much elaborative. I myself have learned using MVVM with this one. I think there is and will be some others like me. So, can anyone explain the binding sequences a little bit more elaborately please?
Relevant Note :
May be it'll give you a hint of what I already know in this context, and help you in answering. I'm a beginner level WPF application developer. With my not so good knowledge on XAML -
DataTemplate
of displaying the View when the ViewModel type occurs, and then setting the ViewModel as the DataContext of that ViewUpvotes: 3
Views: 1223
Reputation: 22445
"But where exactly is the TabControl’s DataContext being set?" Workspaces is the DataContext and so the Itemssource for the TabControl.
<ContentControl Content="{Binding Path=Workspaces}" ContentTemplate="{StaticResource ResourceKey=WorkspacesTemplate}"/>
"How exactly is Content="{Binding Path=Workspaces}" creating a binding between ItemsSource of the TabControl and the Workspaces (the ObservableCollection of WorkspaceViewModel)?" Workspaces are the DataContext for the DataTemplate/TabControl and the ItemsSource is set to the DataContext.
<TabControl Margin="4" ItemsSource="{Binding}"
"The article says By relying on data binding, the Content property of a TabItem receives a ViewModelBase-derived object to display. How ?!?" i dont know the article, but i assume that Workspaces is a collection of object derived from ViewModelBase. every tabitem represent on item from the collection and so a viewmodelbase-derived object.
Upvotes: 0
Reputation: 178660
The syntax ItemsSource="{Binding}" should bind the ItemsSource directly to the TabControl’s DataContext, rather than to any of the DataContext’s properties. But where exactly is the TabControl’s DataContext being set?
By virtue of being a data template, the TabControl
will have its DataContext
set (by WPF) to the data item it is templating. In fact, the root-level item in the data template will have its DataContext
set by WPF. In this case, it's a TabControl
.
Since the data template is assigned to the ContentControl
's ContentTemplate
property, it will automatically receive the ContentControl
's Content
as its DataContext
.
How exactly is Content="{Binding Path=Workspaces}" creating a binding between ItemsSource of the TabControl and the Workspaces (the ObservableCollection of WorkspaceViewModel)?
I think my previous answer addresses this, but let me re-state it in a form that directly answers this question. The binding on the ContentControl
ensures that the DataContext
for the DataTemplate
is set to the workspace collection. Thus, the TabControl
can bind to the workspace collection by specifying a Binding
without a Path
.
The article says By relying on data binding, the Content property of a TabItem receives a ViewModelBase-derived object to display. How ?!? Ok, through data binding. But that is just too much to abstract away, for me.
Again, this comes down to WPF automatically assigning the correct object as the data context of the generated item (a TabItem
in this case). When an ItemsControl
(such as TabControl
) is bound to a collection, it generates a container (a TabItem
in this case) for each item in the bound collection. The container automatically receives the data item (a workspace view model in this case) as its data context.
Upvotes: 3