I'm trying to set up a WPF DataTemplate that will be used for Line
(System.Windows.Shapes.Line
) objects.
From a default .NET 4 WPF Application, I set my Window xaml to:
<Window x:Class="WpfTestDataTemplates.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type system:String}" >
<TextBlock>It's a string</TextBlock>
</DataTemplate>
<DataTemplate DataType="{x:Type Line}" >
<TextBlock>It's a line</TextBlock>
</DataTemplate>
</Window.Resources>
<ListView ItemsSource="{Binding MyItems}" />
</Window>
And the code behind is:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Shapes;
namespace WpfTestDataTemplates
{
public partial class MainWindow : Window
{
public List<object> MyItems {get; set; }
public MainWindow()
{
InitializeComponent();
DataContext = this;
MyItems = new List<object>();
MyItems.Add("The first string");
MyItems.Add(new Line { X1 = 0, Y1 = 0, X2 = 5, Y2 = 5 });
MyItems.Add("The second string");
MyItems.Add(new Rectangle { Height = 5, Width = 15 });
MyItems.Add(42);
}
}
}
The resulting window looks like this:
I expect the second entry to read: It's a line, but instead it seems the DataTemplate for the Line
type is not found. For types without an explicit DataTemplate, I expect the default rendering to be the .ToString() member of the object, but that's not what is happening either. So I'd expect the fourth entry to read: System.Windows.Shapes.Rectangle
Why is the {x:Type Line}
type not being recognized, and what DataTemplate is being applied to Shape objects?
A DataTemplate
is what you use to put UI on data objects that aren't themselves UIElements
and have no concept of rendering themselves on-screen. Line
and Rectangle
however are UIElements - they know how to render themselves, and don't need a DataTemplate to tell them how.
If you give your Line and Rectangle some color, you'll see that they disregard the well-meaning DataTemplate and show up in the list as a line and a rectangle:
MyItems.Add(new Line { X1 = 0, Y1 = 0, X2 = 5, Y2 = 5,
Stroke = Brushes.Lime, StrokeThickness = 2 });
...
MyItems.Add(new Rectangle { Height = 5, Width = 15, Fill = Brushes.Blue });
To change the appearance of UIElements, you'd typically use Style
(if it is a FrameworkElement
) and/or ControlTemplate
(if it is a Control
).
Edit:
If, instead of a Line
, you have your own data class representing a line (let's call it LineData
), you can use a DataTemplate to render that class any way you'd like:
public class LineData
{
public LineData(Point start, Point end)
{
this.Start = start;
this.End = end;
}
public Point Start { get; private set; }
public Point End { get; private set; }
public double XLength
{
get { return this.End.X - this.Start.X; }
}
public double YLength
{
get { return this.End.Y - this.Start.Y; }
}
}
...
MyItems.Add(new LineData(new Point(10, 10), new Point(60, 30)));
..and the DataTemplate..
<DataTemplate DataType="{x:Type vm:LineData}" >
<StackPanel Orientation="Horizontal" SnapsToDevicePixels="True" >
<TextBlock>It's a line:</TextBlock>
<Grid>
<Rectangle Stroke="Black" StrokeThickness="1"
Width="{Binding Path=XLength}" Height="{Binding Path=YLength}" />
<Line Stroke="Red" StrokeThickness="2"
X1="{Binding Path=Start.X}" Y1="{Binding Path=Start.Y}"
X2="{Binding Path=End.X}" Y2="{Binding Path=End.Y}" />
</Grid>
</StackPanel>
</DataTemplate>
..gives us:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With