This example will show you how to use a FuncDataTemplate
to create an advanced DataTemplate
in code.
You should already know what a DataTemplate
is and how it works in Avalonia. If not, read more about it in the [Basic DataTemplate Sample].
The class FuncDataTemplate
provides a DataTemplate
for a given object
. Most of the time you will want to use the generic version. You can pass lambda expressions for building the template and if the given object
matches to this DataTemplate
. Please see the [API Reference] for more information.
ℹ️
|
If you are not familiar with lambda expressions, please visit the [Microsoft Docs] for more information. |
The model is build up similar to the Basic DataTemplate Sample. We have one class called Person
and one enum
called Sex
:
- Person.cs
public class Person
{
/// <summary>
/// Gets or sets the first name of the person. You can only set this property on init.
/// </summary>
public string? FirstName { get; init; }
/// <summary>
/// Gets or sets the last name of the person. You can only set this property on init.
/// </summary>
public string? LastName { get; init; }
/// <summary>
/// Gets or sets the sex of the person. You can only set this property on init.
/// </summary>
public Sex Sex { get; init; }
// Override ToString()
public override string ToString()
{
return $"{FirstName} {LastName}";
}
}
- Sex.cs
// Feel free to add or reorder the entries based on your needs.
public enum Sex
{
Diverse,
Female,
Male
}
In the file ViewModels ► MainWindowViewModel
we add a list of Persons:
public List<Person> People { get; } = new List<Person>()
{
new Person
{
FirstName = "Mr.",
LastName = "X",
Sex=Sex.Diverse
},
new Person
{
FirstName = "Hello",
LastName = "World",
Sex= Sex.Male
},
new Person
{
FirstName = "Hello",
LastName = "Kitty",
Sex= Sex.Female
}
};
In your project create a new directory called DataTemplates
. Inside this directory you can add a static
class
called DataTemplateProvider.cs
. This file can hold several FuncDataTemplates
. In this sample we will only add one.
ℹ️
|
We make this class static as nothing is depending on instance members. If you need to access instance members, don’t make it static. |
To make it easier for maintaining, we will first write a function which takes a Person
and returns the Control
, which represents the data the way we want.
// This private function will return a control that represents our persons sex as a gender symbol.
private static Control BuildGenderPresenter(Person person)
{
// Create a new Path as a presenter. You can also use any other Control.
// If you want to add more than one control, remember to wrap them inside a Panel.
Path path = new Path()
{
Width = 32,
Height = 32,
// We set Stretch to Uniform. That way our Path will be made as big as needed while keeping the aspect ratio.
Stretch = Stretch.Uniform,
// Create a Binding for the ToolTip
[!ToolTip.TipProperty] = new Binding(nameof(person.Sex))
};
switch (person.Sex)
{
case Sex.Diverse:
// We use StreamGeometry.Parse() to get the needed Data.
path.Data = StreamGeometry.Parse("...");
// We can set Fill to any Brush. We can also look up a Brush in Resources, if needed.
path.Fill = new LinearGradientBrush
{
StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
GradientStops =
{
new GradientStop(Colors.Red, 0),
new GradientStop(Colors.Orange, 0.2),
new GradientStop(Colors.Yellow, 0.4),
new GradientStop(Colors.DarkTurquoise, 0.6),
new GradientStop(Colors.Blue, 0.8),
new GradientStop(Colors.Violet, 1),
}
};
break;
case Sex.Female:
path.Data = StreamGeometry.Parse("...");
path.Fill = new SolidColorBrush(Colors.DeepPink);
break;
case Sex.Male:
path.Data = StreamGeometry.Parse("...");
path.Fill = new SolidColorBrush(Colors.Blue);
break;
default:
// Fall-back value
return new TextBlock { Text = "NOT SUPPORTED" };
}
return path;
}
ℹ️
|
The Path.Data is not shown in the above sample code. Please refer to the source code for the needed path data.
|
💡
|
For the [!MyProperty] = new Binding("The Binding Path"); Read more about binding in code in the [Docs] |
We can now add our FuncDataTemplate
which will consume the function we wrote above:
// This FuncDataTemplate can be static, as it will not change over time.
public static FuncDataTemplate<Person> GenderDataTemplate { get; }
= new FuncDataTemplate<Person>(
// Check if we have a valid object and return true if it is valid.
(person) => person is not null,
// Avalonia will provide the Person automatically as the functions parameter.
// We can also write (person) => BuildGenderPresenter(person)
BuildGenderPresenter);