【问题标题】:PropertyGrid with possibly-null List具有可能为空列表的 PropertyGrid
【发布时间】:2012-10-23 23:04:28
【问题描述】:

我正在使用 PropertyGrid 类来编辑我的应用程序中的对象。这些是相关的类(或者更确切地说,是它们的简化):

public class Inner
{
    public int A { get; set; }
    public string B { get; set; }
}

public class Outer
{
    public List<Inner> InnerData { get; set; }
    public int Id { get; set; }
}

我将设置一个 Outer 类型的对象作为我的属性网格的 SelectedObject 字段。当 Outer 对象的 InnerData 属性设置为 null 时,就会出现问题。 Null 被视为此属性的可接受值,因为 InnerData 属性表示“可选”数据,并且不指定它与指定空列表不同。理想情况下,我希望用户能够通过指定新列表的组件、修改现有的非 null InnerData 值并将现有的 InnerData 值替换为 null 来将 null InnerData 属性替换为实际值。

有人知道如何实现吗?

【问题讨论】:

    标签: c# .net propertygrid


    【解决方案1】:

    看看创建 UITypeEditor,我认为如果您使用编辑器,您将对列表有更多的控制权,并且能够判断当前值是否为空,如果是,您可以让编辑器显示一个空白网格或者可以添加或删除列表项的东西,您还可以添加一个复选框来告诉编辑器再次返回 null 并在属性上设置 null,编辑器基本上是一个 WinForm,因此您几乎可以在其中执行任何操作。

    internal class GenericTypeEditor : UITypeEditor
    {
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            IWindowsFormsEditorService winFormEditorSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
    
            using (MyForm editorForm = new MyForm())
            {
                if (winFormEditorSvc.ShowDialog(editorForm) == System.Windows.Forms.DialogResult.OK)
                    value = editorForm.ReturnObject;
            }
    
            return value; //this can be null if you wish
        }
    
        public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
        {
            return UITypeEditorEditStyle.Modal;
        }
    }
    

    然后在你的属性上设置属性

    [EditorAttribute(typeof(GenericTypeEditor), typeof(System.Drawing.Design.UITypeEditor))]
    public List<Inner> InnerData { get; set; }
    

    这篇文章曾经帮助过我,也许对你有帮助: http://msdn.microsoft.com/en-us/library/ms171840(v=vs.100).aspx

    【讨论】:

    • EditorAttribute 部分不太对,应该是EditorAttribute(typeof(GenericTypeEditor)), typeof(System.Drawing.Design.UITypeEditor))],它适用于我示例的public List&lt;Inner&gt; Inner 属性。
    • @scott 啊抱歉,我只是复制粘贴在那里并从 Wanabrutbeer 而不是您的复制了属性.. 我仍然不习惯在答案发布页面中输入代码,所以也许我没有向上滚动: P关于属性的好点,编辑了我的答案...
    【解决方案2】:

    属性网格尝试将新的内部项添加到 InnerData 对象,但由于您尚未对其进行初始化,因此属性网格没有保存添加项的位置。在 Outter 中需要一个构造函数,它将 InnerData 初始化为一个新的 List。您不必将任何项目放入其中,用户可以在运行时执行此操作,也可以将它们清空,但需要初始化 InnerData 列表对象。

    如果您只想将 Inner 作为属性,请将 System.ComponentModel 添加到您的 usings 中并尝试此操作

    [TypeConverter(typeof(ExpandableTypeConverter))]
    public Inner DefaultInner { get; set; }
    

    这将使您的对象在属性网格中可展开,以便您可以设置其嵌套属性

    尝试处理 PropertyGrid.SelectedGridItemChanged 事件:

    private void propertyGrid1_SelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e)
    {
        if ((e.NewSelection.Label == "InnerData") && (_outter.InnerData == null)) _outter.InnerData = new List<Inner>();
    }
    

    然后,只要选择内部项目,如果收集为null,则其初始化为新列表。

    【讨论】:

    • 添加将 InnerData 初始化为空列表的构造函数不是可接受的解决方案,因为在我的数据模型中 InnerData == null 和 InnerData != null && InnerData.Count == 0 表示不同的东西。我需要能够代表这两种可能性。
    • 那么你将无法使用属性网格来操作 InnerData
    • 看起来你可以处理 SelectedGridItemChanged 事件,编辑显示
    猜你喜欢
    • 1970-01-01
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多