如何为基于ITypeEditor的WPF自定义控件添加参数适配Xceed PropertyGrid?
通用Xceed PropertyGrid浏览编辑器实现方案(文件/文件夹二合一)
刚好我之前做过类似的需求,给你分享一个简洁的实现方式,完美符合DRY原则,不用重复写多个编辑器控件!核心思路是通过自定义特性传递配置参数,然后在编辑器中读取这些参数来切换行为。
步骤1:定义自定义特性(传递模式参数)
先创建一个特性类,用来标记属性的浏览模式(文件/文件夹),还可以扩展文件过滤规则等额外配置:
// 浏览模式枚举 public enum BrowseMode { File, Folder } // 自定义特性,用于标记属性的浏览配置 [AttributeUsage(AttributeTargets.Property)] public class BrowseSettingsAttribute : Attribute { // 核心:浏览模式(文件/文件夹) public BrowseMode Mode { get; set; } = BrowseMode.File; // 可选:文件对话框的过滤规则 public string FileFilter { get; set; } = "All Files (*.*)|*.*"; // 可选:文件夹对话框的描述文本 public string FolderDescription { get; set; } = "Select a folder"; }
步骤2:改造你的通用编辑器控件
修改PropertyGridFilePicker,在ResolveEditor方法中读取当前绑定属性的自定义特性,然后根据配置切换对话框类型:
public partial class PropertyGridFilePicker : ITypeEditor { private BrowseMode _currentMode; private string _fileFilter; private string _folderDesc; public PropertyGridFilePicker() { InitializeComponent(); } public string Value { get { return (string)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } } public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(PropertyGridFilePicker), new PropertyMetadata(null)); public FrameworkElement ResolveEditor(PropertyItem propertyItem) { // 读取当前属性的BrowseSettings特性 var settings = propertyItem.PropertyDescriptor.Attributes .OfType<BrowseSettingsAttribute>() .FirstOrDefault(); // 初始化配置,默认用文件模式 _currentMode = settings?.Mode ?? BrowseMode.File; _fileFilter = settings?.FileFilter ?? "All Files (*.*)|*.*"; _folderDesc = settings?.FolderDescription ?? "Select a folder"; // 绑定属性值(原逻辑保留) Binding binding = new Binding("Value") { Source = propertyItem, Mode = propertyItem.IsReadOnly ? BindingMode.OneWay : BindingMode.TwoWay }; BindingOperations.SetBinding(this, ValueProperty, binding); return this; } private void PickFileButton_Click(object sender, RoutedEventArgs e) { if (_currentMode == BrowseMode.File) { var fileDialog = new OpenFileDialog { Filter = _fileFilter, CheckFileExists = true }; if (fileDialog.ShowDialog() == true) { Value = fileDialog.FileName; } } else { var folderDialog = new FolderBrowserDialog { Description = _folderDesc, ShowNewFolderButton = true }; if (folderDialog.ShowDialog() == true) { Value = folderDialog.SelectedPath; } } } }
步骤3:在业务属性上使用通用编辑器
现在只需要给不同的属性标记对应的特性,就能实现不同的浏览行为,完全复用同一个编辑器:
// 文件夹选择模式 [Editor(typeof(MyControls.PropertyGridFilePicker), typeof(MyControls.PropertyGridFilePicker))] [BrowseSettings(Mode = BrowseMode.Folder, FolderDescription = "Select project root folder")] public string ProjectFolder { get; set; } = ""; // 文件选择模式(带自定义过滤) [Editor(typeof(MyControls.PropertyGridFilePicker), typeof(MyControls.PropertyGridFilePicker))] [BrowseSettings(Mode = BrowseMode.File, FileFilter = "JSON Files (*.json)|*.json|All Files (*.*)|*.*")] public string ConfigFilePath { get; set; } = ""; // 默认文件模式 [Editor(typeof(MyControls.PropertyGridFilePicker), typeof(MyControls.PropertyGridFilePicker))] public string LogFilePath { get; set; } = "";
额外说明
如果不想用自定义特性,也可以直接通过propertyItem.PropertyDescriptor.Name获取属性名称,然后在编辑器中做判断(比如判断属性名是否包含"Folder"就用文件夹模式),但这种方式耦合性高,不如自定义特性灵活可控,更推荐前者。
内容的提问来源于stack exchange,提问作者wotnot
相关产品推荐
相关产品推荐

