Using BindingContext within Border (C# MAUI, appliable to Xamarin/WPF) - wpf

I've been struggling with getting Binding to work within a Border. When I try to bind something outside the Border, it works wonderfully, but I can't get it to work within the Border.
Code here of what works:
<DataTemplate x:Key="TaskTemplate">
<GridLayout
ColumnDefinitions="*"
>
<Label Text={Binding Path=TestText}/>
</GridLayout>
</DataTemplate>
This code displays the text properly.
What does not and what I need to get to work:
<DataTemplate x:Key="TaskTemplate">
<GridLayout
ColumnDefinitions="*"
>
<Border
GridLayout.Column="0"
BackgroundColor="{StaticResource MidBackgroundColor}"
StrokeThickness="1"
Stroke="Transparent"
HorizontalOptions="Center">
<Border.StrokeShape>
<RoundRectangle CornerRadius="30"/>
</Border.StrokeShape>
<Label
Text="{Binding Path=TestText}"/>
</Border>
</GridLayout>
</DataTemplate>
This code shows it as empty.
From what I've understood so far, the Border takes away the Context and I've tried numerous things off of other threads to get it to work, but since I'm quite new, I'm struggling to find out how it works exactly.
Thanks in advance!
EDIT:
I've already tried replacing the Binding with plain text and that works just fine, so it's not that a Label within a Border would be invisible.
I want to clarify that the aforementioned Text property is not actually the Label's or Border's Text property, but a Text property of a bounded object. Renamed it for clarity above to TestText.
This code shows proper text:
<GridLayout
ColumnDefinitions="*"
>
<Border
GridLayout.Column="0"
BackgroundColor="{StaticResource MidBackgroundColor}"
StrokeThickness="1"
Stroke="Transparent"
HorizontalOptions="Center">
<Border.StrokeShape>
<RoundRectangle CornerRadius="30"/>
</Border.StrokeShape>
<Label
Text="Testing text."/>
</Border>
</GridLayout>
</DataTemplate>
The desired result is this: https://i.stack.imgur.com/wUdGD.jpg
But instead of the hard-coded text, it should Bind text of another object. This shouldn't be an issue of other code, since it works just fine if I write the code outside the Border.
EDIT2:
Including all the other code.
This is the Page that displays everything.
TasksPage.xaml:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
<ContentPage.Resources>
<ResourceDictionary Source="/Views/ViewTask.xaml"/>
</ContentPage.Resources>
<GridLayout RowDefinitions="*">
<GridLayout
GridLayout.Row="0"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<StackLayout Margin="5,5,5,0">
<CollectionView x:Name="TasksCollection"
ItemsSource="{Binding Tasks}"
ItemTemplate="{StaticResource TaskTemplate}">
</CollectionView>
</StackLayout>
</GridLayout>
</GridLayout>
</ContentPage>
TasksPage.xaml.cs:
public partial class TasksPage : ContentPage
{
public TasksPage()
{
InitializeComponent();
BindingContext = new TaskViewModel();
}
}
This is the itemtemplate for that collection.
ViewTask.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
<DataTemplate x:Key="TaskTemplate">
<GridLayout
ColumnDefinitions="*">
<Border
GridLayout.Column="0"
BackgroundColor="{StaticResource MidBackgroundColor}"
StrokeThickness="1"
Stroke="Transparent"
HorizontalOptions="Center">
<Border.StrokeShape>
<RoundRectangle CornerRadius="30"/>
</Border.StrokeShape>
<Label GridLayout.Column="0"
GridLayout.Row="0"
Text="{Binding TaskText}" />
</Border>
</GridLayout>
</DataTemplate>
</ResourceDictionary>
The ViewModel just has an ObservableCollection, which works just fine. So all the items actually populate the DataTemplate, it's just that the DataTemplate only shows Binded properties if it's not within a Border.

Someone else has also seen this as a bug. Lester Moreno's comment on blog announcing maui preview 9.
For now, you can simulate Border by using "Frame-inside-Frame":
<!-- Without Grid, the Frame takes the whole width. -->
<!-- To have multiple buttons in one row, use more Grid columns. -->
<!-- Border will be more convenient once it works. -->
<Grid ColumnDefinitions="Auto,*">
<!-- "Padding 6" of outer frame determines how thick the Border color is. -->
<Frame HasShadow="False" CornerRadius="18" Padding="6" BackgroundColor="#F69927">
<!-- "Padding 2" of inner frame is white space surrounding the label. -->
<Frame HasShadow="False" CornerRadius="12" BackgroundColor="White" Padding="6,2">
<Label Text="{Binding LabelText}" VerticalTextAlignment="Center" HorizontalTextAlignment="Center"
TextColor="Blue"/>
</Frame>
</Frame>
</Grid>

Related

WPF TextBox in DataTemplate of ToggleButton does not show text if in toolbar flyout

If I put the Column where the toolbar is hosted to be very big (800) then all the text is visible:
but if I put a smaller column this happens:
But I cannot understand why:
<DataTemplate x:Key="IconFilterButton">
<StackPanel Orientation="Horizontal">
<TextBlock
VerticalAlignment="Center"
Style="{StaticResource LargeIconStyle}"
Text="{Binding}" />
<TextBlock
Margin="6,0,0,0"
VerticalAlignment="Center"
DataContext="{Binding}"
Style="{StaticResource BodyTextStyle}"
Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ToggleButton}, Path=Tag}" />
</StackPanel>
</DataTemplate>
and here the definition
<ToggleButton
x:Name="DFilter"
Click="Filtering_Click"
Content=""
ContentTemplate="{StaticResource IconFilterButton}"
Tag="1d"
/>
<ToggleButton
x:Name="WFilter"
Click="Filtering_Click"
Content=""
ContentTemplate="{StaticResource IconFilterButton}"
Tag="1w"
/>
Even worst if I click on the button once they are out:
and then the text is visible but is wrong as the TextBlock is not considered in the object size:
The WPF ToolBar control uses a custom panel for the overflow Popup. In many styles, the ToolBarOverFlowPanel has a property WrapWidth set to a static value like 200. This determines how many items can be displayed before it wraps to another row in the popup.
I've created custom styling for this control and have found that the ToolBarOverFlowPanel used internally is buggy. That's probably the source of your problem.
You can re-template the ToolBar and wire-up a different value for WrapWidth to try to fix the issue, but my guess is that you'll still run into layout problems.
Otherwise, you might consider making your own replacement control.

Improve performance for huge ListBox in StackPanel?

I am using a StackPanel to layout several controls vertically (ie, Title, sub titles, listbox, separator, listbox, etc).
The StackPanel is a child of a ScrollViewer to ensure its content is always scrollable.
One of the controls in the StackPanel is a ListBox.
Its ItemsSource is data bound to a huge collection, and a complex DataTemplate is used to realise each item.
Unfortunately, I'm getting really poor performance (high cpu/memory) with it.
I tried
setting the ListBox's ItemsPanel to a VirtualizingStackPanel, and
overriding its ControlTemplate to only an ItemsPresenter (remove the ListBox's ScrollViewer).
But there were no difference in performances. I'm guessing the StackPanel gives its internal children infinite height during measure?
When I replaced the ScrollViewer and StackPanel with other panels/layouts (e.g, Grid, DockPanel) and the performance improves significantly, which leads me to believe the bottleneck, as well as solution, is in virtualization.
Is there any way for me to improve the cpu/memory performance of this view?
[Update 1]
Original Sample project: http://s000.tinyupload.com/index.php?file_id=29810707815310047536
[Update 2]
I tried restyling/templating TreeView/TreeViewItems to come up with the following example. It still takes a long time to start/same,high memory usage. But once loaded, scrolling feels a lot more responsive than the original sample.
Wonder if there's any other way to further improve the start up time/memory usage?
Restyled TreeView project: http://s000.tinyupload.com/index.php?file_id=00117351345725628185
[Update 2]
pushpraj's solution works like a charm
Original:
Startup: 35s,
Memory: 393MB
Scrolling: Slow
TreeView:
Startup: 18s,
Memory 377MB,
Scrolling: Fast
pushpraj's solution:
Startup: <1s,
Memory: 20MB,
Scrolling: Fast
you may perhaps limit the maximum size of the huge list box and enable Virtualization
eg
<ListBox MaxHeight="500"
VirtualizingPanel.IsVirtualizing="true"
VirtualizingPanel.VirtualizationMode="Recycling" />
this will enable the ListBox to load a few items only and will enable a scrollbar on listbox to scroll to rest of the items if needed.
at the same time setting VirtualizationMode to Recycling will help you to reuse the complex data templates thus eliminating the need of re creating them again for every item.
EDIT
here is a solution based on your sample, I have used CompositeCollection with Virtualization to achieve the desired.
xaml
<Grid xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:l="clr-namespace:PerfTest">
<Grid.Resources>
<DataTemplate DataType="{x:Type l:Permission}">
<StackPanel Orientation="Horizontal">
<CheckBox />
<TextBlock Text="{Binding Name}" />
<Button Content="+" />
<Button Content="-" />
<Button Content="..." />
</StackPanel>
</DataTemplate>
<CompositeCollection x:Key="data">
<!-- Content 1 -->
<TextBlock Text="Title"
FontSize="24"
FontWeight="Thin" />
<!-- Content 2 -->
<TextBlock Text="Subtitle"
FontSize="16"
FontWeight="Thin" />
<!-- Content 3 -->
<CollectionContainer Collection="{Binding DataContext, Source={x:Reference listbox}}" />
<!-- Content 4 -->
<TextBlock Text="User must scroll past the entire list box before seeing this"
FontSize="16"
FontWeight="Thin"
Padding="5"
TextWrapping="Wrap"
Background="#99000000"
Foreground="White" />
</CompositeCollection>
</Grid.Resources>
<ListBox x:Name="listbox"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{StaticResource data}" />
</Grid>
code
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var items = new ObservableCollection<Permission>();
foreach (var i in Enumerable.Range(0, 10000).Select(i => new Permission() { Name = "Permission " + i }))
{ items.Add(i); }
DataContext = items;
}
}
public class Permission
{
public string Name { get; set; }
}
since we can not create data template for string so I changed the string collection to Permission collection. I hope in your real project it would be something similar.
give this a try and see if this is close to what you need.
note: you may safely ignore if there is any designer warning on Collection="{Binding DataContext, Source={x:Reference listbox}}"

How to avoid sizing grip overlap in Window

I made a WPF Window containing StatusBar with StatusBarItem and ProgressBar.
The Window has a property ResizeMode set to CanResizeWithGrip.
It shows the sizing grip properly, but it overlaps elements underneath:
How can I avoid this overlap? I can set right margin to the progress bar, but how large? I don't want to use any magic numbers or hardcoded values. It would be also nice to have this resolved purely in XAML.
You can change style for "Window" considering all wishes.
http://msdn.microsoft.com/en-us/library/aa969824(v=vs.110).aspx
or https://stackoverflow.com/a/8278917/3492412
Or can do something like this
<StatusBar VerticalAlignment="Bottom">
<StatusBarItem x:Name="statusbar" Background="Gray" HorizontalContentAlignment="Stretch">
<DockPanel>
<ResizeGrip DockPanel.Dock="Right" Visibility="Hidden" />
<ProgressBar Background="red" Height="20" Value="50" />
</DockPanel>
</StatusBarItem>
</StatusBar>

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>

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