C# 基于通用对象属性的WPF用户控件

C# 基于通用对象属性的WPF用户控件,c#,wpf,xaml,user-controls,C#,Wpf,Xaml,User Controls,我有一个基于字节数据的对象,它有200多个我关心的属性,从某种意义上说,我想(1)知道值,以及(2)知道值何时从一条消息更改到下一条消息 我正在使用的XAML的一个片段: <Label Content="Prop Name" /> <TextBlock Text="{Binding PropName}" Background="{Binding PropName, Converter={StaticResource CompareToLastValu

我有一个基于字节数据的对象,它有200多个我关心的属性,从某种意义上说,我想(1)知道值,以及(2)知道值何时从一条消息更改到下一条消息

我正在使用的XAML的一个片段:

<Label Content="Prop Name" />
<TextBlock Text="{Binding PropName}" 
    Background="{Binding PropName, 
        Converter={StaticResource CompareToLastValueConverter}}" />

目前,我为每个属性粘贴了这些线,并设置了适当的网格位置

我的问题是:是否有一种很好的方法来创建一个嵌套的WPF用户控件,该控件从模型获取一个通用对象属性,并处理将名称(带空格)分配给标签,然后将属性值分配给文本块,如上面的示例所示


另外,这是思考这个问题的最佳方式,还是我缺少了“WPF方式”中的一个环节?

我经常想尝试一下。我将为PropertyInfo创建一个ItemsControl模板

我创建了一个测试类:

    public class MyClass
    {
        public string PropertyTest1 {get;set;}
        public string PropertyTest2 { get; set; }
        public string PropertyTest3 { get; set; }
        public string PropertyTest4 { get; set; }
    }
显示的属性。在我的显示数据上下文中,我有两件事要绑定。财产的列表,以及所讨论的对象。由于PropertyInfo是静态的,因此使用转换器或其他工具可以更好地实现这一点,而无需将其绑定到属性:

    public PropertyInfo[] Properties
    {
        get { return typeof(MyClass).GetProperties(); }
    }

    public MyClass MyObject
    {
        get { return new MyClass { PropertyTest1 = "test", PropertyTest3 = "Some string", PropertyTest4 = "Last Property" }; }
    }
现在,显示属性很容易:

<ItemsControl x:Name="PropertyDisplay" ItemsSource="{Binding Properties}" Grid.IsSharedSizeScope="True">
    <ItemsControl.Resources>
        <local:PropertyInfoValueConverter x:Key="PropertyInfoValueConverter"/>
    </ItemsControl.Resources>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="{Binding Name}" Margin="4,2"/>
                <TextBlock Grid.Column="1" Margin="4,2"/>
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
转换器实际上非常简单,特别是因为您不使用文本框(因此只使用只读方向):

结果是:

你说你想要用空格来表示名字,这可以通过一个转换器来完成,这个转换器有一些逻辑,可以寻找你已经有的命名约定(大写字母前的空格?)

使用模板选择器来选择布尔、字符串、浮点模板并对它们进行不同的处理是很有趣的。(复选框、文本、00.00格式文本等)

编辑:浏览模板选择器

下面是一个示例模板选择器:

public class PropertyInfoTemplateSelector : DataTemplateSelector
{
    public DataTemplate StringTemplate { get; set; }
    public DataTemplate IntegerTemplate { get; set; }
    public DataTemplate DecimalTemplate { get; set; }
    public DataTemplate BooleanTemplate { get; set; }
    public DataTemplate DefaultTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        PropertyInfo propertyInfo = item as PropertyInfo;
        if (propertyInfo.PropertyType == typeof(string))
        {
            return StringTemplate;
        }
        else if (propertyInfo.PropertyType == typeof(int))
        {
            return IntegerTemplate;
        }
        else if (propertyInfo.PropertyType == typeof(float) || propertyInfo.PropertyType == typeof(double))
        {
            return DecimalTemplate;
        }
        else if (propertyInfo.PropertyType == typeof(bool))
        {
            return BooleanTemplate;
        }
        return DefaultTemplate;
    }
}
我们的ItemsControl现在只是:

<ItemsControl x:Name="PropertyDisplay" ItemsSource="{Binding Properties}"
              Grid.IsSharedSizeScope="True"
              Tag="{Binding MyObject}"
              ItemTemplateSelector="{StaticResource PropertyInfoTemplateSelector}"
              Margin="20"/>

我还使用此转换器在名称中添加了空格:

public class PropertyInfoNameConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string text = value as string;
        if (string.IsNullOrWhiteSpace(text))
            return string.Empty;
        StringBuilder newText = new StringBuilder(text.Length * 2);
        newText.Append(text[0]);
        for (int i = 1; i < text.Length; i++)
        {
            if (char.IsUpper(text[i]))
                if ((text[i - 1] != ' ' && !char.IsUpper(text[i - 1])) ||
                    (char.IsUpper(text[i - 1]) &&
                     i < text.Length - 1 && !char.IsUpper(text[i + 1])))
                    newText.Append(' ');
            newText.Append(text[i]);
        }
        return newText.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
公共类属性inFoNameConverter:IValueConverter
{
公共对象转换(对象值、类型targetType、对象参数、CultureInfo区域性)
{
字符串文本=作为字符串的值;
if(string.IsNullOrWhiteSpace(text))
返回字符串。空;
StringBuilder newText=新的StringBuilder(text.Length*2);
newText.Append(text[0]);
for(int i=1;i
(归功于此:)

正在更新类以包含一些布尔和fload字段:


非常好!谢谢
<ItemsControl x:Name="PropertyDisplay" ItemsSource="{Binding Properties}"
              Grid.IsSharedSizeScope="True"
              Tag="{Binding MyObject}"
              ItemTemplateSelector="{StaticResource PropertyInfoTemplateSelector}"
              Margin="20"/>
public class PropertyInfoNameConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        string text = value as string;
        if (string.IsNullOrWhiteSpace(text))
            return string.Empty;
        StringBuilder newText = new StringBuilder(text.Length * 2);
        newText.Append(text[0]);
        for (int i = 1; i < text.Length; i++)
        {
            if (char.IsUpper(text[i]))
                if ((text[i - 1] != ' ' && !char.IsUpper(text[i - 1])) ||
                    (char.IsUpper(text[i - 1]) &&
                     i < text.Length - 1 && !char.IsUpper(text[i + 1])))
                    newText.Append(' ');
            newText.Append(text[i]);
        }
        return newText.ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}