I am new to WPF and spent hours of searching a solution for that, but I cannot find anything.
I want to display all properties of a class with a DataTemplate
:
<ItemsControl ItemsSource="{Binding Car}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
public class Car
{
public int Axes { get; set; }
public int Seats { get; set; }
public int Doors { get; set; }
public VehicleProperties.Car.Type Type { get; set; }
public int MaxWeight { get; set; }
public Fuel Fuel { get; set; }
public double ConsumptionPer100km { get; set; }
public bool Childseat { get; set; }
public string Brand { get; set; }
public string Model { get; set; }
public int FirstRegistration { get; set; }
public int Mileage { get; set; }
public Transmission Transmission { get; set; }
public int Power { get; set; }
public bool Tempomat { get; set; }
public SolidColorBrush Color { get; set; }
public int PollutionClass { get; set; }
public int EnvironmentalBadge { get; set; }
}
How can I at least display the name and bind the ItemsSource
and the TextBlock
correctly? I need that, because after this, I will design the DataTemplate
s with the DataType
property.
CodePudding user response:
If you are only interested in the property names of a concrete type, you could create a custom markup extension that receives a type and uses reflection to get its property infos and returns the property names as enumerable.
public class PropertyNamesExtension : MarkupExtension
{
public Type Type { get; set; }
public PropertyNamesExtension(Type type)
{
Type = type;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return Type?.GetProperties().Select(propertyInfo => propertyInfo.Name);
}
}
In XAML you can use the markup extension with the type Car
as ItemsSource
.
<ItemsControl ItemsSource="{local:PropertyNamesExtension local:Car}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If you want more information, e.g. the type of each property, return the PropertyInfo
s instead.
public override object ProvideValue(IServiceProvider serviceProvider)
{
return Type?.GetProperties();
}
<ItemsControl ItemsSource="{local:PropertyNamesExtension local:Car}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding Name, Mode=OneWay}"/>
<Run Text="{Binding PropertyType, Mode=OneWay}"/>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I need that, because after this, I will design the DataTemplates with the DataType-Property.
I do not know exactly what you goal is, but I think you are trying to achieve something different. Let's suppose you want to display a single instance of a Car
. Then expose that instance through a property and bind it as Content
of a ContentControl
with a DataTemplate
.
public Car Car { get; }
<ContentControl Content="{Binding Car}">
<ContentControl.ContentTemplate>
<DataTemplate DataType="{x:Type local:Car}">
<StackPanel>
<TextBlock Text="{Binding Brand}"/>
<TextBlock Text="{Binding Axes}"/>
<!-- ...other markup. -->
</StackPanel>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
If you want to show a list of Car
s, expose them as any collection, e.g. a List<Car>
or an ObservableCollection<Car>
if the collection is changed at runtime (otherwise added or removed items will not be updated in the user interface). Then use an ItemsControl
or ListBox
or ListView
depending on your requirements and add an ItemsTemplate
.
public ObservableCollection<Car> Cars { get; }
<ItemsControl ItemsSource="{Binding Cars}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Brand}"/>
<TextBlock Text="{Binding Axes}"/>
<!-- ...other markup. -->
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
CodePudding user response:
C# code
Car car = new();
itemControl.ItemsSource = car.GetType().GetProperties();