HandyControl PropertyGrid及自定义编辑器

前提条件

项目引入对应HandyControl对应版本包。

使用案例

UI部分

xml 复制代码
<Window xmlns:hc="https://handyorg.github.io/handycontrol">
    <hc:TabControl>
        <hc:TabItem Header="默认样式">
            <hc:PropertyGrid Width="380" SelectedObject="{Binding DemoModel}"/>
        </hc:TabItem>
    </hc:TabControl>
</Window>

数据实体

实体类PropertyGridDemoModel.cs

cs 复制代码
public class PropertyGridDemoModel
{
    [Category("类别1")]
    [DisplayName("字符串")]
    public string String { get; set; }

    [Category("类别2")]
    [DisplayName("整型")]
    public int Integer { get; set; }

    [Category("类别3")]
    [DisplayName("布尔型")]
    public bool Boolean { get; set; }

    [Category("类别1")]
    [DisplayName("枚举型")]
    public Gender Enum { get; set; }
    [DisplayName("枚举型")]
    public HorizontalAlignment HorizontalAlignment { get; set; }
    [DisplayName("枚举型")]
    public VerticalAlignment VerticalAlignment { get; set; }
    [DisplayName("图像类型")]
    public ImageSource ImageSource { get; set; }
}

public enum Gender
{
    [Description("男性")] //可考虑自定义编辑器,3.2不支持
    Male,
    [Description("女性")] //可考虑自定义编辑器,3.2不支持
    Female
}

设置数据上下文

当前为简化案例,直接在窗口后台进行上下文设置。

cs 复制代码
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DemoModel = new PropertyGridDemoModel
        {
            String = "TestString",
            Enum = Gender.Female,
            Boolean = true,
            Integer = 98,
            VerticalAlignment = VerticalAlignment.Stretch
        };
        DataContext = this;
    }

    public PropertyGridDemoModel DemoModel { get; private set; }
}

运行效果一

内置编辑器

HandyControl 内置了一下基础类型的编辑器,具体如下:

名称 说明
DatePropertyEditor 日期编辑器
DateTimePropertyEditor 日期时间编辑器
EnumPropertyEditor 枚举编辑器
HorizontalAlignmentPropertyEditor 水平对齐方式编辑器
ImagePropertyEditor 图片编辑器
NumberPropertyEditor 数字编辑器
PlainTextPropertyEditor 纯文本编辑器
ReadOnlyTextPropertyEditor 只读文本编辑器
SwitchPropertyEditor 布尔编辑器(开关风格)
TimePropertyEditor 时间编辑器
VerticalAlignmentPropertyEditor 垂直对齐方式编辑器

自定义编辑器

内置编辑器毕竟是有限的,不少需求需要进行编辑器自定义,自定义编辑器需要实现基类 PropertyEditorBase,假定需要实现一个带进度条的属性值,定义一个进度条编辑器,代码如下:

cs 复制代码
public class ProgressPropertyEditor : PropertyEditorBase
{
	// 重写对应的控件构建类,用于返回UI需要显示的控件实例
    public override FrameworkElement CreateElement(PropertyItem propertyItem)
    {
        var bar = new ProgressBar();
        bar.Maximum = 100;
        return bar;
    }
	// 设置对应实体属性与控件关联的依赖属性
    public override DependencyProperty GetDependencyProperty()
    {
       return System.Windows.Controls.ProgressBar.ValueProperty;
    }
}

添加属性并指定编辑器

PropertyGridDemoModel中,添加一个属性ProgressValue,并指定编辑器类型。

cs 复制代码
public class PropertyGridDemoModel
{
    //省略重复内容
    [Editor(typeof(ProgressPropertyEditor)
    , typeof(ProgressPropertyEditor))] // 必须指定编辑器!!!
	[DisplayName("自定义")]
	public int ProgressValue { get; set; }
    //省略重复内容
}

//省略重复内容

MainWindow.cs设置属性值。

cs 复制代码
public partial class MainWindow : Window
{
    public MainWindow()
    {
        //省略重复
        DemoModel = new PropertyGridDemoModel
        {
	        //省略重复
            ProgressValue = 12,// 模拟设置属性值
	        //省略重复
        };
        //省略重复
    }
    //省略重复
}

运行效果二

代码解析

控件PropertyGrid逻辑代码

cs 复制代码
// 应用模板
public override void OnApplyTemplate()
{
	// 省略代码
    UpdateItems(SelectedObject);
}

private void UpdateItems(object obj)
{
    if (obj != null && _itemsControl != null)
    {
        _dataView = CollectionViewSource.GetDefaultView((from item in TypeDescriptor.GetProperties(obj.GetType()).OfType<PropertyDescriptor>(
                                                         where PropertyResolver.ResolveIsBrowsable(item)
                                                         select item).Select(CreatePropertyItem).Do(delegate (PropertyItem item)
                                                     {
                                                         item.InitElement();
                                                     }));
        SortByCategory(null, null);
        _itemsControl.ItemsSource = _dataView;
    }
}

protected virtual PropertyItem CreatePropertyItem(PropertyDescriptor propertyDescriptor)
{
    return new PropertyItem
    {
		// 省略代码
		// 获取编辑器
        Editor = PropertyResolver.ResolveEditor(propertyDescriptor),
    };
}

属性解析器PropertyResolver

cs 复制代码
public PropertyEditorBase ResolveEditor(PropertyDescriptor propertyDescriptor)
{
    EditorAttribute editorAttribute = propertyDescriptor.Attributes.OfType<EditorAttribute>().FirstOrDefault();
    if (editorAttribute != null && !string.IsNullOrEmpty(editorAttribute.EditorTypeName))
    {
	    // 获取自定义编辑器
        return CreateEditor(Type.GetType(editorAttribute.EditorTypeName));
    }
	// 创建内置编辑器实例
    return CreateDefaultEditor(propertyDescriptor.PropertyType);
}

// 创建自定义编辑器实例
public virtual PropertyEditorBase CreateEditor(Type type)
{
    return (Activator.CreateInstance(type) as PropertyEditorBase) ?? new ReadOnlyTextPropertyEditor();
}

问题思考

编辑器如何外部传入控件的多参数值,可以考虑自定义解析器。

相关推荐
当下就是最好2 小时前
WPF应用程序的生命周期-笔记
wpf
九鼎科技-Leo17 小时前
什么是 WPF 中的依赖属性?有什么作用?
windows·c#·.net·wpf
麻花20131 天前
C#之WPF的C1FlexGrid空间的行加载事件和列事件变更处理动态加载的枚举值
开发语言·c#·wpf
lcintj1 天前
【WPF】Prism学习(九)
学习·wpf·prism
界面开发小八哥1 天前
界面控件DevExpress WPF中文教程:网格视图数据布局的列和卡片字段
wpf·界面控件·devexpress·ui开发·用户界面
△曉風殘月〆1 天前
如何在WPF中嵌入其它程序
wpf
Crazy Struggle1 天前
功能齐全的 WPF 自定义控件资源库(收藏版)
.net·wpf·ui控件库
shepherd枸杞泡茶2 天前
WPF动画
c#·.net·wpf
lcintj2 天前
【WPF】Prism学习(十)
学习·wpf·prism
wyh要好好学习2 天前
WPF数据加载时添加进度条
ui·wpf