WPF DataTemplate ContentPresenter "Binding" - wpf

Can someone explain me how the code I am using here can work?
<Window.Resources>
<DataTemplate DataType="{x:Type VM:PBRKEntryViewModel}">
<V:Overview />
</DataTemplate>
<DataTemplate DataType="{x:Type VM:LoginViewModel}">
<V:LoginView />
</DataTemplate>
</Window.Resources>
<Grid>
<ContentPresenter Content="{Binding CurrentView}"/>
</Grid>
My current problems in Details are:
Why can the ContentPresenter present the correct UserControl without Reference to the different DataTemplates? I can see, that ContentPresenter content is bound to my ViewModels CurrentViewProperty but my DataTemplates not?
Another great feature is that the UserControls using the correct ViewModels without a declaration. (Or without a declaration I can see)
I have found this description http://msdn.microsoft.com/en-us/library/System.Windows.Controls.ContentPresenter(v=vs.110).aspx but the remarks section has no answer to this questions. (Or I couldn´t see them...)
Again and just for clarity everything is working perfect, but I do not understand why, so this is just a question to understand the Selection of the template and the Binding.

DateTemplates that specify a DataType property are automatically applied to any instance of that type in the view. It's just a way to tell WPF "every time you need to display this type, use this template"
Your ContentPresenter has its Content bound to some object. If that object type has a matching template, then WPF will use it.

Under the remarks section of the link you posted it's clear enough with this statement:
If there is a DataTemplate associated with the type of Content, the
ContentPresenter applies that DataTemplate to the Content property and
the resulting UIElement and its child elements, if any, are displayed.
Also, if you want to know how dataTemplates are picked automatically, you can read about it here - Data Templating Overview.
Quote from the link:
The DataTemplate class has a DataType property that is very similar to
the TargetType property of the Style class. DataTemplate gets applied
automatically to all objects associated with underlying type.
This is something similar to Styles. If you doesn't specify any x:Key on your Style it will be applied automatically to all child elements falling under the root element where resource is defined.
As soon as you set x:Key on Style, it is no more a default style and will be applied only to the elements explicitly setting style to this resource.
Same holds true for DataTemplate as well. When you specify DataType only, it becomes default template to represent underlying data type. Explicitly specifying x:Key will break this feature.

Related

DataTemplate vs ItemContainerTemplate

What is ItemContainerTemplate used for? It is derived from DataTemplate, but I don't see any difference between them except the ItemContainerTemplateKey property. When should I use one and when the other?
The only difference between DataTemplate and ItemContainerTemplate is the way the resource dictionary key is automatically provided (assuming it is not set explicitly). Namely, DataTemplate is decorated with [DictionaryKeyProperty("DataTemplateKey")] attribute, and the DataTemplateKey is basically defined as:
public object DataTemplateKey
{
get { return (DataType != null) ? new DataTemplateKey(DataType) : null;
}
See DataTemplate source for reference.
ItemContainerTemplate derives from DataTemplate, but is decorated with [DictionaryKeyProperty("ItemContainerTemplateKey")] attribute (which in practice replaces the inherited one), and ItemContainerTemplateKey property is defined as follows:
public object ItemContainerTemplateKey
{
get { return (DataType != null) ? new ItemContainerTemplateKey(DataType) : null; }
}
See ItemContainerTemplate source for reference.
The difference seems small - DataTemplate returns an instance of DataTemplateKey and ItemContainerTemplate returns an instance of ItemContainerTemplateKey (both derive from TemplateKey). So basically these two are equivalent1:
<ItemContainerTemplate DataType="{x:Type sys:String}" />
<DataTemplate x:Key="{ItemContainerTemplateKey {x:Type sys:String}}" />
and so are these:
<ItemContainerTemplate x:Key="{DataTemplateKey {x:Type sys:String}}" />
<DataTemplate DataType="{x:Type sys:String}" />
The main practical difference between these two is that DataTemplate with default key is treated as an implicit template2, whereas ItemContainerTemplate is not. In fact, you need to manually reference it, e.g.:
<ListBox ItemTemplate="{StaticResource {ItemContainerTemplate {x:Type sys:String}}}" />
I'm not sure about the intentions behind creating ItemContainerTemplate class. I guess it gives you a clearer overview of the code, where you know that such a template is specifically intended to be used in an ItemsControl (or a derived control). Also, I guess it would prove to be pretty simple to write a strongly reusable DataTemplateSelector that would take advantage of this class.
1 They're not equivalent in the sense that created objects are of different types, but functionally they're equivalent.
2 Implicit templates are applied to all objects of corresponding type within the scope, unless a template is set explicitly.
The ItemContainerTemplate describes the world around your Item. For example in a ListBox the selection rectangle around your ListBoxItem. The DataTemplate describes how you ListBoxItem apears and of which elements it consists.
Dr. WPF did a good example:
http://drwpf.com/blog/category/item-containers/
You can put an ItemContainerTemplate in a ResourceDictionary, and it will automatically use the DataType as its key.
That's the only difference.
ItemContainerTemplate is useful/necessary when you need different Item containers for an ItemsControl.
Usually the XAML infracstructure decides which item container is used for a given ItemsControl:
ListBox uses ListBoxItem
DataGrid uses DataRow
ComboBox uses ComboBoxItem
Menu uses MenuItem
As for a Menu you would sometimes want a Separator (which is not a MenuItem technically)
That's where ItemContainerTemplate, ItemContainerTemplateSelector and ItemContainerTemplatekey come into play.
Based on the viewmodel/datacontext type or one/many of its property values you can switch between a Separator in an ItemContainerTemplate and a MenuItem in another
ItemContainerTemplate.
You may use triggers or a ItemContainerTemplateSelector to achieve this.
Actually and honestly I am myself just now about to understand what the ItemContainerTemplateKey is for.
I think to have understood that it's an easy way to map an ItemContainerTemplate to a data type without the need for a Selector or code behind or triggers.
If you're fine with the default ItemContainerTemplate you simply don't need to deal with it in your XAML. Manipulating the ItemsContainer style can be achieved within the ItemContainerTemplate. Having a custom DataTemplate to bind your data (and also to style it) is done within the ItemTemplate.
Usage of ItemContainerTemplate is rarely needed. But sometimes very handy.
You could check that Link to see the difference between controltemplate and datatemplate and hierarchicaldatatemplate itemspaneltemplate:
http://nirajrules.wordpress.com/2009/03/08/controltemplate-vs-datatemplate-vs-hierarchicaldatatemplate-vs-itemspaneltemplate/

How do you navigate a complex Visual Tree in order to re-bind an existing element?

In the above image, child is a ContentPresenter. Its Content is a ViewModel. However, its ContentTemplate is null.
In my XAML, I have a TabControl with the following structure:
<local:SuperTabControlEx DataContext="{Binding WorkSpaceListViewModel}"
x:Name="superTabControl1" CloseButtonVisibility="Visible" TabStyle="OneNote2007" ClipToBounds="False" ContentInnerBorderBrush="Red" FontSize="24" >
<local:SuperTabControlEx.ItemsSource>
<Binding Path="WorkSpaceViewModels" />
</local:SuperTabControlEx.ItemsSource>
<TabControl.Template>
<ControlTemplate
TargetType="TabControl">
<DockPanel>
<TabPanel
DockPanel.Dock="Top"
IsItemsHost="True" />
<Grid
DockPanel.Dock="Bottom"
x:Name="PART_ItemsHolder" />
</DockPanel>
<!-- no content presenter -->
</ControlTemplate>
</TabControl.Template>
<TabControl.Resources>
<DataTemplate DataType="{x:Type vm:WorkSpaceViewModel}">
....
WorkSpaceViewModels is an ObservableCollection of WorkSpaceViewModel. This code uses the code and technique from Keeping the WPF Tab Control from destroying its children.
The correct DataTemplate - shown above in the TabControl.Resource - appears to be rendering my ViewModel for two Tabs.
However, my basic question is, how is my view getting hooked up to my WorkSpaceViewModel, yet, the ContentTemplate on the ContentPresenter is null? My requirement is to access a visual component from the ViewModel because a setting for the view is becoming unbound from its property in the ViewModel upon certain user actions, and I need to rebind it.
The DataTemplate is "implicitly" defined. The ContentPresenter will first use it's ContentTemplate/Selector, if any is defined. If not, then it will search for a DataTemplate resource without an explicit x:Key and whose DataType matches the type of it's Content.
This is discussed here and here.
The View Model shouldn't really know about it's associated View. It sounds like there is something wrong with your Bindings, as in general you should not have to "rebind" them. Either way, an attached behavior would be a good way to accomplish that.
I think the full answer to this question entails DrWPF's full series ItemsControl: A to Z. However, I believe the gist lies in where the visual elements get stored when a DataTemplate is "inflated" to display the data item it has been linked to by the framework.
In the section Introduction to Control Templates of "ItemsControl: 'L' is for Lookless", DrWPF explains that "We’ve already learned that a DataTemplate is used to declare the visual representation of a data item that appears within an application’s logical tree. In ‘P’ is for Panel, we learned that an ItemsPanelTemplate is used to declare the items host used within an ItemsControl."
For my issue, I still have not successfully navigated the visual tree in order to get a reference to my splitter item. This is my best attempt so far:
// w1 is a Window
SuperTabControlEx stc = w1.FindName("superTabControl1") as SuperTabControlEx;
//SuperTabItem sti = (SuperTabItem)(stc.ItemContainerGenerator.ContainerFromItem(stc.Items.CurrentItem));
ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(stc);
//ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(sti);
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
The above code is an attempt to implement the techniques shown on the msdn web site. However, when I apply it to my code, everything looks good, except myDataTemplate comes back null. As you can see, I attempted the same technique on SuperTabControlEx and SuperTabItem, derived from TabControl and TabItem, respectively. As described in my original post, and evident in the XAML snippet, the SuperTabControlEx also implements code from Keeping the WPF Tab Control from destroying its children.
At this point, perhaps more than anything else, I think this is an exercise in navigating the Visual Tree. I am going to modify the title of the question to reflect my new conceptions of the issue.

What does (x) in x:Name mean in Silverlight XAML Markup?

We see some properties in TextBlock or Grid like this:
<TextBlock x:Name="TextBlock1" ...
Why do we include this (x)? why don't we just say:
<TextBlock Name="TextBlock1" ...
I mean, we're already within the definition scope of this TextBlock, right?
There must be a reason for that.
Thanks in advance.
As an extension to Gabe's answer, x:Name is an attached property. Attached properties are different from standard properties, as they aren't defined (usually) on the control that uses them. For example, the TextBlock control does not have an x:Name property - instead, this property is defined elsewhere (in the XAML namespace), and is being "attached" to the TextBlock control to implement it's behaviour. It's saying "I want to use the Name attached property that can be found in the XAML namespace). Of course, to complicate things, the TextBlock control has a Name property (it didn't used to in Silverlight 2, thus you needed to use the x:Name attached property instead). They do the same thing though.
Another (easier to understand) example of an attached property is Grid.Row. You can use this property on the TextBlock control to specify what row the control should appear in a Grid, even though it's not defined on that control (the Grid control defines it). The TextBlock is simply attaching that property to itself, which associates itself with that behaviour. It's a confusing concept initially, but very powerful and useful. More info on attached properties can be found here: http://msdn.microsoft.com/en-us/library/cc265152(VS.95).aspx.
Hope this helps...
Chris
That is a namespace prefix.
Example 1:
You should see something like this on the xaml page:
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Which declares the x prefix referring to the xaml namespace.
Example 2:
You could load your own user controls by registering the namespace and giving it a prefix.
xmlns:mycontrols="clr-namespace:MyControls.Namespace;assembly=MyAssembly"
Then here we are using the prefix to utilize one of the controls from this namespace.
<mycontrols:MyControl />

How to set ItemsSource?

This dialog makes no sense to me
http://img576.imageshack.us/img576/4223/50709706.gif
And I'm having trouble finding good tutorials on it. Most of the examples aren't detailed enough, or do stuff via code, but I'd like to take advantage of the IDE as much as possible.
Whats the difference between ItemsSource and DataContext?
I'd like to bind it to just a List for starters. I don't need SQL or databases or anything fancy. Where would I declare my list? In MainWindow.xaml.cs? How do I get it to appear in that dialog?
Think of "DataContext" as the default value for "Source" in a binding.
When you create a binding, you can specify the path and source, like this (I'll use TextBox as an example):
<TextBox Text="{Binding Path=Foo,Source={StaticResource Bar}}" />
So my TextBox.Text property is bound to a Foo property on an object called Bar (a resource somewhere in the application).
However, if you have a whole bunch of things that you want to bind to properties on Bar, it's easier to set Bar as the DataContext of the parent container. A Binding without a Source will just use the DataContext by default, and DataContext flows through to child controls from the parent. So:
<StackPanel DataContext="{StaticResource Bar}">
<TextBox Text="{Binding Path=Foo}" />
<TextBox Text="{Binding Path=Fizz}" />
<TextBox Text="{Binding Path=Buzz}" />
</StackPanel>
All of the TextBoxes are still binding to properties on Bar, but they're doing it without setting it as a Source explicitly.
So let's have another look at the dialog you posted. It's giving you several options for the "source" of the ItemsSource binding. When you choose "DataContext", you're telling Visual Studio that the ItemsControl doesn't need to know the source - it'll pick it up from the DataContext of the parent container (maybe even the Window itself).
If you chose one of the other options (ElementName, RelativeSource or StaticResource) then you'd be setting the binding's source explicitly for that ItemsControl.
Once you've told it that it's binding to the DataContext, you'll need to drop into the "Path" section of the dialog and tell it which property to bind the items of the control to. In the end, the markup would look something like this (assuming it's a ListBox):
<ListBox ItemsSource="{Binding Path=Foos}" />
So the items in the ListBox are coming from a property called "Foos", and that property is on an object that's set in the DataContext somewhere higher in the logical tree (perhaps on the Window itself).
You rarely need to use the data context of a control outside of the control. The most common use case for setting DataContext(DataContext = this;) is within UserControl's code-behind to make all controls within the UserControl to bind to the control's properties.
When you use a ListBox, setting ItemsSource is sufficient, unless you are doing something funky.
This is a pretty good walkthrough: http://windowsclient.net/learn/video.aspx?v=315275
Specifically, you need to set the DataContext first to tell it where to look for the ItemsSource. The easiest way is to set this on the Window through the XAML:
<Window.DataContext>
<controllers:DownloadManager />
</Window.DataContext>

How to specify two DataTemplates for single type?

I defined in XAML DataTemplate for my own type.
<DataTemplate DataType="{x:Type MyType}">
...
</DataTemplate>
Now I want to add one more template for the same type in the same scope. How would I choose then which of templates to use in concrete ItemsControl?
Background:
I have ItemsControl that displays objects of different types (derived from one base class of course) in different way depending on the item's type. So I've specified unnamed data templates for each type. Now I need to show the same data but with new templates (old templates supported editing, new ones - not).
you would need to use DataTemplateSelector (msdn link)
you can do it by using DataTemplateSelector, Check this for details about how to use DataTemplateSelector:
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5b4db370-095e-4233-9d89-5dd8082fd474

Resources