Please teach me how to use ControlTemplate properly? - wpf

Ok, I think I am pretty noob on using ControlTemplate lol...
All I want is to template my every UserControl so every UserControl will have Delete, Save, Cancel buttons.
So now I am writting some test......
Try to make a border around the everything...
In App.xaml
<Application.Resources>
<ControlTemplate x:Key="DeleteSaveCancelTemplate">
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Border BorderThickness="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="Black">
<ContentPresenter/>
</Border>
</Grid>
</ControlTemplate>
</Application.Resources>
Then in UserControl:
<UserControl ... Height="150" Width="300" Template="{StaticResource DeleteSaveCancelTemplate}" >
But all I see is just ...black... what did I do wrong? I thought I should use ContentPresenter to shows the content?

For most controls you use ContentPresenter. ItemsPresenter only applies to elements that extend ItemsControl.

So... I found the problem lol From this page
The ControlPresenter doens't bind to Content by default...
I need to write
<ContentPresenter Content="{TemplateBinding Property=ContentControl.Content}" />
Unless you have specify the TargetType, then you it will bind by default.

Related

Stretch WPF ListView Template layout [duplicate]

I want to have the ListItems to extend with their orange background the full width of the Listbox.
Currently they are only as wide as the FirstName + LastName.
I've set every element I can to: HorizontalAlignment="Stretch".
I want the background of the ListboxItems to expand as the user stretches the Listbox so I don't want to put in absolute values.
What do I have to do so that the background color of the ListBoxItems fill the width of the ListBox?
<Window x:Class="TestListBoxSelectedItemStyle.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestListBoxSelectedItemStyle"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<local:CustomerViewModel x:Key="TheDataProvider"/>
<DataTemplate x:Key="CustomerItemTemplate">
<Border CornerRadius="5" Background="Orange" HorizontalAlignment="Stretch" Padding="5" Margin="3">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" Width="Auto">
<TextBlock HorizontalAlignment="Stretch">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} {1}">
<Binding Path="FirstName"/>
<Binding Path="LastName"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</Border>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemsSource="{Binding Path=GetAllCustomers, Source={StaticResource TheDataProvider}}"
ItemTemplate="{StaticResource CustomerItemTemplate}"/>
</Grid>
</Window>
I found another solution here, since I ran into both post...
This is from the Myles answer:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
This worked for me.
I'm sure this is a duplicate, but I can't find a question with the same answer.
Add HorizontalContentAlignment="Stretch" to your ListBox. That should do the trick. Just be careful with auto-complete because it is so easy to get HorizontalAlignment by mistake.
If your items are wider than the ListBox, the other answers here won't help: the items in the ItemTemplate remain wider than the ListBox.
The fix that worked for me was to disable the horizontal scrollbar, which, apparently, also tells the container of all those items to remain only as wide as the list box.
Hence the combined fix to get ListBox items that are as wide as the list box, whether they are smaller and need stretching, or wider and need wrapping, is as follows:
<ListBox HorizontalContentAlignment="Stretch"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
(credits for the scroll bar idea)
Since the border is used just for visual appearance, you could put it into the ListBoxItem's ControlTemplate and modify the properties there. In the ItemTemplate, you could place only the StackPanel and the TextBlock. In this way, the code also remains clean, as in the appearance of the control will be controlled via the ControlTemplate and the data to be shown will be controlled via the DataTemplate.
The fix for me was to set property HorizontalAlignment="Stretch" on ItemsPresenter inside ScrollViewer..
Hope this helps someone...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ScrollViewer x:Name="ScrollViewer" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" Padding="{TemplateBinding Padding}" HorizontalAlignment="Stretch">
<ItemsPresenter Height="252" HorizontalAlignment="Stretch"/>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
I also had the same problem, as a quick workaround, I used blend to determine how much padding was being added. In my case it was 12, so I used a negative margin to get rid of it. Now everything can now be centered properly

How To Make A WPF UserControl Act As A Container

I'm trying to create a Toolbar control that can group selected buttons with a border and a label. If there is already a built-in control that will do this then I could use that instead of building a UserControl.
If not, then what I'm wanting to build is a UserControl that would allow me to enter one-to-many of my ImageButton UserControls and set a GroupLabel text like below. Can this be done in WPF?
<User_Controls:ToolbarGroup GroupLabel="Entity">
<User_Controls:ImageButton ButtonText="Entity Setup"/>
<User_Controls:ImageButton ButtonText="New Entity"/>
</User_Controls:ToolbarGroup>
PS: I would post an image but this quirky forum won't allow me to post an image.
If i have got you correctly then I think you can achieve this way also, and on mouse eneter and leave event you can do the button click job.
for setting text you can use a grid and a label inside it to set the text, and Image buttons below it.
<UserControl x:Class="ABC.View.Oats"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Image Source="{Binding Image}" Stretch="Fill"/>
</Grid>
</UserControl>
I think what you're looking for is a GroupBox, it has a header property where you can set the label.
Something like this:
<GroupBox Width="300" Height="100">
<GroupBox.Header>
<Label>Text</Label>
</GroupBox.Header>
<StackPanel>
<Button Content="Button"/>
<Button Content="Button"/>
<Button Content="Button"/>
</StackPanel>
</GroupBox>
I would also recommend using the groupbox, it seems to be doing exactly what you want it to do and it looks neat. Here's some examples on how to use them: http://www.dotnetperls.com/groupbox-wpf
On the other hand, if you believe the groupbox is not sufficient, you could create a control that inherits from the groupbox and you could extend it and add whatever you need to it. It would look like this:
public class customGroupBox: GroupBox{
....Add whatever you need here
}
Thanks for the replies. I tried the GroupBox and it's not the layout we want because we want the label underneath the buttons and centered. I never could find a way to add a collection to the UserControl. Maybe I didn't ask the question right by calling it a container. The code below will work, but it's not elegant. I wanted something that would wrap the layout in a UserControl and allow me to add a variable number of buttons to each toolbar group.
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0">
<Border Background="GhostWhite" BorderBrush="Gainsboro" BorderThickness="1">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<User_Controls:ImageButton ButtonText="New 1"/>
<User_Controls:ImageButton ButtonText="New 2"/>
<User_Controls:ImageButton ButtonText="New 3"/>
</StackPanel>
<Label HorizontalAlignment="Center" Content="Group 1"/>
</StackPanel>
</Border>
<Border Background="GhostWhite" BorderBrush="Gainsboro" BorderThickness="1">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<User_Controls:ImageButton ButtonText="New 4"/>
</StackPanel>
<Label HorizontalAlignment="Center" Content="Group 2"/>
</StackPanel>
</Border>
</StackPanel>
One way to accomplish this is with a custom styled ItemsControl.
You can then reuse it and just bind it to different data.
Please forgive me, this is hand-typed...
In your resources...
<Style x:Key="ToolbarGroupItemsControlStyle" TargetType="ItemsControl">
...
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<Grid>
... XAML to form your group with a binding to the
... group name
<ItemsPresenter/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="ToolbarGroupItemTemplate">
<Grid>
... XAML and binding for each toolbar group item ...
</Grid>
</DataTemplate>
In your XAML...
<ItemsControl
Style="{DynamicResource ToolbarGroupItemsControlStyle}"
ItemsSource="{Binding ToolbarGroupItems}"
ItemTemplate="{DynamicResource ToolbarGroupItemTemplate"/>
If your resources above are at the application level, then you can place the ItemsControl above on any Window/UserControl you want.
Your ItemsSource will need to be a collection of a custom type you create that has bindings for the button text, etc.
I hope this is helpful.

Prevent WPF control from expanding beyond viewable area

I have an ItemsControl in my user control with a scroll viewer around it for when it gets too big (Too big being content is larger than the viewable area of the UserControl). The problem is that the grid that it is all in just keeps expanding so that the scroll viewer never kicks in (unless I specify an exact height for the grid). See code below and thanks in advance.
<UserControl x:Class="BusinessObjectCreationWizard.View.TableSelectionPageView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<GroupBox FontWeight="Bold" Height="300px"
Header="Tables"
Padding="2">
<ScrollViewer>
<ItemsControl FontWeight="Normal"
ItemsSource="{Binding Path=AvailableTables}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Path=DisplayName}"
IsChecked="{Binding Path=IsSelected}"
Margin="2,3.5" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</GroupBox>
</UserControl>
This user control is loaded here
<Border Background="White" Grid.Column="1" Grid.Row="0">
<HeaderedContentControl Content="{Binding Path=CurrentPage}"
Header="{Binding Path=CurrentPage.DisplayName}" />
</Border>
I would like to not specify the height.
If you remove the Height from your GroupBox (which, as far as I understand, is what you want to do), then it will fill its container, unless there's a panel upstream that imposes its own sizing rules.
I used this simplified version of your XAML. I removed the template and the binding, and hard-coded some items, to make this stand alone; those changes won't affect the way layout is done.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<GroupBox FontWeight="Bold" Header="Tables" Padding="2">
<ScrollViewer>
<ItemsControl FontWeight="Normal">
<TextBlock>Foo</TextBlock>
<TextBlock>Bar</TextBlock>
<TextBlock>Baz</TextBlock>
</ItemsControl>
</ScrollViewer>
</GroupBox>
</Window>
Run it, and you'll see that the content does indeed size to fit the window, and the scrollbar only enables when the window gets too small to see all three items. I believe this is what you want.
So the problem is most likely one of the parent panels, one you're not showing in your sample XAML. The problem you describe could occur if your GroupBox appears inside a StackPanel:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<StackPanel>
<GroupBox FontWeight="Bold" Header="Tables" Padding="2">
<ScrollViewer>
<ItemsControl FontWeight="Normal">
<TextBlock>Foo</TextBlock>
<TextBlock>Bar</TextBlock>
<TextBlock>Baz</TextBlock>
</ItemsControl>
</ScrollViewer>
</GroupBox>
</StackPanel>
</Window>
Now the GroupBox appears at the top of the Window, sized to exactly fit its contents. If you shrink the Window enough, the GroupBox will be cut off -- because it's sized to fit its content, not its container. This sounds like the problem you're describing.
The reason is that StackPanel asks its children what their ideal height is (based on their content), and uses that height. Without StackPanel (or something similar), the default is to respect the control's VerticalAlignment, and if that's set to the default value of Stretch, then the control is stretched to fill its parent. This means it won't be taller than its parent, which sounds like what you want.
Solution: remove the StackPanel (or whatever else is causing you problems) and use something else. Depending on what you're trying to accomplish, you might have better luck with a DockPanel or a Grid. Hard to tell without knowing more about your layout.
Edit: Okay, it looks like the problem is indeed the HeaderedContentControl parent -- but not directly. HeaderedContentControl isn't a panel, so it doesn't do any layout of its own (and its descendant, GroupBox, doesn't have this same problem). The problem is its default template -- which includes a StackPanel. The good news is, you're free to use a different template, let's say one with a DockPanel instead:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<HeaderedContentControl>
<HeaderedContentControl.Style>
<Style TargetType="{x:Type HeaderedContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type HeaderedContentControl}">
<DockPanel>
<ContentPresenter ContentSource="Header" DockPanel.Dock="Top"/>
<ContentPresenter/>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</HeaderedContentControl.Style>
<GroupBox FontWeight="Bold" Header="Tables" Padding="2">
<ScrollViewer>
<ItemsControl FontWeight="Normal">
<TextBlock>Foo</TextBlock>
<TextBlock>Bar</TextBlock>
<TextBlock>Baz</TextBlock>
</ItemsControl>
</ScrollViewer>
</GroupBox>
</HeaderedContentControl>
</Window>
If you leave off the <HeaderedContentControl.Style> part, this reproduces your problem; but with the style in place, it allows the GroupBox to fill its container, so the ScrollViewer will get a scrollbar when you want it to.
If the previous answer doesn't fix the problem, you could also try binding the Width, Height of your grid to the ActualWidth, ActualHeight of your parent UserControl. Something like:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfApplication.UserControl1"
x:Name="UserControl">
<Grid Height="{Binding ElementName=UserControl, Path=ActualHeight}"
Width="{Binding ElementName=UserControl, Path=ActualWidth}" />
In this case you aren't setting an explicit width and height but you are limiting the Grids width/height to the constraints of the UserControl it sits in.
I had the same issue, after reading this response I replaced all StackPanels with Grids in UserControl. It resolved the Scrollbar issue.
Try removing the grid entirely and setting the HorizontalAlignment and VerticalAlignment directly on the GroupBox. If a layoutpanel has only one child, it's often redundant... this migth be true in your case.
If that doesn't work... what's the parent of your grid control?
Why not just use a listbox instead of an itemscontrol, that has a built in scrollviewer.
They are different. If you do not want to have the items selectable, then don't use a ListBox. It is going to be heavier, and will also have the deselect a selection everytime the user clicks on an entry. Just put the ItemsControl in a ScrollViewer
I had the same problema with ListBox, it wasn't expanding and the scroll viewer didn't appear. I solved it as follows:
<UserControl x:Class="TesteView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid MaxHeight="710">
....
....
<StackPanel>
<ListBox MaxHeight="515"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Path=Teste,Mode=TwoWay}">
....
....
</ListBox>
</StackPanel>
</Grid>
</UserControl>

Customize WPF databinding: How to add custom logic?

i have a question regarding some complex data-binding.
I want to be able to update a grid (which has the property "IsItemsHost" set to true)
dynamically whenever a data-binding occurs.
Actually i am using a CustomControl which is an ItemsControl and this
has the Grid in its ControlTemplate.
To be more specific, i bind the grid to some items and i want to
change the number of grid rows depending on these items,
add something like a header (one row containing some text),
and set the items' Grid.Row and Grid.Column using some custom logic.
What is the easiest way to apply such behaviour
whenever the bound data is updated?
Do i have to use a viewmodel that also contains the header data?
Thanks in advance.
Code of the CustomControl Generic.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TimeTableControl">
<Style TargetType="{x:Type local:TimeTableControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TimeTableControl}">
<Border Width="Auto" Height="Auto" BorderBrush="#FF4B5A9B" BorderThickness="4" CornerRadius="4" Margin="2" Padding="0" Background="White">
<Grid Width="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="0.1*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Viewbox>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DayCaption}"/>
</Viewbox>
<Border Grid.Row="1" BorderThickness="0,2,0,0" BorderBrush="#FF4B5A9B">
<Grid Name="ContentGrid" IsItemsHost="True">
</Grid>
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Grid is used for layout. If you have a changing number of items in some collection, what you really want is ItemsControl, or more specific ListBox (if you want item selection, etc).
If you still want Grid-like behavior of individual rows, you may want to define a Grid in ItemsControl.ItemTemplate and play with Grid.IsSharedSizeScope at ItemsControl level. Alternatively, you may just use ListView instead to get the grid look and item selection in a package.
Update: I got it working by creating a custom panel that uses MeasureOverride and ArrangeOverride to update itself. This lets me adjust the panel to the children and I don't even need to use a grid. This also makes the control lookless.

Difference between Control Template and DataTemplate in WPF

What is difference between a ControlTemplate and a DataTemplate in WPF?
Typically a control is rendered for its own sake, and doesn't reflect underlying data. For example, a Button wouldn't be bound to a business object - it's there purely so it can be clicked on. A ContentControl or ListBox, however, generally appear so that they can present data for the user.
A DataTemplate, therefore, is used to provide visual structure for underlying data, while a ControlTemplate has nothing to do with underlying data and simply provides visual layout for the control itself.
A ControlTemplate will generally only contain TemplateBinding expressions, binding back to the properties on the control itself, while a DataTemplate will contain standard Binding expressions, binding to the properties of its DataContext (the business/domain object or view model).
Very basically a ControlTemplate describes how to display a Control while a DataTemplate describes how to display Data.
For example:
A Label is a control and will include a ControlTemplate which says the Label should be displayed using a Border around some Content (a DataTemplate or another Control).
A Customer class is Data and will be displayed using a DataTemplate which could say to display the Customer type as a StackPanel containing two TextBlocks one showing the Name and the other displaying the phone number. It might be helpful to note that all classes are displayed using DataTemplates, you will just usually use the default template which is a TextBlock with the Text property set to the result of the Object's ToString method.
Troels Larsen has a good explanation on MSDN forum
<Window x:Class="WpfApplication7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate x:Key="ButtonContentTemplate">
<StackPanel Orientation="Horizontal">
<Grid Height="8" Width="8">
<Path HorizontalAlignment="Stretch"
Margin="0,0,1.8,1.8"
VerticalAlignment="Stretch" Stretch="Fill" Stroke="#FF000000"
Data="M0.5,5.7 L0.5,0.5 L5.7,0.5"/>
<Path HorizontalAlignment="Stretch"
Margin="2,3,0,0"
VerticalAlignment="Stretch" Stretch="Fill" Stroke="#FFFFFFFF"
Data="M3.2,7.5 L7.5,7.5 L7.5,3.5"/>
<Path HorizontalAlignment="Stretch"
Margin="1.2,1.4,0.7,0.7"
VerticalAlignment="Stretch" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000"
Data="M2.5,2.5 L7.5,7.5"/>
<Path HorizontalAlignment="Stretch"
Margin="1.7,2.0,1,1"
VerticalAlignment="Stretch" Stretch="Fill" Stroke="#FF000000"
Data="M3,7.5 L7.5,7.5 L7.5,3.5"/>
<Path HorizontalAlignment="Stretch"
Margin="1,1,1,1"
VerticalAlignment="Stretch" Stretch="Fill" Stroke="#FFFFFFFF"
Data="M1.5,6.5 L1.5,1 L6.5,1.5"/>
</Grid>
<ContentPresenter Content="{Binding}"/>
</StackPanel>
</DataTemplate>
<ControlTemplate TargetType="Button" x:Key="ButtonControlTemplate">
<Grid>
<Ellipse Fill="{TemplateBinding Background}"/>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Window.Resources>
<StackPanel>
<Button Template="{StaticResource ButtonControlTemplate}" ContentTemplate="{StaticResource ButtonContentTemplate}" Content="1"/>
<Button Template="{StaticResource ButtonControlTemplate}" ContentTemplate="{StaticResource ButtonContentTemplate}" Content="2"/>
<Button Template="{StaticResource ButtonControlTemplate}" ContentTemplate="{StaticResource ButtonContentTemplate}" Content="3"/>
</StackPanel>
</Window>
(Templates blatently stolen from
http://msdn.microsoft.com/en-us/library/system.windows.controls.controltemplate.aspx
and
http://msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol.contenttemplate%28VS.95%29.aspx
respectively)
Anyway, the ControlTemplate decides how the Button itself looks, while
the ContentTemplate decides how the Content of the button looks. So
you could bind the content to one of you data classes and have it
present itself however you wanted it.
ControlTemplate: Represents control style.
DataTemplate: Represents data style(How would you like to show your data).
All controls are using default control template that you can override through template property.
For example
Button template is a control template.
Button content template is a data template
<Button VerticalAlignment="Top" >
<Button.Template>
<ControlTemplate >
<Grid>
<Rectangle Fill="Blue" RadiusX="20" RadiusY="20"/>
<Ellipse Fill="Red" />
<ContentPresenter Content="{Binding}">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="50">
<TextBlock Text="Name" Margin="5"/>
<TextBox Text="{Binding UserName, Mode=TwoWay}" Margin="5" Width="100"/>
<Button Content="Show Name" Click="OnClickShowName" />
</StackPanel>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
public String UserName
{
get { return userName; }
set
{
userName = value;
this.NotifyPropertyChanged("UserName");
}
}
ControlTemplate - Changing the appearance of element. For example Button can contain image and text
DataTemplate - Representing the underlying data using the elements.
ControlTemplate DEFINES the visual appearance, DataTemplate REPLACES the visual appearance of a data item.
Example: I want to show a button from rectangular to circle form => Control Template.
And if you have complex objects to the control, it just calls and shows ToString(), with DataTemplate you can get various members and display and change their values of the data object.
All of the above answers are great but there is a key difference that was missed. That helps make better decisions about when to use what. It is ItemTemplate property:
DataTemplate is used for elements that provide ItemTemplate property for you to replace its items' content using DataTemplates you define previously according to bound data through a selector that you provide.
But if your control does not provide this luxury for you then you still can use a ContentView that can display its content from predefined ControlTemplate. Interestingly, you can change the ControlTemplate property of your ContentView at runtime. One more thing to note that unlike controls with ItemTemplate property, you cannot have a TemplateSelector for this (ContentView) control. However, you still can create triggers to change the ControlTemplate at runtime.

Resources