PropertyGridLib 1.5.0

dotnet add package PropertyGridLib --version 1.5.0
                    
NuGet\Install-Package PropertyGridLib -Version 1.5.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="PropertyGridLib" Version="1.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="PropertyGridLib" Version="1.5.0" />
                    
Directory.Packages.props
<PackageReference Include="PropertyGridLib" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add PropertyGridLib --version 1.5.0
                    
#r "nuget: PropertyGridLib, 1.5.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package PropertyGridLib@1.5.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=PropertyGridLib&version=1.5.0
                    
Install as a Cake Addin
#tool nuget:?package=PropertyGridLib&version=1.5.0
                    
Install as a Cake Tool

PropertyGridLib

WPF PropertyGrid 控件库 — 仿 WinForms PropertyGrid,基于 HandyControl UI 库。

版本 1.4.0 | .NET Framework 4.8+ / .NET 6/7/8-windows | HandyControl 3.5.1 | 作者:WangShuo

📦 相关仓库

仓库 地址
本库(PropertyGridLib) NuGet:Install-Package PropertyGridLib -Version 1.4.0
Demo 项目 https://github.com/1wangshuo/PropertyGridDemo
技能文档 skill/SKILL.md(多页使用文档:基础用法 / 特性清单 / 编辑器类型 / 主题多语言 / 公式绑定 / PropertyGridPro / 示例模型 / FAQ)

✨ v1.4.0 新特性

  • ✅ 📐 Small 紧凑布局(TitlePlacement 新属性) — 属性行标题可在「编辑器上方(Top,默认)」与「编辑器左侧(Left)」之间切换;Left 时标题与编辑器平齐一行,对齐 HandyControl 表单左标题风格,行高压缩近一半。R 复位按钮保留在编辑器右侧,值被修改时标题右侧出现红点;公式绑定区与子属性列表仍另起一行
  • ✅ 🅰️ 标题/分类头字体粗细(TitleFontWeight / CategoryFontWeight) — 新增两个可配置属性,分别控制属性行标题(如 1.设备名称)与分类头(如 I.基本信息)的 FontWeight,默认 Bold,可按需设为 Normal / Light / SemiBold 等,解决 release 版本标题视觉上偏细的问题
  • ✅ ⚡ 属性列表 UI 虚拟化 — 类别 Expander → 内层 ItemsControl 的两层嵌套压平为单层列表,开启虚拟滚动,只生成视口内行并复用容器。切换选中 → 属性页重建 206ms → 8ms,重复刷新托管堆增长 44.5MB → 14.6MB。新增 EnableVirtualization 开关(默认 true),遇自定义模板串值时可回退到全量生成
  • ✅ 🔌 事件页能力 — ShowEventsPage 开关 + EventPicker 事件筛选选择器 + EventItem 模型 + EventEditorControl 行内编辑器;默认关闭,不影响旧行为,开启后便于设计器宿主把事件绑定与代码编辑器(如 CodeForge)打通
  • ✅ 🐛 稳定性修复 — SelectedObject 置 null / 传入已销毁对象时不再崩溃;加载指示由 LoadingCircle 动画改为静态文本,消除动画时钟在快速显隐元素上的持续 tick

✨ v1.3.0 新特性

  • ✅ 🧩 PropertyGridPro 平铺参数面板(新控件) — 纵向平铺、卡片式属性行,面向「参数面板 / 属性面板」场景:Header / HeaderDescription / SourceText 头部区、EditorWidth 统一编辑器宽度、RowTemplate 可整体替换行模板;属性搜索附匹配计数与空结果提示;与 PropertyGrid 共用同一套特性、编辑器模板、本地化与主题资源,模型无需改动即可互换

    PropertyGridPro 平铺面板(浅色)

  • ✅ 🃏 卡片式属性行布局 — 属性行改为卡片承载(圆角 7、行间距、分类头独立成卡片),底色取主题次级区域画刷(SecondaryRegionBrush),深浅主题下层次一致

    卡片式行布局

  • ✅ 🌓 主题色跟随(去除硬编码) — 面板模板中硬编码的深色全部替换为 SkinDark / ThemeHelper 等主题资源键,卡片背景、边框、标题与描述文字、分类头、嵌套引导线均随主题切换

    主题跟随对比

  • ✅ 🪜 无限嵌套样式统一 — 复杂对象子属性以卡片逐层铺开并按层级缩进 + 引导线,层级不限;统一了各层级的间距、圆角与引导线样式

    多级嵌套

  • ✅ 🔗 公式绑定接入 Pro 面板 — [FormulaEditor] 属性在 PropertyGridPro 中同样显示公式绑定区(值编辑器 + 链接图标 + 公式文本框 + 树选择器 Popup),并支持全局 FormulaTreeProvider

    公式绑定行

  • ✅ 📐 复位按钮常驻占位(消除布局抖动) — 复位按钮可见性由 Collapsed 改为 Hidden(新增 BoolToHiddenVisibilityConverter),未悬停时仍保留占位,实测同行的值编辑器位移 0px,不再左右跳动

    复位按钮占位

  • ✅ 🔀 [ToggleSwitch] 布尔开关特性(新特性) — bool 专用编辑器:滑块式开关(圆角轨道 + 圆形滑块,HandyControl ToggleButtonSwitch 样式)+可选的开/关状态文字([ToggleSwitch("已启用","已禁用")] / OnText / OffText,传 null 可隐藏文字);基类与 Pro 面板通过同一 EditorSelector 复用生效,未标注的 bool 属性保持默认开关外观(无状态文字)

    ToggleSwitch 布尔开关

  • ✅ 🧹 演示程序清理 — 移除演示旧模型(右侧「实时值」区块与旧对象演示),Pro 演示窗口统一改用与基类一致的 SampleObject


✨ v1.2.0 新特性

  • ✅ 🔌 宿主自定义编辑器扩展机制 — PropertyGrid.RegisterEditor<TAttr>(DataTemplate) 一行注册,宿主侧定义 Attribute + DataTemplate 即可让 PropertyGrid 渲染自定义编辑器;框架对此 Attribute 一无所知。内置 CustomEditors 静态字典 + PropertyItem.CustomEditorTemplate / CustomEditorAttribute 属性,EditorTemplateSelector 优先返回宿主模板,完全覆盖框架内置编辑器的渲染路径
  • ✅ 🎨 颜色编辑器 — 自动识别 Color / Color? / SolidColorBrush 类型,显示为颜色预览块 + ... 按钮(紧凑居左,与 FilePath/Dictionary 编辑器风格统一);点击弹出 HandyControl ColorPicker(StaysOpen=true + 手动外部点击检测,支持拖动 Slider 不丢失焦点,点"确定"才应用值);预览块显示 #RRGGBB(不透明时省略 Alpha 前缀)
  • ✅ 📁 字典嵌套字典自动弹窗 — 字典值为集合(IDictionary / IList)时不再内联,改为显示"N 项 + ..."按钮,点击弹出二级编辑器(模态覆盖父级,UI 不会无限拉长);字典值为复杂对象时仍内嵌 PropertyGrid 就地编辑
  • ✅ 🌳 FormulaTree 类型提示 — FormulaTreeNode 新增 FormulaType / TypeHint 属性,TreeView 弹窗叶子节点右侧显示淡蓝色斜体类型名(如 (int) (DateTime)),宿主可通过 ShowTypeHint=False 关闭;Category 前缀改为罗马数字(I. II. III.),切换中英文时分类顺序稳定
  • ✅ 🔤 全局字体同步 — PropertyGrid.FontSize / FontFamily 动态变化时通过 DependencyPropertyDescriptor 实时更新 GlobalFontSize / GlobalFontFamily,所有 Dialog(字典、集合、文件夹、颜色)打开时自动读取最新值
  • ✅ 🌓 HandyControl 主题切换修复 — SetAppSkin 改为直接改 Theme.Skin 属性(HC 官方推荐方式),白→黑→白双向切换均正常,不再因替换 MergedDictionaries 导致重复 key 冲突

✨ v1.1.2 新特性

  • ✅ 命令按钮编辑器 [Button] — 属性标记后渲染为按钮,点击可反射调用宿主方法(Action)并触发 ButtonClicked 事件;新增静态 PropertyGrid.GlobalButtonClicked 全局事件,主网格与集合/字典内嵌网格中的按钮点击都能被宿主统一捕获
  • ✅ 字典编辑器(IDictionary) — 自动识别字典属性;新增 DictionaryEditorDialog(弹窗)与 DictionaryEditorControl(内联,当 SelectedObject 直接是字典时);键、值均可为简单类型或复杂对象(内嵌 PropertyGrid,可无限嵌套),两者都是对象时左右各占 50%
  • ✅ 修复字典 "..." 按钮无响应 的历史缺陷(字典曾被当作集合但 EditCollection 只处理 IList)
  • ✅ 修复嵌套网格中按钮"失效"(内嵌 PropertyGrid 的按钮事件无法上抵宿主、且不刷新)
  • ✅ 新增 .NET Core 3.0 / 3.1 目标框架(连同 net48 / net6 / net7 / net8-windows)

✨ v1.1.1 新特性

  • ✅ 集合编辑器内联显示 — 当 PropertyGrid.SelectedObject 设为 IList 类型时,自动内联显示集合编辑器(无需弹出对话框)
  • ✅ 集合编辑器 UserControl 化 — CollectionEditorControl / SimpleCollectionEditorControl 可独立作为 UserControl 嵌入任意容器
  • ✅ FormulaBindingControl 独立使用 — 新增 TreeItemsSource / FormulaTreeProvider 依赖属性,支持脱离 PropertyGrid 直接使用
  • ✅ 简单类型自动检测 — 内联模式自动区分简单类型(string/int/double 等)和复杂对象,选择对应编辑器

✨ v1.1.0 新特性

  • ✅ 完全移除 System.Windows.Forms 依赖 - 纯 WPF 实现
  • ✅ 多框架支持 - .NET Framework 4.8 / .NET 6/7/8-windows
  • ✅ HandyControl 主题集成 - 所有对话框自动跟随深色/浅色主题
  • ✅ 自定义文件夹浏览器 - 纯 WPF 实现,树形目录浏览
  • ✅ 文件夹浏览器支持手动输入路径自动定位 - 输入合法路径自动在树上选中
  • ✅ 完整中英文多语言 - 所有新增组件支持语言切换
  • ✅ 现代化序列化 - JSON 替代 BinaryFormatter
  • ✅ 零依赖冲突 - System.Text.Json 向上兼容到 16.0+

目录


安装

NuGet 包管理器

Install-Package PropertyGridLib -Version 1.3.0

.NET CLI

dotnet add package PropertyGridLib --version 1.3.0

PackageReference (PackageReference)

<PackageReference Include="PropertyGridLib" Version="1.3.0" />

安装后,NuGet 会自动拉取依赖项 HandyControl 3.5.1。

🎯 单 DLL 部署

PropertyGridLib 使用 Costura.Fody 将 HandyControl.dll、System.Text.Json.dll 等依赖嵌入合并到主 DLL 内。

PropertyGridLib.dll  ← 唯一需要部署的 DLL(内部已嵌入 HandyControl 等)

宿主项目只需引用这一个 DLL,无需额外附带 HandyControl.dll。运行时通过 AssemblyResolve 事件自动从内嵌资源加载依赖。

⚠️ 若宿主项目也直接引用了 HandyControl(版本可能不同),两个内嵌的 HandyControl 会并存。建议宿主统一使用 PropertyGridLib 内嵌的版本,或在宿主 csproj 中显式指定 HandyControl 版本以覆盖内嵌。


快速开始

1. 添加命名空间

xmlns:pg="clr-namespace:PropertyGridLib;assembly=PropertyGridLib"

2. 在 XAML 中使用

<pg:PropertyGrid x:Name="propertyGrid"
                 Width="400"
                 Height="600"
                 ShowSearchBar="True"
                 ShowDescription="True"/>

3. 绑定对象

propertyGrid.SelectedObject = new MyConfig();

4. 重置与刷新

propertyGrid.ResetSelectedToDefault();  // 重置当前选中属性
propertyGrid.ResetAllToDefault();       // 重置所有属性
propertyGrid.RefreshProperties();        // 刷新属性列表

命名空间

命名空间 内容
PropertyGridLib PropertyGrid 控件、IPropertyLocalization 接口
PropertyGridLib.Controls PropertyItem、IPropertyItem、PropertyCategory、EditorTemplateSelector、FormulaBound<T>、FormulaTreeNode、IFormulaTreeProvider、IMultiSelectProvider、MultiSelectControl、FormulaBindingControl、CollectionEditorControl、SimpleCollectionEditorControl、DictionaryEditorControl、ColorEditControl、PropertyButtonClickEventArgs、CustomEditorType 枚举
PropertyGridLib.Attributes FilePathAttribute、DirectoryPathAttribute、CollectionEditorAttribute、NumberSliderAttribute、FormulaEditorAttribute、MultiSelectAttribute、ButtonAttribute、ToggleSwitchAttribute
PropertyGridLib.Dialogs FolderBrowserDialog、CollectionEditorDialog、SimpleCollectionEditorDialog、DictionaryEditorDialog
PropertyGridLib.Localization LocalizationManager、LocalizationProxy、LocalizedExtension、Language 枚举
PropertyGridLib.Converters BoolToVisibilityConverter、InverseBoolConverter、ObjectToTypeConverter、ColorToBrushConverter 等值转换器

标准 .NET 特性

PropertyGrid 自动识别以下标准 .NET 特性:

特性 说明 示例
[Category("分类名")] 属性分组显示 [Category("外观")]
[DisplayName("显示名")] 自定义属性显示名称 [DisplayName("字体大小")]
[Description("描述")] 底部描述栏显示 [Description("文字的字体大小")]
[DefaultValue(value)] 默认值,控制重置按钮显示 [DefaultValue(14)]
[ReadOnly(true)] 只读属性,不可编辑 [ReadOnly(true)]
[Browsable(false)] 隐藏属性,不在列表中显示 [Browsable(false)]

自定义特性

FilePathAttribute — 文件路径选择

标记属性为文件路径,显示浏览按钮,点击弹出文件选择对话框。支持多后缀筛选。

using PropertyGridLib.Attributes;

// 单后缀
[FilePath("*.log")]
public string LogFilePath { get; set; } = "";

// 多后缀
[FilePath("*.json", "*.xml", "*.txt")]
public string ConfigFilePath { get; set; } = "";

可选属性:

属性 类型 说明
Filters string[] 文件后缀列表(构造函数参数)
Filter string 完整过滤器字符串(如 "*.json;*.xml")
InitialDirectory string 初始目录
Title string 对话框标题
Multiselect bool 是否允许多选

DirectoryPathAttribute — 目录路径选择

标记属性为目录路径,显示浏览按钮,点击弹出文件夹选择对话框(纯 WPF 实现,支持 HandyControl 主题)。

[DirectoryPath]
public string DataDirectory { get; set; } = "";

可选属性:

属性 类型 说明
InitialDirectory string 初始目录
Title string 对话框标题

特性:

  • 树形目录浏览
  • 支持路径直接输入
  • 自动跟随 HandyControl 深色/浅色主题
  • 完整的中英文多语言支持

CollectionEditorAttribute — 集合编辑器

标记集合类型属性使用编辑器对话框。简单类型(string、int 等)使用简易编辑器,复杂对象使用完整编辑器(含属性面板)。

// 简单类型集合 — 弹出简易编辑器(输入框 + 列表 + 增删排序)
[CollectionEditor]
public List<string> Tags { get; set; } = new List<string> { "A", "B" };

// 复杂对象集合 — 弹出完整编辑器(列表 + 属性面板 + 增删复制排序)
[CollectionEditor]
public List<RobotConfig> Robots { get; set; } = new List<RobotConfig>();

可选属性:

属性 类型 默认值 说明
CanAdd bool true 是否允许添加新项
CanRemove bool true 是否允许删除项
CanCopy bool true 是否允许复制项
CanSort bool true 是否允许上移/下移排序

集合编辑器自动区分简单类型和复杂对象。无需手动指定,控件会根据 List<T> 的 T 类型自动选择合适的编辑器。


NumberSliderAttribute — 数值滑块

将数值属性显示为滑块编辑器,支持 int、double、float、decimal 等数值类型。

// 整数滑块
[NumberSlider(0, 100, 5)]  // min, max, step
public int Volume { get; set; } = 50;

// 小数滑块(默认显示只读数值标签)
[NumberSlider(0.0, 1.0, 0.1)]
public double Brightness { get; set; } = 0.8;

// 滑块 + 可编辑数字框(hc:NumericUpDown,可键入小数等精确值;min/max/step 与滑块共用,
// 双向同步;显示后取代只读数值标签)
[NumberSlider(0, 100, 5, ShowNumberBox = true)]
public double Opacity { get; set; } = 50;

参数说明:

参数 类型 说明
minimum double 最小值
maximum double 最大值
step double 步长(默认 1)
ShowNumberBox bool 是否显示可编辑数字输入框(默认 false;启用后与滑块双向同步并取代数值标签)

FormulaEditorAttribute — 公式绑定

标记属性支持公式绑定编辑器。标记后,属性编辑器下方会额外显示一行公式绑定区(链接图标 + 公式文本框 + Popup 树选择器)。

// 需要实现 IFormulaTreeProvider 接口
[FormulaEditor(typeof(MyFormulaTreeProvider))]
public FormulaBound<string> NameFormula { get; set; } = new FormulaBound<string> { Value = "默认值" };

IFormulaTreeProvider 接口:

using PropertyGridLib.Controls;

public class MyFormulaTreeProvider : IFormulaTreeProvider
{
    public List<FormulaTreeNode> GetFormulaTree(PropertyItem propertyItem)
    {
        return new List<FormulaTreeNode>
        {
            new FormulaTreeNode
            {
                Header = "流程A",
                Children = new List<FormulaTreeNode>
                {
                    new FormulaTreeNode
                    {
                        Header = "任务1",
                        Children = new List<FormulaTreeNode>
                        {
                            new FormulaTreeNode { Header = "属性X", Formula = "&{流程A.任务1.属性X}" }
                        }
                    }
                }
            }
        };
    }
}

FormulaTreeNode 属性:

属性 类型 说明
Header string 节点显示文本
Formula string 选中后填入的公式字符串(仅叶子节点需要设置)
Children List<FormulaTreeNode> 子节点列表
FormulaType Type? 叶子节点的数值类型(如 typeof(int)),用于 TreeView 弹窗显示类型提示
TypeHint string 自动从 FormulaType 生成的类型提示(如 (int)、(string))

MultiSelectAttribute — 多选列表

标记属性为多选列表编辑器,弹出 CheckBox 列表供用户多选。属性类型应为 List<string>,Provider 动态返回可选项。

// 需要实现 IMultiSelectProvider 接口
[MultiSelect(typeof(MyMultiSelectProvider))]
public List<string> SelectedOptions { get; set; } = new List<string>();

IMultiSelectProvider 接口:

using PropertyGridLib.Controls;

public class MyMultiSelectProvider : IMultiSelectProvider
{
    public List<string> GetAvailableItems(PropertyItem propertyItem)
    {
        return new List<string> { "选项A", "选项B", "选项C", "选项D" };
    }
}

ButtonAttribute — 命令按钮

标记属性为命令按钮。被标记的属性不再显示值编辑器,而是渲染为一个按钮;点击后:① 通过反射调用宿主对象上 Action 指定的方法(若指定);② 触发 PropertyItem.ButtonClicked 与 PropertyGrid.ButtonClicked / 静态 PropertyGrid.GlobalButtonClicked 事件。

using PropertyGridLib.Attributes;

// 仅触发事件(文本回退到 DisplayName,随多语言切换)
[Button]
public object GreetButton { get; set; }

// 指定按钮文本 + 点击时反射调用的宿主方法(无参或单参)
[Category("操作")]
[DisplayName("测试连接")]
[Button("测试连接", nameof(TestConnection))]
public object TestConnectionButton { get; set; }

public void TestConnection() { /* 点击后由库反射调用 */ }

宿主侧统一响应(推荐订阅静态全局事件,可捕获集合/字典内嵌网格中的按钮):

PropertyGrid.GlobalButtonClicked += (s, e) =>
{
    // e.PropertyName / e.PropertyItem / e.Owner
    Console.WriteLine($"{e.PropertyName} 被点击");
};
// 静态事件,窗口关闭时记得取消订阅:PropertyGrid.GlobalButtonClicked -= handler;

参数说明:

参数 类型 说明
text string 按钮文本;为空时回退到 DisplayName
action string 点击时反射调用的宿主方法名(无参或单参);为空时仅触发事件

建议将按钮属性声明为 object/string 占位类型(值可为 null)。按钮默认始终可点,仅当属性显式标注 [ReadOnly(true)] 时禁用。


ToggleSwitchAttribute — 布尔开关

标注在 bool 属性上时,属性行的编辑器渲染为「滑块式开关(圆角轨道 + 圆形滑块)+ 开/关状态文字」(基于 HandyControl ToggleButtonSwitch 样式);未标注的 bool 属性保持默认显示(同样是滑块开关,但不带状态文字)。该特性仅对 bool 生效,标注在其它类型属性上会被忽略。

using PropertyGridLib.Attributes;

[Category("开关")]
[DisplayName("启用记录回放")]
[ToggleSwitch]                                     // 默认状态文字「开 / 关」
public bool LoopRecording { get; set; }

[ToggleSwitch("已启用", "已禁用")]                  // 自定义状态文字
public bool UseHttps { get; set; }

[ToggleSwitch(OnText = null, OffText = null)]       // 只显示开关,不显示文字
public bool IsEnabled { get; set; }

参数说明:

参数 类型 说明
onText string 打开(true)状态文字,默认「开」;为 null 或空字符串表示不显示文字
offText string 关闭(false)状态文字,默认「关」;为 null 或空字符串表示不显示文字

两个参数也可作为命名参数单独设置,例如 [ToggleSwitch(OnText = "在线")]。 编辑器由 EditorTemplateSelector.ToggleSwitchTemplate 提供:宿主/派生控件可覆写该属性以替换开关外观;模板缺失时自动回退到默认 bool 编辑器,不会出现空白行。

实际渲染效果(浅色主题):

未标注(默认 bool) [ToggleSwitch] [ToggleSwitch("已启用","已禁用")]
默认 bool 默认文字 自定义文字
开关区域(浅色) 开关区域(深色)
浅色 深色

🎨 颜色编辑器

自动检测

PropertyGrid 自动识别以下类型,无需任何特性:

类型 处理方式
Color 值类型,双向编辑
Color? 可空,支持 null
SolidColorBrush 取 Brush.Color 编辑,写回时重建 SolidColorBrush

UI 布局

┌──────────────────┐ ┌──────┐
│ ■ #FF0000        │ │  ... │
└──────────────────┘ └──────┘
   颜色预览块 + HEX      编辑按钮
  • 居左占满宽度,与 FilePath/Dictionary 编辑器风格统一
  • 预览块:16×16 颜色方块 + #AARRGGBB HEX 文本
  • 不透明颜色(Alpha=255)时省略 Alpha 前缀,显示 #RRGGBB
  • 深色/浅色主题自动适配

交互流程

点击 ... 按钮弹出 HandyControl ColorPicker:

操作 行为
拖动 Slider / 选色块 ColorPicker 内部预览,不修改 PropertyItem.Value
点"确定" 写入 PropertyItem.Value → 关闭弹窗
点"取消" 不改值 → 关闭弹窗
点弹窗外面 不改值 → 关闭弹窗

关键技术点

  • StaysOpen=true + 手动 Window.PreviewMouseDown 检测外部点击(避免 HC ColorPicker 内部 Slider 拖动导致 Popup 误判关闭)
  • IsInVisualTree() 从 OriginalSource 向上遍历 VisualTree 判定点击来源
  • Freeze() 创建 SolidColorBrush 防止绑定循环警告
  • DependencyPropertyDescriptor 监听 FontSize/FontFamily 变化,ColorPicker 弹窗自动同步宿主字体

FormulaBound 属性的颜色提示

当属性带 [FormulaEditor] 且 ShowTypeHint=True 时,公式绑定区右侧显示淡蓝色斜体类型提示(如 (string)、(int)),颜色与公式输入框区分。


📁 字典编辑器(IDictionary)

字典属性(Dictionary<TKey,TValue> 等 IDictionary)会被自动识别,显示为 "N 项 + ..." 按钮,点击弹出 DictionaryEditorDialog。无需任何特性;若把 [CollectionEditor] 标在字典属性上,也会路由到字典编辑器。

// 简单键值:键、值都用文本框编辑(自动类型转换)
public Dictionary<string, int> ScoreMap { get; set; } = new Dictionary<string, int>();

// 复杂值:值区显示内嵌 PropertyGrid,可继续编辑其内部的集合/字典(无限嵌套)
public Dictionary<string, RobotConfig> Robots { get; set; } = new Dictionary<string, RobotConfig>();

// 复杂键:键区也显示内嵌 PropertyGrid(键类型需重写 Equals/GetHashCode)
public Dictionary<ServerEndpoint, string> Endpoints { get; set; } = new Dictionary<ServerEndpoint, string>();

// ===== 嵌套字典:值为字典时自动弹窗 =====
// 框架检测到值类型是 IDictionary → 显示 "N 项 ..." 按钮,点击弹出二级字典编辑器
public Dictionary<string, Dictionary<string, int>> NestedConfig { get; set; } = new()
{
    { "白天模式", new Dictionary<string, int> { { "人员检测", 6 }, { "车辆检测", 5 } } },
    { "夜间模式", new Dictionary<string, int> { { "人员检测", 8 }, { "车辆检测", 7 } } }
};

// ===== 字典值为列表:同样弹窗 =====
public Dictionary<string, List<string>> ZoneAlerts { get; set; } = new()
{
    { "大门", new List<string> { "2024-03-15 检测到人员" } }
};

嵌套值的三种渲染模式

值类型 检测 UI 表现 编辑方式
简单类型(string/int/double 等) IsSimpleType TextBox 就地文本编辑
集合类型(IDictionary / IList) IsDictionaryType / IsListType "N 项 ..."按钮 点击弹窗(模态覆盖父级)
其他复杂对象 排除以上两种 内嵌 PropertyGrid 就地编辑(可继续嵌套其属性)

内联模式

当 PropertyGrid.SelectedObject 直接设为字典时,自动内联显示 DictionaryEditorControl(就地编辑、实时写回,无弹窗),与集合内联模式一致。

propertyGrid.SelectedObject = new Dictionary<string, int> { { "A", 1 }, { "B", 2 } };

独立使用

DictionaryEditorControl(PropertyGridLib.Controls)可作为 UserControl 嵌入任意容器,Items 为 IDictionary,直接操作源字典。

⚠️ 复杂键为可变对象时,就地编辑会改变其哈希——编辑器在"确定/切换条目"时会 Clear + 重新 Add 重建哈希;复杂键类型务必重写 Equals/GetHashCode。另注意 System.Text.Json 不支持非字符串字典键,故复杂键字典不宜作为会被深拷贝(Reset)的 [Serializable] 模型属性。


🔌 宿主自定义编辑器扩展机制

PropertyGridLib 提供通用扩展点,宿主只需 3 步即可让自定义编辑器生效,框架对此 Attribute 一无所知。

完整流程

宿主侧: [MyUnitEditor("GB,MB,KB", "MB")] 属性
  → PropertyGrid.RegisterEditor<MyUnitEditorAttribute>(template)  // 注册
    → PropertyItem.DetectCustomEditor 发现 Attribute
      → CustomEditorTemplate = template, CustomEditorAttribute = attr  // 存起来
        → EditorTemplateSelector.SelectTemplate 优先返回 CustomEditorTemplate  // 渲染
          → DataTemplate 里 NumericUpDown + ComboBox
            → ComboBox Loaded 从 CustomEditorAttribute 读参数  // 宿主解析参数

Step 1 — 宿主定义 Attribute

// 纯宿主侧,框架对此类型一无所知
[AttributeUsage(AttributeTargets.Property)]
public class MyUnitEditorAttribute : Attribute
{
    public string Units { get; }
    public string DefaultUnit { get; set; }

    public MyUnitEditorAttribute(string units) => Units = units;
}

Step 2 — 宿主定义 DataTemplate


<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            
            <ResourceDictionary Source="pack://application:,,,/PropertyGridLib;component/Themes/Generic.xaml"/>
            <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/>
            <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/>
        </ResourceDictionary.MergedDictionaries>

        <DataTemplate x:Key="MyUnitEditorTemplate">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="Auto"/>
                </Grid.ColumnDefinitions>
                <hc:NumericUpDown Grid.Column="0"
                                  Value="{Binding ValueString, ...}"
                                  Margin="0,0,4,0"/>
                <ComboBox Grid.Column="1"
                          Loaded="UnitCombo_Loaded"
                          SelectionChanged="UnitCombo_SelectionChanged"/>
            </Grid>
        </DataTemplate>
    </ResourceDictionary>
</Application.Resources>

Step 3 — 宿主注册

// MainWindow 构造函数中(必须在 PropertyGrid.SelectedObject 赋值前注册)
PropertyGridLib.PropertyGrid.RegisterEditor<MyUnitEditorAttribute>(
    (DataTemplate)FindResource("MyUnitEditorTemplate"));

Step 4 — 使用

[MyUnitEditor("GB,MB,KB", "MB")]
public double FileSize { get; set; } = 256;

模板内读 Attribute 参数

宿主在 DataTemplate 的 code-behind 中,从 PropertyItem.CustomEditorAttribute 拿到宿主 Attribute 实例,再读参数:

private void UnitCombo_Loaded(object sender, RoutedEventArgs e)
{
    if (sender is ComboBox combo && combo.DataContext is PropertyItem pi)
    {
        var attr = pi.CustomEditorAttribute as MyUnitEditorAttribute;
        if (attr == null) return;

        var units = (attr.Units ?? "").Split(',').Select(s => s.Trim()).ToList();
        combo.ItemsSource = units;
        combo.SelectedItem = !string.IsNullOrEmpty(attr.DefaultUnit)
            ? attr.DefaultUnit
            : units.FirstOrDefault();
    }
}

API 参考

成员 类型 说明
PropertyGrid.CustomEditors Dictionary<Type, DataTemplate> 静态注册字典,宿主可直接操作或通过 RegisterEditor 泛型方法
PropertyGrid.RegisterEditor<TAttribute>(template) static void 泛型注册方法,一行搞定
PropertyItem.CustomEditorTemplate DataTemplate? 宿主注册的编辑器模板,非 null 时 EditorTemplateSelector 优先使用
PropertyItem.CustomEditorAttribute Attribute? 宿主 Attribute 实例,模板 code-behind 可读取参数

优先级

宿主注册 高于 框架内置。DetectCustomEditor 最前面先查 PropertyGrid.CustomEditors,找到就返回,内置的 Slider/Color/FilePath/Dictionary 都排在后面。宿主甚至可以覆盖框架内置编辑器的行为 — 比如给带 [NumberSlider] 的属性也注册一个自己的模板。


🌳 FormulaTree 类型提示

FormulaTreeNode 支持在 TreeView 弹窗中显示叶子节点的类型信息,帮助用户判断绑定源的类型是否匹配目标属性。

宿主设置类型

var provider = new DemoFormulaTreeProvider();
// 叶子节点设置 FormulaType
new FormulaTreeNode
{
    Header = "任务A.值",
    Formula = "&{Flow2,TaskA,Value}",
    FormulaType = typeof(int)  // ← 宿主指定类型
}

PropertyGrid 控制显示

<pg:PropertyGrid ShowTypeHint="False" .../>
属性 类型 默认值 说明
ShowTypeHint bool true 是否显示类型提示(FormulaTree 弹窗 + 公式绑定区)

效果

├─ ▼ 流程2
│    任务A.值          (int)    ← 淡蓝色斜体,靠右
│    任务B.计数        (double)
│    任务C.启用状态    (bool)
  • 非叶子节点(分类容器)不填 FormulaType,不显示类型提示
  • TypeHint 自动从 FormulaType 生成,宿主也可直接覆盖 TypeHint 属性
  • 颜色 InfoBrush + Italic + 比正常小 2 号,与节点 Header 区分

🧩 PropertyGridPro 平铺参数面板

PropertyGridPro 是 1.3.0 新增的控件,与 PropertyGrid 同源:共用同一套特性体系、编辑器模板、本地化与主题资源,模型代码无需任何改动即可在两者之间切换;区别在于布局形态与面向场景。

对比项 PropertyGrid PropertyGridPro
整体布局 分类 + 可折叠树形层级(仿 WinForms) 纵向平铺,属性与分组直接铺开,列表整体滚动
属性行 通栏式行 卡片式行(圆角、行间距、分类头卡片)
头部区 无 Header + HeaderDescription + SourceText
属性搜索 有(过滤属性行) 有(过滤 + 匹配计数 + 空结果提示)
编辑器宽度 随行自适应 EditorWidth 统一控制,行内编辑器对齐
行模板 内置 RowTemplate 可整体替换
适用场景 层级深、属性多、需要折叠收纳 参数面板 / 属性面板,强调一屏扫读
PropertyGridPro(浅色) PropertyGridPro(深色)
Pro 浅色 Pro 深色

用法

<pg:PropertyGridPro x:Name="PropertyGridPro1"
                    Header="参数配置"
                    HeaderDescription="修改后立即生效"
                    SourceText="MyApp.Models.SampleObject"
                    ShowHeader="True"
                    ShowSearchBar="True"
                    ShowDescription="True"
                    EditorWidth="220"/>
PropertyGridPro1.SelectedObject = new SampleObject();

依赖属性与方法

成员 类型 说明
SelectedObject object 要编辑的目标对象(与 PropertyGrid 一致)
Header string 面板标题
HeaderDescription string 标题下的说明文字
SourceText string 来源说明(如模型类型全名)
ShowHeader bool 是否显示头部区(默认 true)
ShowSearchBar bool 是否显示属性搜索栏(默认 true)
ShowDescription bool 是否显示底部描述栏(默认 true)
EditorWidth double 行内编辑器统一宽度
RowTemplate DataTemplate 整行卡片模板,可整体替换外观
RefreshProperties() 方法 刷新属性列表
ResetAllToDefault() / ResetSelectedToDefault() 方法 重置全部 / 当前选中属性
SetSubPropertiesExpanded(bool) 方法 批量展开或折叠所有嵌套子属性

卡片式行布局与无限嵌套

属性行以卡片承载:圆角 7、行间距、分类头独立成卡片,卡片底色取主题次级区域画刷(SecondaryRegionBrush);复杂对象的子属性逐层铺开,按层级增加缩进与引导线,层级不限。

卡片式行细节 多级嵌套(浅色) 多级嵌套(深色)
卡片细节 嵌套浅色 嵌套深色

搜索

命中(浅色) 无匹配(浅色) 命中(深色) 无匹配(深色)
命中 空结果 命中深色 空结果深色

完整用法(含公式绑定、布尔开关在 Pro 中的表现、主题与多语言)见 skill/06-PropertyGridPro-平铺参数面板.md。


编辑器类型总览

控件根据属性类型和特性自动选择编辑器模板:

编辑器 触发条件 显示效果
TextBox string 类型 文本输入框
ToggleSwitch(默认 bool) bool / bool? 滑块式开关(圆角轨道 + 圆形滑块,无状态文字)
ToggleSwitch(带文字) [ToggleSwitch] 特性(bool) 滑块式开关 + 开/关状态文字(文字可自定义或隐藏)
NumericUpDown int, double, float, decimal, long, short, byte 数字输入框(带增减按钮)
ComboBox enum 枚举下拉选择
DateTimePicker DateTime / DateTime? 日期时间选择器
Slider [NumberSlider] 特性 滑块 + 数值标签
Color Color / Color? / SolidColorBrush 颜色预览块 + "..." 按钮(弹出 HC ColorPicker)
FilePath [FilePath] 特性 文本框 + 浏览按钮
DirectoryPath [DirectoryPath] 特性 文本框 + 浏览按钮
Collection [CollectionEditor] 特性或 IList 类型 文本框 + 编辑按钮(弹出对话框)
Dictionary IDictionary 类型(自动识别) "N 项" + 编辑按钮;值为集合时显示 "N 项 ..." 弹窗
DropDown TypeConverter 标准值 下拉列表(支持排他/可编辑模式)
MultiSelect [MultiSelect] 特性 摘要文本 + 弹出 CheckBox 列表
Button [Button] 特性 命令按钮(点击触发宿主方法/事件)
Expandable 复杂对象(非简单类型、非集合) 可展开子属性
Formula [FormulaEditor] 特性或 FormulaBound<T> 值编辑器 + 公式绑定区
宿主自定义 PropertyGrid.CustomEditors 注册的 Attribute 宿主提供的 DataTemplate

PropertyGrid 集合模式(内联显示)

当 PropertyGrid.SelectedObject 设为 IList 类型(如 List<string>、List<CustomType>)时,PropertyGrid 自动切换为集合编辑模式,内联显示集合编辑器,无需弹出对话框。

// 简单类型列表 — 自动显示 SimpleCollectionEditorControl
propertyGrid.SelectedObject = new List<string> { "A", "B", "C" };

// 复杂对象列表 — 自动显示 CollectionEditorControl(含内嵌 PropertyGrid)
propertyGrid.SelectedObject = new List<MyConfig> { new MyConfig() };

自动类型检测:

  • 简单类型(string、int、double、float、decimal、long、bool、DateTime、enum 等)→ SimpleCollectionEditorControl
  • 复杂对象类型 → CollectionEditorControl(左侧列表 + 右侧属性面板)
  • string 不会被识别为集合;IDictionary 会走独立的字典编辑器(见上节)

集合编辑器 UserControl 独立使用

CollectionEditorControl 和 SimpleCollectionEditorControl 现在可以作为 UserControl 独立嵌入任意容器,不再仅限于对话框弹出。

CollectionEditorControl(复杂对象列表)

xmlns:controls="clr-namespace:PropertyGridLib.Controls;assembly=PropertyGridLib"

<controls:CollectionEditorControl x:Name="editor" Items="{Binding MyList}" />
editor.Items = new List<MyConfig>
{
    new MyConfig { Name = "Item1", Value = 100 },
    new MyConfig { Name = "Item2", Value = 200 }
};

SimpleCollectionEditorControl(简单类型列表)

<controls:SimpleCollectionEditorControl x:Name="simpleEditor" Items="{Binding MyStringList}" />
simpleEditor.Items = new List<string> { "Apple", "Banana", "Cherry" };
// ElementType 会自动从集合泛型参数推断,也可手动指定
simpleEditor.ElementType = typeof(int);
simpleEditor.Items = new List<int> { 1, 2, 3 };

两个控件都直接操作传入的 IList 实例,每次增删改操作后立即同步回源集合。


FormulaBindingControl 独立使用

FormulaBindingControl 支持脱离 PropertyGrid 独立使用,通过设置 TreeItemsSource 或 FormulaTreeProvider 提供公式树数据。

方式一:FormulaTreeProvider(推荐)


<Window.Resources>
    <local:MyFormulaTreeProvider x:Key="myProvider"/>
</Window.Resources>

<controls:FormulaBindingControl
    FormulaTreeProvider="{StaticResource myProvider}"
    FormulaString="{Binding MyFormula, Mode=TwoWay}" />

方式二:TreeItemsSource(直接绑定树节点)

<controls:FormulaBindingControl
    TreeItemsSource="{Binding MyTreeNodes}"
    FormulaString="{Binding MyFormula, Mode=TwoWay}" />
public List<FormulaTreeNode> MyTreeNodes { get; } = new List<FormulaTreeNode>
{
    new FormulaTreeNode
    {
        Header = "传感器",
        Children =
        {
            new FormulaTreeNode { Header = "温度", Formula = "&{Sensors,Temperature,Value}" },
            new FormulaTreeNode { Header = "湿度", Formula = "&{Sensors,Humidity,Value}" }
        }
    }
};

数据源优先级: TreeItemsSource > FormulaTreeProvider > PropertyItem.DataContext(PropertyGrid 内嵌用法)


FormulaBound<T> — 公式绑定泛型类型

FormulaBound<T> 是一个包装类型,同时持有值和公式字符串。用于数据绑定场景,让属性既能存储实际值,又能记录绑定公式。

using PropertyGridLib.Controls;

public class MyConfig
{
    // string 类型公式绑定
    [FormulaEditor(typeof(MyProvider))]
    public FormulaBound<string> Name { get; set; } = new FormulaBound<string> { Value = "默认", Formula = "" };

    // int 类型也支持公式绑定
    [FormulaEditor(typeof(MyProvider))]
    public FormulaBound<int> Count { get; set; } = new FormulaBound<int> { Value = 42 };
}

FormulaBound<T> 属性:

属性 类型 说明
Value T 实际值
Formula string 绑定公式字符串(如 &{流程.任务.属性})

PropertyGrid 自动检测 FormulaBound<T> 类型,使用内部类型 T 选择编辑器,同时显示公式绑定区。即使不标记 [FormulaEditor],FormulaBound<T> 也会自动启用公式绑定输入框。


TypeConverter 下拉列表

当属性的 TypeConverter 提供标准值(GetStandardValuesSupported 返回 true),PropertyGrid 自动显示为下拉列表。

using System.ComponentModel;

// 自定义 TypeConverter 提供标准值
public class ComPortListConverter : TypeConverter
{
    public override bool GetStandardValuesSupported(ITypeDescriptorContext context) => true;

    public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) => true;  // true=排他(不可手动输入),false=可输入

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        return new StandardValuesCollection(new[] { "COM1", "COM2", "COM3", "COM4" });
    }
}

// 使用
[TypeConverter(typeof(ComPortListConverter))]
public string ComPort { get; set; } = "COM1";

多语言 / 本地化系统

PropertyGridLib 内置中英文双语支持,提供三个层面的本地化能力:

1. 类库内部字符串

通过 LocalizationManager 管理搜索框占位符、对话框标题、按钮文本等 47 个内置字符串。

using PropertyGridLib.Localization;

// 切换语言
LocalizationManager.CurrentLanguage = Language.EnUS;   // 英文
LocalizationManager.CurrentLanguage = Language.ZhCN;   // 中文(默认)

// 获取本地化字符串
var text = LocalizationManager.GetString("SearchPlaceholder");
var count = LocalizationManager.GetString("SelectedCount", 5);

在 XAML 中使用标记扩展绑定:

xmlns:loc="clr-namespace:PropertyGridLib.Localization;assembly=PropertyGridLib"

<TextBlock Text="{loc:Localized SearchPlaceholder}"/>

2. 属性名 / 描述 / 分类动态翻译

实现 IPropertyLocalization 接口,让数据对象提供动态的多语言翻译。语言切换时,PropertyGrid 自动刷新所有属性。

using PropertyGridLib;
using PropertyGridLib.Localization;

public class MyConfig : IPropertyLocalization
{
    [Category("外观")]
    [DisplayName("名称")]
    [Description("对象的显示名称")]
    public string Name { get; set; } = "Test";

    // 返回 null 时回退到 [DisplayName] 特性值
    public string GetDisplayName(string propertyName, Language language)
    {
        if (language == Language.ZhCN) return null;  // 中文用特性值
        return propertyName switch
        {
            "Name" => "Name",
            _ => null
        };
    }

    // 返回 null 时回退到 [Description] 特性值
    public string GetDescription(string propertyName, Language language)
    {
        if (language == Language.ZhCN) return null;
        return propertyName switch
        {
            "Name" => "Display name of the object",
            _ => null
        };
    }

    // 返回 null 时回退到 [Category] 特性值
    public string GetCategory(string propertyName, Language language)
    {
        if (language == Language.ZhCN) return null;
        return propertyName switch
        {
            "Name" => "Appearance",
            _ => null
        };
    }
}

3. 语言切换流程

用户调用 LocalizationManager.CurrentLanguage = Language.EnUS
    ↓
触发 LanguageChanged 事件
    ↓
PropertyGrid.OnLanguageChanged() 遍历所有属性
    ↓
PropertyItem.UpdateLocalization() 递归更新 DisplayName/Description/Category
    ↓
刷新描述栏 + 重新分组过滤

内置本地化 Key 列表(部分常用,共 47 个):

Key 中文 English
SearchPlaceholder 搜索属性... Search properties...
SelectBindingSource 选择绑定源 Select Binding Source
SelectItems 选择项 Select Items
SelectMultiple 选择多项 Select Multiple
ResetToDefault 重置为初始值 Reset to default
FormulaPlaceholder 公式绑定... Formula binding...
SelectFile 选择文件 Select File
SelectFolder 选择文件夹 Select Folder
AllFiles 所有文件 All Files
Files 文件 Files
ItemsCount [{0} 项] [{0} items]
Misc 杂项 Miscellaneous
NotSelected (未选择) (None)
SelectedCount 已选 {0} 项 {0} items selected
CollectionEditorTitle 集合编辑器 Collection Editor
CollectionItems 集合项 Collection Items
Properties 属性 Properties
Add 添加 Add
Copy 复制 Copy
Remove 删除 Remove
OK 确定 OK
Cancel 取消 Cancel
EditCollectionTitle 编辑集合 Edit Collection
InputPlaceholder 输入新值... Enter new value...
MoveUp 上移 Move Up
MoveDown 下移 Move Down
Tip 提示 Tip
Error 错误 Error
AddFailed 添加失败:{0} Add failed: {0}
CopyFailed 复制失败:{0} Copy failed: {0}
ConvertFailed 转换失败:{0} Convert failed: {0}
SelectItemToDelete 请先选择要删除的项 Please select an item to delete first
SelectItemToCopy 请先选择要复制的项 Please select an item to copy first
NoDefaultConstructor 类型 {0} 没有无参构造函数 Type {0} has no parameterless constructor
DictionaryEditorTitle 字典编辑器 Dictionary Editor
DictEntries 字典条目 Entries
DictKey 键 (Key) Key
DictValue 值 (Value) Value
DuplicateKey 键 "{0}" 已存在,请使用唯一的键 Key "{0}" already exists. Keys must be unique.

API 参考

PropertyGrid 类

命名空间: PropertyGridLib

依赖属性
属性 类型 默认值 说明
SelectedObject object null 要编辑的目标对象
SearchText string "" 搜索文本(自动过滤)
ShowDescription bool true 是否显示底部描述栏
ShowSearchBar bool true 是否显示搜索栏
SelectedPropertyItem IPropertyItem null 当前选中的属性项
GroupedCategories IEnumerable null 分组后的分类列表(供绑定)
IsLoading bool false 是否正在加载(切换对象时显示动画)
FormulaTreeProvider IFormulaTreeProvider null 全局公式树提供者(可选)
ShowTypeHint bool true 是否显示 FormulaTree 类型提示和公式绑定区类型提示
静态成员
成员 类型 说明
GlobalFontFamily FontFamily 全局字体(默认 Consolas),宿主可设置;PropertyGrid.FontFamily 变化时自动同步
GlobalFontSize double 全局字号(默认 12),宿主可设置;PropertyGrid.FontSize 变化时自动同步
CustomEditors Dictionary<Type, DataTemplate> 宿主自定义编辑器注册字典,AttributeType → DataTemplate
RegisterEditor<TAttribute>(template) static void 泛型注册方法,一行搞定宿主自定义编辑器
公共方法
方法 说明
RefreshProperties() 刷新属性列表(重新反射对象)
ResetSelectedToDefault() 重置当前选中属性到初始值
ResetAllToDefault() 重置所有属性到初始值
事件
事件 说明
ButtonClicked(实例) 本网格内 [Button] 属性被点击时触发(参数 PropertyButtonClickEventArgs)
GlobalButtonClicked(静态) 任意 PropertyGrid 实例(含集合/字典内嵌网格、弹窗网格)的 [Button] 被点击时触发;宿主订阅一次即可全局响应,窗口关闭时应取消订阅

PropertyGrid 在内部监听 LocalizationManager.LanguageChanged 事件,语言切换时自动刷新所有属性的本地化文本。

集合/字典模式行为: 当 SelectedObject 为 IList(排除 string)时内联显示集合编辑器;为 IDictionary 时内联显示字典编辑器;两者均自动隐藏正常属性列表。


ColorEditControl 类

命名空间: PropertyGridLib.Controls

颜色编辑器 UserControl,内嵌 HandyControl ColorPicker 弹窗。PropertyGrid 自动检测 Color / Color? / SolidColorBrush 类型,宿主无需手动使用此类。

成员 类型 说明
PART_ColorPreview Border 颜色预览块(16×16),颜色随 ColorPicker.SelectedColor 同步
PART_ColorHexText TextBlock HEX 文本,显示 #RRGGBB 或 #AARRGGBB
PART_EditButton Button 点击弹出 ColorPicker 弹窗
PART_ColorPicker hc:ColorPicker 弹窗内的 ColorPicker(StaysOpen=true,Confirmed/Canceled 事件处理)

CollectionEditorControl 类

命名空间: PropertyGridLib.Controls

复杂对象列表编辑器 UserControl。左侧列表 + 右侧内嵌 PropertyGrid + 增删复制排序按钮。

依赖属性 类型 默认值 说明
Items IList null 绑定的集合数据(直接操作源集合)

SimpleCollectionEditorControl 类

命名空间: PropertyGridLib.Controls

简单类型列表编辑器 UserControl。列表 + 输入框 + 增删排序按钮。

依赖属性 类型 默认值 说明
Items IList null 绑定的集合数据(直接操作源集合)
ElementType Type typeof(string) 元素类型(通常自动从集合泛型参数推断)

DictionaryEditorControl 类

命名空间: PropertyGridLib.Controls

字典编辑器 UserControl。左侧条目列表 + 右侧键/值编辑区(键、值各自可为文本框或内嵌 PropertyGrid)。直接操作传入的 IDictionary 实例,增删改即时写回。

依赖属性 类型 默认值 说明
Items IDictionary null 绑定的字典数据(直接操作源字典)

弹窗版为 PropertyGridLib.Dialogs.DictionaryEditorDialog(构造传入 IDictionary,ShowDialog() 返回 true 表示写回)。


FormulaBindingControl 独立使用属性

命名空间: PropertyGridLib.Controls

除 PropertyGrid 内嵌用法外,新增以下依赖属性支持独立使用:

依赖属性 类型 默认值 说明
TreeItemsSource IEnumerable null 直接设置公式树节点(FormulaTreeNode 集合),优先级最高
FormulaTreeProvider IFormulaTreeProvider null 设置公式树提供者,优先级次之
FormulaString string "" 公式字符串(支持 TwoWay 绑定)

PropertyItem 类

命名空间: PropertyGridLib.Controls

属性 类型 说明
Name string 属性名(代码中的名称)
DisplayName string 显示名称
Category string 分类
Description string 描述
Value object 属性值(可读写)
ValueString string 属性值字符串表示
PropertyType Type 属性类型
EffectivePropertyType Type 有效类型(FormulaBound<T> 时返回 T;Color 类型时省略 Alpha 显示)
IsReadOnly bool 是否只读
IsBrowsable bool 是否可浏览
IsExpandable bool 是否可展开子属性
IsExpanded bool 是否已展开
HasDefaultValue bool 是否有默认值
IsDefault bool 当前值是否等于初始值
IsModified bool 是否已修改
CustomEditor CustomEditorType 自定义编辑器类型(仅框架内置编辑器设置,宿主扩展为 null)
CustomEditorTemplate DataTemplate? 宿主注册的自定义编辑器模板,非 null 时 EditorTemplateSelector 优先使用
CustomEditorAttribute Attribute? 宿主自定义编辑器对应的 Attribute 实例,模板 code-behind 可读取参数
FileFilter string 文件过滤器
EnumValues Array 枚举值列表
StandardValues List<object> 下拉列表标准值
IsStandardValuesExclusive bool 下拉列表是否排他
SliderMinimum/Maximum/Step double 滑块参数
SliderShowNumberBox bool 滑块旁是否显示可编辑数字框(取代数值标签)
IsFormulaEnabled bool 是否启用公式绑定
FormulaString string 公式字符串
FormulaTreeProvider IFormulaTreeProvider 公式树提供者
MultiSelectProvider IMultiSelectProvider 多选列表提供者
ChildProperties List<PropertyItem> 子属性列表
ResetCommand ICommand 重置命令
BrowseFileCommand ICommand 浏览文件命令
BrowseDirectoryCommand ICommand 浏览目录命令
EditCollectionCommand ICommand 编辑集合命令
ButtonText string 按钮文本([Button];为空时回退到 DisplayName)
ButtonClickCommand ICommand 按钮点击命令([Button])
CustomEditorType 枚举
值 说明
None 无自定义编辑器(按类型自动选择)
FilePath 文件路径选择器
DirectoryPath 目录路径选择器
Collection 集合编辑器
Expandable 可展开对象
Slider 数值滑块
DropDown TypeConverter 下拉列表
Formula 公式绑定
MultiSelect 多选列表
Button 命令按钮([Button])
Dictionary 字典编辑器(IDictionary)
Color 颜色编辑器(Color / SolidColorBrush)

FormulaTreeNode 类

命名空间: PropertyGridLib.Controls

属性 类型 说明
Header string 节点显示文本
Formula string 选中后填入的公式字符串(仅叶子节点需要设置)
Children List<FormulaTreeNode> 子节点列表
FormulaType Type? 叶子节点的数值类型(如 typeof(int)),用于 TreeView 弹窗显示类型提示
TypeHint string 自动从 FormulaType 生成的类型提示(如 (int)、(string)),宿主也可直接覆盖

LocalizationManager 类

命名空间: PropertyGridLib.Localization

成员 类型 说明
CurrentLanguage Language 当前语言(默认 ZhCN)
LanguageChanged event EventHandler 语言切换事件
GetString(key) string 获取本地化字符串
GetString(key, args) string 获取本地化字符串(带格式化参数)

依赖项

依赖 版本 说明
.NET Framework 4.8+ 支持的目标框架之一
.NET 6.0/7.0/8.0-windows 支持的现代框架
HandyControl 3.5.1 官方 HandyControl UI 控件库
System.Text.Json 6.0.0+ 仅 .NET Framework 4.8 需要(.NET 6+ 内置)

版本兼容性:

  • System.Text.Json 向上兼容到 16.0+
  • 你的项目可以使用更高版本的 System.Text.Json,不会产生冲突
  • .NET 6/7/8 使用内置版本,无需额外引用

更新日志

v1.4.1(2026-09-28)

✨ 新增功能
  • 🈶 属性/事件显示名翻译表(宿主注册):反射场景(如 WPF 设计器把控件实例直接交给 SelectedObject)没有 [DisplayName] 可用,属性名只能显示 PropertyInfo.Name 原文。新增 LocalizationManager.RegisterPropertyName(name, displayName) / RegisterPropertyNames(map) / ClearPropertyNames() / TryGetPropertyName(name):宿主把「CLR 名 → 显示名」词条注册进来后,PropertyItem 与 EventItemFactory.FromEventInfo 在无 [DisplayName] 时自动查表(取词链:[DisplayName] 特性 → 宿主翻译表 → 英文原名);仅中文环境(zh*)命中,其余语言回退原名,语言切换随 UpdateLocalization() 自动生效。CodeForge.DesignerKit 据此内置了约 300 条 WPF 常用属性/事件中文词典(WpfDesignerNames,XamlFormController 构造时自动注册)

v1.4.0(2026-09-24)

✨ 新增功能
  • 📐 Small 紧凑布局(TitlePlacement 新属性):属性行标题排布可在「编辑器上方(Top,默认)」与「编辑器左侧(Left,Small 模式)」之间切换。Left 时标题与值编辑器平齐一行,对齐 HandyControl 表单左标题风格,行高压缩近一半;R 复位按钮保留在编辑器右侧(未修改时隐藏占位,编辑时布局不抖动),值被修改时标题右侧显示红点提示;公式绑定区与子属性列表因宽度原因仍另起一行
    • 实现方式:由 PropertyItem 隐式 DataTemplate 内的 DataTrigger 驱动(绑定祖先 PropertyGrid.TitlePlacement),顶层扁平列表、分类内列表、各级子属性列表一处切换全局生效,无需逐个 ItemsControl 设置 ItemTemplate
    • 用法:<pg:PropertyGrid TitlePlacement="Left"/> 或代码 grid.TitlePlacement = PropertyGridTitlePlacement.Left;
  • 🅰️ 标题与分类头字体粗细(TitleFontWeight / CategoryFontWeight):新增两个 FontWeight 类型依赖属性,分别控制属性行标题与分类头(Expander 标题)的粗细,默认值均为 Bold(即截图里「标题在左」或「标题在上」的 1.设备名称 / I.基本信息 都会加粗)。如果宿主希望更纤细,可设为 Normal / Light
    • 用法:<pg:PropertyGrid TitleFontWeight="Normal" CategoryFontWeight="Bold"/>
    • 说明:该属性通过 XAML 绑定直接生效,切换时无需调用 RefreshProperties;Top / Left 两种行模板均已绑定
  • ⚡ 属性列表 UI 虚拟化(性能重点):属性列表由「类别 Expander → 内层 ItemsControl」的两层嵌套压平为单层列表(类别头 + 其下的属性行同级排列),并开启 UI 虚拟化 —— 只生成视口内的十几行并复用行容器,而不是每次刷新都全量销毁重建上百行(80 属性 + 60 事件,每行含 NumericUpDown / ComboBox / ColorPicker 等重编辑器)。实测切换选中 → 属性页重建 206ms → 8ms,重复刷新的托管堆增长 44.5MB → 14.6MB。属性仍全部可见,不是靠默认折叠换来的,API 与用法不变
    • 关键坑(已在本次解决):ScrollViewer 必须放进 ItemsControl 的模板内、Content 用 ItemsPresenter,且 CanContentScroll="True"。外置 ScrollViewer 时它的 Content 是 ItemsControl 而非 IScrollInfo,找不到内部的 VirtualizingStackPanel,会退化成物理滚动、全量生成行 —— 第一版就是这么改的,压测证实毫无效果(209ms,与未开一致)
    • 公式绑定区与子属性列表由 Visibility 折叠改为按需创建(原先每行都实例化一个 FormulaBindingControl,80 行白白创建 80 个)
    • 新增 EnableVirtualization 开关(默认 true)。若宿主自定义行模板出现「滚动后行内值串行」,设为 false 即回到 1.3.4 的全量生成行为
  • 🔌 事件页能力:ShowEventsPage 开关 + EventPicker 事件筛选选择器 + EventItem 模型 + EventEditorControl 行内编辑器;默认关闭,不开时控件行为与旧版完全一致。开启后顶部出现「属性 | 事件」切换,事件行双击或点 ⚡ 触发 EventEditRequested,便于设计器宿主把事件绑定与代码编辑器(如 CodeForge)打通
🐛 缺陷修复
  • Value / ValueString 增加相等性检查 —— 消除「无用户操作却触发属性变更事件」:TwoWay 绑定在「绑定建立 / 虚拟化容器复用」时会把控件的当前值推回源。此前两个 setter 都没有相等性判断,即使推回的值与当前值完全相同(如 "False" vs False)也会写回宿主对象并触发 ValueChanged → PropertyValueChanged。压测实测:30 秒内误触发上百次,涉及 bool 属性的开关编辑器与 Visibility / HorizontalAlignment / FlowDirection 等枚举属性;设计器宿主会据此把同一个值反复写回 XAML(污染撤销栈、无谓开销)。修复后误触发降为 0 次,同时保留 472 次/轮的绑定推回调用被正确短路
    • 澄清一个容易误判的点:开关(ToggleSwitch)的切换动画不会触发任何写入。动画是纯视觉层(滑块位移),不改变 IsChecked 逻辑值。真正的写入来源是绑定推回,两者不可混淆
  • SelectedObject 置 null / 传入已销毁对象时崩溃:防抖路径会拿陈旧的选中项去访问已释放的实例,抛 NullReferenceException
  • 加载指示动画:LoadingCircle 改为静态文本。动画时钟在「快速显隐」的元素上持续 tick,是宿主侧 CLR 闪退的诱因之一,静态化后无时钟、无竞态
🔄 向后兼容性
  • ✅ 公共 API 无破坏性变更;EnableVirtualization / ShowEventsPage / TitlePlacement 均为新增开关,默认值(true / false / Top)下渲染结果与旧版完全一致
  • ⚠️ 虚拟化开启后行容器会被回收复用(Recycling)。使用自定义行模板且模板内含非绑定状态(如在 Loaded 里缓存对象引用)的宿主,请验证滚动后的取值;有异常时把 EnableVirtualization 设为 false 即可回退

v1.3.0(2026-09-15)

✨ 新增功能
  • 🧩 PropertyGridPro 平铺参数面板(新控件):新增 PropertyGridLib.PropertyGridPro,纵向平铺布局 + 卡片式属性行,面向「参数面板 / 属性面板」场景。提供 Header / HeaderDescription / SourceText 头部区、ShowHeader / ShowSearchBar / ShowDescription 开关、EditorWidth 统一编辑器宽度、RowTemplate 整体替换行模板;属性搜索附匹配计数与空结果提示;提供 RefreshProperties() / ResetAllToDefault() / ResetSelectedToDefault() / SetSubPropertiesExpanded(bool) 方法。与 PropertyGrid 共用同一套特性体系、编辑器模板、本地化与主题资源,模型代码无需改动即可互换
  • 🃏 卡片式属性行布局:属性行改为卡片承载(圆角 7、行间距、分类头独立成卡片),卡片底色取主题次级区域画刷(SecondaryRegionBrush),深浅主题下层次一致
  • 🌓 主题色跟随(去除硬编码):面板模板中硬编码的深色值全部替换为 SkinDark / ThemeHelper 等主题资源键,卡片背景、边框、标题与描述文字、分类头、嵌套引导线均随主题切换;资源键缺失时自动回退到 HandyControl 默认画刷
  • 🪜 无限嵌套样式统一:复杂对象子属性以卡片逐层铺开,按层级增加缩进与引导线(层级不限);统一各层级的间距、圆角与引导线样式,深层嵌套不再视觉走形
  • 🔗 公式绑定接入 Pro 面板:标注 [FormulaEditor] 的属性在 PropertyGridPro 中同样渲染公式绑定区(值编辑器 + 链接图标 + 公式文本框 + 树选择器 Popup),并支持全局 FormulaTreeProvider 与类型提示
  • 📐 复位按钮常驻占位:复位按钮可见性由 Collapsed 改为 Hidden,未悬停时仍保留占位,消除「鼠标移入/移出导致同行编辑器左右跳动」的问题(实测位移 0px);基础控件与 Pro 面板一并生效
  • 🔀 ToggleSwitchAttribute — 布尔开关特性:新增 PropertyGridLib.Attributes.ToggleSwitchAttribute,bool 属性渲染为滑块式开关(圆角轨道 + 圆形滑块,基于 HandyControl ToggleButtonSwitch 样式)+ 可选的开/关状态文字;支持 [ToggleSwitch](默认「开 / 关」)、[ToggleSwitch("已启用","已禁用")]、OnText / OffText 命名参数(传 null 隐藏文字);仅对 bool 生效,标注在其它类型上被忽略;基类与 Pro 面板通过同一 EditorSelector 复用同一模板
  • 📚 技能文档:新增多页使用文档 skill/SKILL.md 及 8 个分页(快速开始 / 特性清单 / 编辑器类型 / 主题与多语言 / 公式绑定 / PropertyGridPro / 示例模型 / FAQ),配套截图统一存放于演示仓库的 PropertyGridDemo/skill/images/
🐛 缺陷修复
  • 复位按钮导致布局抖动:隐藏态使用 Collapsed 会挤动同行值编辑器,现改用 Hidden(新增 BoolToHiddenVisibilityConverter)
  • 浅色主题下 Pro 面板发暗:面板模板中的硬编码深色画刷改为主题资源键,浅色/深色双向切换均正常
  • Pro 面板嵌套样式不一致:统一各级子属性的间距、圆角与引导线
📦 新增公共类型
  • PropertyGridLib.PropertyGridPro — 平铺参数面板控件
  • PropertyGridLib.Attributes.ToggleSwitchAttribute — 布尔开关特性(OnText / OffText)
  • PropertyGridLib.Converters.BoolToHiddenVisibilityConverter — 隐藏(保留占位)可见性转换器
  • PropertyItem.ToggleOnText / ToggleOffText / ToggleStateText / ToggleStateTextVisibility — 开关状态文字相关成员
  • 编辑器模板属性:EditorTemplateSelector.BooleanTemplate(默认 bool 开关)、EditorTemplateSelector.ToggleSwitchTemplate(带状态文字的开关)
🔄 其它变更
  • 演示程序移除旧模型与「实时值」区块,Pro 演示窗口改用与基类一致的 SampleObject
  • 版本号字段(Version / AssemblyVersion / FileVersion / InformationalVersion)同步为 1.3.0,Description 与 PackageTags 补充 PropertyGridPro / ToggleSwitch
🔄 向后兼容性
  • ✅ 现有公共 API 与行为全部保留,1.3.0 均为新增或视觉优化
  • ⚠️ 未标注 [ToggleSwitch] 的 bool 属性外观为滑块开关(无状态文字),如宿主此前依赖自定义 bool 模板请确认未被覆盖
  • ⚠️ 复位按钮的隐藏态由 Collapsed 改为 Hidden,若宿主自行覆写了行模板中的可见性转换器需同步调整

v1.2.0(2026-09-07)

✨ 新增功能
  • 🔌 宿主自定义编辑器扩展机制:PropertyGrid.CustomEditors 静态字典 + RegisterEditor<TAttr>(template) 泛型方法;宿主只需定义 Attribute + DataTemplate + 一行注册,PropertyGrid 即可渲染自定义编辑器;框架对此 Attribute 一无所知。新增 PropertyItem.CustomEditorTemplate / CustomEditorAttribute 属性,EditorTemplateSelector 优先返回宿主模板,宿主甚至可覆盖框架内置编辑器
  • 🎨 颜色编辑器:自动识别 Color / Color? / SolidColorBrush 类型(内置 IsColorType 检测在 CanExpand 之前拦截,防止 Color struct 被误判为可展开对象);显示为颜色预览块(16×16 + #RRGGBB HEX 文本)+ "..." 按钮(紧凑居左,与 FilePath/Dictionary 编辑器风格统一);点击弹出 HandyControl ColorPicker(StaysOpen=true + 手动 Window.PreviewMouseDown + IsInVisualTree 外部点击检测,支持拖动 Slider 不丢失焦点;"确定"才写入值并关闭,"取消"不改值);HEX 显示:不透明时省略 Alpha 前缀
  • 📁 字典嵌套字典/列表自动弹窗:字典值为集合(IDictionary / IList)时不再内联显示内嵌 PropertyGrid,改为显示 "N 项 + ..." 按钮,点击弹出二级 DictionaryEditorDialog / SimpleCollectionEditorDialog(模态覆盖父级,UI 不会无限拉长);字典值为复杂对象时仍内嵌 PropertyGrid 就地编辑(三种模式互斥)
  • 🌳 FormulaTree 类型提示:FormulaTreeNode 新增 FormulaType / TypeHint 属性,TreeView 弹窗叶子节点右侧显示淡蓝色斜体类型名(如 (int)、(DateTime));PropertyGrid 新增 ShowTypeHint 依赖属性(默认 true)控制是否显示;公式绑定区同样显示类型提示
  • 🔤 全局字体动态同步:PropertyGrid.FontSize / FontFamily 通过 DependencyPropertyDescriptor 实时监听,变化时自动更新 GlobalFontSize / GlobalFontFamily;所有 Dialog(字典、集合、文件夹、颜色)打开时读取最新全局值,FontSize/FontFamily 跟随宿主变化
  • 📁 FolderBrowserDialog 主题修复:所有文字控件显式指定 Foreground="{DynamicResource PrimaryTextBrush}" + Background="{DynamicResource RegionBrush}",深色主题下不再出现白字黑底问题;TreeView/TreeViewItem 选中/悬停触发器适配深浅色主题
  • 🎨 ColorPicker 弹窗图标适配:FolderBrowserDialog 文件夹图标从 emoji 改为 Material Design 风格 Path 图标(Fill="{DynamicResource PrimaryBrush}"),选中时 Foreground 自动变白
🐛 缺陷修复
  • HandyControl 主题切换失效:原 SetAppSkin 用 is HandyControl.Themes.Theme 匹配不到 App.xaml 里通过 URI 加载的 Theme.xaml(那是 ResourceDictionary,不是 Theme 实例),导致替换 MergedDictionaries 时 idx=-1 每次 Add 新 Theme 到末尾,旧的还留着,第二次切换资源冲突——现改为直接改 Theme.Skin 属性(HC 官方推荐方式),白→黑→白双向切换均正常
  • 颜色编辑器选完值不生效:原 XAML 双向绑定 ValueString 用 ColorToBrushConverter,但 WPF 调 ConvertBack 时 targetType=object(因为 PropertyItem.Value 是 object),类型检查全挂;现改 code-behind,在 Confirmed 事件里根据 EffectivePropertyType 做正确类型转换(Color/SolidColorBrush/Color?)
  • ColorPicker 弹窗 Slider 拖动时消失:StaysOpen=false 时 HC ColorPicker 内部 Slider 的 MouseCapture 状态变化导致 Popup 误判"鼠标在外部"——现改为 StaysOpen=true + 手动 Window.PreviewMouseDown + IsInVisualTree 检测外部点击
📦 新增公共类型
  • PropertyGridLib.Controls.ColorEditControl — 颜色编辑器 UserControl(弹出 HC ColorPicker)
  • PropertyGridLib.Controls.ColorToBrushConverter — Color ↔ SolidColorBrush 双向转换器
  • PropertyGridLib.Controls.FormulaTreeNode.FormulaType / TypeHint — FormulaTree 类型提示
🔄 框架侧删除
  • ❌ PropertyGridLib.Attributes.UnitEditorAttribute(框架内置的单位编辑器特性)
  • ❌ CustomEditorType.Unit 枚举值
  • ❌ PropertyItem.UnitOptions / SelectedUnit / UnitDisplayValue 属性
  • ❌ Generic.xaml 里的 UnitTemplate
  • 原因:宿主扩展机制 RegisterEditor<TAttr>(template) 可完全替代,框架内置编辑器与宿主扩展功能重复
🔄 向后兼容性
  • ✅ 现有公共 API 全部保留(新增成员不影响旧代码)
  • ⚠️ PropertyGrid.FontSize / FontFamily 现在会自动同步到全局值(之前只在 OnApplyTemplate 同步一次),若宿主依赖"全局值独立于实例值"的行为需注意
  • ⚠️ 字典编辑器嵌套值的渲染模式变化:集合类型值从"内嵌 PropertyGrid"改为"弹窗",UI 更紧凑但编辑交互从就地改为弹窗;复杂对象值仍保持内嵌模式

v1.1.2(2026-09-04)

✨ 新增功能
  • 命令按钮编辑器 [Button]:属性标记 [Button("文本", nameof(方法))] 后渲染为按钮;点击时①反射调用宿主对象上的 Action 方法(支持无参或单参),②触发 PropertyItem.ButtonClicked 与 PropertyGrid.ButtonClicked 事件;Text 为空时回退到 DisplayName(随多语言切换)。按钮默认始终可点,仅显式 [ReadOnly(true)] 时禁用
  • 全局按钮事件 PropertyGrid.GlobalButtonClicked(静态):任何 PropertyGrid 实例(包括集合/字典编辑器内嵌的网格、弹窗内的网格)触发 [Button] 都会引发,宿主订阅一次即可跨窗口/跨层级统一响应
  • 字典编辑器(IDictionary):自动识别 IDictionary / IDictionary<,> 属性(无需特性,[CollectionEditor] 标在字典上也会路由到字典编辑器);提供弹窗 DictionaryEditorDialog 与内联 DictionaryEditorControl(当 SelectedObject 直接是字典时自动内联);键、值各自支持简单类型(文本框 + 类型转换)或复杂对象(内嵌 PropertyGrid,可继续向下嵌套集合/字典);键值均为对象时左右各占 50%;支持增/删/改、重复键校验、实时写回原字典
  • 多框架:新增 .NET Core 3.0 / 3.1 目标(实际目标:net48 / netcoreapp3.0 / netcoreapp3.1 / net6.0-windows / net7.0-windows / net8.0-windows)
🐛 缺陷修复
  • 字典 "..." 按钮无响应:此前字典被 ICollection 识别为集合,但 EditCollection 仅处理 IList,导致点击编辑按钮无反应——现按 IDictionary 路由到字典编辑器
  • 嵌套网格中按钮失效:集合/字典编辑器内嵌 PropertyGrid 的按钮点击无法上抵宿主、且 Action 修改不刷新——现通过全局事件 + 点击后网格自刷新解决
  • 字典编辑器描述栏白条:内嵌网格 ShowDescription 不一致导致底部描述栏折叠后露出 80px 白色空行——现键/值网格统一显示描述栏
📦 新增公共类型
  • PropertyGridLib.Attributes.ButtonAttribute
  • PropertyGridLib.Controls.PropertyButtonClickEventArgs
  • PropertyGridLib.Controls.DictionaryEditorControl(内联字典编辑器 UserControl,Items 为 IDictionary)
  • PropertyGridLib.Dialogs.DictionaryEditorDialog
  • CustomEditorType 新增枚举值:Button、Dictionary
🔄 向后兼容性
  • ✅ 现有公共 API 与行为全部保留,仅新增成员
  • ⚠️ IPropertyItem 接口新增了 ButtonText / ButtonClickCommand / ButtonClicked(库内仅 PropertyItem 实现该接口;若宿主自行实现过该接口,需补充这几个成员)
  • ⚠️ .NET Core 3.0/3.1 目标仍为 Windows 专用(WPF 不支持 Linux/macOS);因其 TFM 无 -windows 后缀,跨平台项目误装后运行时才会报错,请注意

v1.1.1(2026-09-01)

✨ 新增功能
  • PropertyGrid 集合模式(内联显示):当 SelectedObject 为 IList 类型时,自动切换为集合编辑模式,内联显示编辑器(无需弹出对话框)
  • 集合编辑器 UserControl 化:CollectionEditorControl(复杂对象列表)和 SimpleCollectionEditorControl(简单类型列表)可作为独立 UserControl 嵌入任意容器
  • FormulaBindingControl 独立使用:新增 TreeItemsSource / FormulaTreeProvider 依赖属性,支持脱离 PropertyGrid 直接设置公式树数据源
🔧 技术改进
  • PropertyGrid 模板新增 PART_CollectionEditorHost / PART_NormalHost 双区域切换机制
  • 集合元素类型自动检测:简单类型(primitives、enum、string、decimal、DateTime、TimeSpan、Guid)→ SimpleCollectionEditor,复杂类型 → CollectionEditor
  • FormulaBindingControl.LoadTreeItems() 三级优先级:TreeItemsSource → FormulaTreeProvider → PropertyItem DataContext
  • 集合编辑器控件直接操作源 IList 实例,每次操作后立即同步
📦 新增公共类型
  • PropertyGridLib.Controls.CollectionEditorControl — 复杂对象列表编辑器 UserControl
  • PropertyGridLib.Controls.SimpleCollectionEditorControl — 简单类型列表编辑器 UserControl
🔄 向后兼容性
  • ✅ 所有现有公共 API 保持不变
  • ✅ PropertyGrid 正常对象绑定行为不受影响
  • ✅ FormulaBindingControl 在 PropertyGrid 内嵌用法不受影响

许可证

MIT License

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net6.0-windows7.0 is compatible.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net7.0-windows7.0 is compatible.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net8.0-windows7.0 is compatible.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 is compatible.  netcoreapp3.1 is compatible. 
.NET Framework net48 is compatible.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.5.0 92 10/2/2026
1.4.0 102 9/23/2026
1.3.0 111 9/16/2026
1.2.0 114 9/7/2026
1.1.2 109 9/4/2026
1.1.0 118 8/28/2026
1.0.9.1 118 8/28/2026 1.0.9.1 is deprecated because it has critical bugs.
1.0.9 127 8/28/2026 1.0.9 is deprecated because it has critical bugs.
1.0.8-official-hc.1 99 8/28/2026 1.0.8-official-hc.1 is deprecated because it has critical bugs.
1.0.7 112 8/27/2026
1.0.6 134 8/15/2026
1.0.5 122 8/5/2026
1.0.3 129 7/29/2026