【问题标题】:Display all properties of a Class with XAML使用 XAML 显示类的所有属性
【发布时间】:2021-09-29 12:10:21
【问题描述】:

我是 WPF 的新手,为此花了数小时寻找解决方案,但我找不到任何东西。

我想用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; }
}

如何至少显示名称并正确绑定ItemsSourceTextBlock?我需要那个,因为在此之后,我将设计带有DataType 属性的DataTemplates。

【问题讨论】:

    标签: c# wpf xaml data-binding


    【解决方案1】:

    如果您只对具体类型的属性名称感兴趣,您可以创建一个自定义标记扩展来接收类型并使用反射来获取其属性信息并将属性名称作为可枚举返回。

    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);
       }
    }
    

    在 XAML 中,您可以将类型为 Car 的标记扩展用作 ItemsSource

    <ItemsControl ItemsSource="{local:PropertyNamesExtension local:Car}">
       <ItemsControl.ItemTemplate>
          <DataTemplate>
             <TextBlock Text="{Binding}" />
          </DataTemplate>
       </ItemsControl.ItemTemplate>
    </ItemsControl>
    

    如果您想了解更多信息,例如每个属性的类型,返回PropertyInfos。

    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>
    

    我需要它,因为在此之后,我将使用 DataType-Property 设计 DataTemplates。

    我不确切知道您的目标是什么,但我认为您正在尝试实现不同的目标。假设您要显示Car 的单个instance。然后通过属性公开该实例并将其绑定为ContentControlContentDataTemplate

    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>
    

    如果您想显示Cars 的列表,请将它们公开为任何集合,例如List&lt;Car&gt;ObservableCollection&lt;Car&gt; 如果集合在运行时更改(否则添加或删除的项目将不会在用户界面中更新)。然后根据您的要求使用ItemsControlListBoxListView 并添加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>
    

    【讨论】:

    • 我必须开发一个程序,您可以在其中创建车辆,但是有不同类型的车辆(有汽车、摩托车、卡车......)和不同的属性。正因为如此,我为每辆车创建了一个具有所需属性的类,我现在正在编写用于创建新车的对话框。这意味着,对于字符串,我需要一个带有属性名称的 TextBlock,但对于布尔值或自定义类,我需要一个带有类属性的 ComboBox。所以我需要不同的 DataTemplates 来动态创建创建对话框。
    • @Alive318 然后您可以将单个Car 实例示例与ContentControl 一起使用。只需为每种不同类型的汽车添加一个DataTemplate,指定相应的DataType。您可以将每个属性的标记放在该模板中,无需为每个简单属性创建单独的数据模板。对于复杂的属性 - 让我们假设 Transmission - 您可以在 DataTemplate 中使用相同的方法。添加ContentControl,绑定Transmission 属性并在范围内为该类型提供DataTemplate
    【解决方案2】:

    C#代码

    Car car = new();
    itemControl.ItemsSource = car.GetType().GetProperties();
    

    【讨论】:

    • 这将是一个解决方案,但我在 MVVM-Concepts 之后工作,因此,我无法使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    • 1970-01-01
    • 2013-06-26
    • 1970-01-01
    • 1970-01-01
    • 2016-09-18
    相关资源
    最近更新 更多