C# winform 如何PropertyGrid的在控件中不允许修改部分字段

在 C# WinForms 中,PropertyGrid 控件用于显示和编辑对象的属性。如果你希望某些属性在 PropertyGrid 中不可编辑,可以通过几种方法来实现这一点。以下是几种常见的方法:

方法 1: 使用 Browsable 和 ReadOnly 属性

你可以在类的属性上使用 [Browsable(false)][ReadOnly(true)] 特性来控制这些属性在 PropertyGrid 中的可见性和可编辑性。

示例代码
 

Csharp

深色版本

using System;
using System.ComponentModel;
using System.Windows.Forms;

public class MyObject
{
    [Category("General")]
    [DisplayName("Name")]
    [Description("The name of the object.")]
    public string Name { get; set; }

    [Category("General")]
    [DisplayName("Created Date")]
    [Description("The date when the object was created.")]
    [ReadOnly(true)] // 使该属性只读
    public DateTime CreatedDate { get; set; }

    [Browsable(false)] // 使该属性在 PropertyGrid 中不可见
    public string SecretField { get; set; }
}

public class MainForm : Form
{
    private PropertyGrid propertyGrid;
    private MyObject myObject;

    public MainForm()
    {
        this.myObject = new MyObject
        {
            Name = "Example Object",
            CreatedDate = DateTime.Now,
            SecretField = "This is a secret"
        };

        this.propertyGrid = new PropertyGrid
        {
            Dock = DockStyle.Fill,
            SelectedObject = this.myObject
        };

        this.Controls.Add(this.propertyGrid);
    }

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());
    }
}

方法 2: 自定义 TypeConverter

你可以通过自定义 TypeConverter 来控制属性的编辑行为。这允许你在属性编辑器中提供更复杂的逻辑。

示例代码
 

Csharp

深色版本

using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Forms;

public class MyObject
{
    [Category("General")]
    [DisplayName("Name")]
    [Description("The name of the object.")]
    public string Name { get; set; }

    [Category("General")]
    [DisplayName("Created Date")]
    [Description("The date when the object was created.")]
    [TypeConverter(typeof(CustomDateTimeConverter))]
    public DateTime CreatedDate { get; set; }
}

public class CustomDateTimeConverter : TypeConverter
{
    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    {
        return false;
    }

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        if (sourceType == typeof(string))
        {
            return true;
        }
        return base.CanConvertFrom(context, sourceType);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if (value is string stringValue)
        {
            return DateTime.Parse(stringValue);
        }
        return base.ConvertFrom(context, culture, value);
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        if (destinationType == typeof(string))
        {
            return true;
        }
        return base.CanConvertTo(context, destinationType);
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(string) && value is DateTime dateTime)
        {
            return dateTime.ToString();
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }

    public override bool GetPropertiesSupported(ITypeDescriptorContext context)
    {
        return false;
    }

    public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
    {
        return TypeDescriptor.GetProperties(typeof(DateTime), attributes).Sort(new string[] { "Year", "Month", "Day" });
    }
}

public class MainForm : Form
{
    private PropertyGrid propertyGrid;
    private MyObject myObject;

    public MainForm()
    {
        this.myObject = new MyObject
        {
            Name = "Example Object",
            CreatedDate = DateTime.Now
        };

        this.propertyGrid = new PropertyGrid
        {
            Dock = DockStyle.Fill,
            SelectedObject = this.myObject
        };

        this.Controls.Add(this.propertyGrid);
    }

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());
    }
}

方法 3: 使用 PropertyDescriptor 和 TypeDescriptionProvider

你可以通过自定义 TypeDescriptionProviderPropertyDescriptor 来更细粒度地控制属性的行为。

示例代码
 

Csharp

深色版本

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

public class MyObject
{
    [Category("General")]
    [DisplayName("Name")]
    [Description("The name of the object.")]
    public string Name { get; set; }

    [Category("General")]
    [DisplayName("Created Date")]
    [Description("The date when the object was created.")]
    public DateTime CreatedDate { get; set; }
}

public class ReadOnlyTypeDescriptionProvider : TypeDescriptionProvider
{
    private TypeDescriptionProvider _baseProvider;

    public ReadOnlyTypeDescriptionProvider(Type type) : base(TypeDescriptor.GetProvider(type))
    {
        _baseProvider = TypeDescriptor.GetProvider(type);
    }

    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
    {
        return new ReadOnlyCustomTypeDescriptor(_baseProvider.GetTypeDescriptor(objectType, instance));
    }
}

public class ReadOnlyCustomTypeDescriptor : CustomTypeDescriptor
{
    public ReadOnlyCustomTypeDescriptor(ICustomTypeDescriptor parent) : base(parent) { }

    public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        PropertyDescriptorCollection properties = base.GetProperties(attributes);
        List<PropertyDescriptor> readOnlyProperties = new List<PropertyDescriptor>();

        foreach (PropertyDescriptor prop in properties)
        {
            if (prop.Name == "CreatedDate")
            {
                readOnlyProperties.Add(new ReadOnlyPropertyDescriptor(prop));
            }
            else
            {
                readOnlyProperties.Add(prop);
            }
        }

        return new PropertyDescriptorCollection(readOnlyProperties.ToArray());
    }
}

public class ReadOnlyPropertyDescriptor : PropertyDescriptor
{
    private readonly PropertyDescriptor _originalDescriptor;

    public ReadOnlyPropertyDescriptor(PropertyDescriptor originalDescriptor) : base(originalDescriptor)
    {
        _originalDescriptor = originalDescriptor;
    }

    public override bool CanResetValue(object component)
    {
        return false;
    }

    public override Type ComponentType
    {
        get { return _originalDescriptor.ComponentType; }
    }

    public override object GetValue(object component)
    {
        return _originalDescriptor.GetValue(component);
    }

    public override bool IsReadOnly
    {
        get { return true; }
    }

    public override Type PropertyType
    {
        get { return _originalDescriptor.PropertyType; }
    }

    public override void ResetValue(object component)
    {
        // Do nothing
    }

    public override void SetValue(object component, object value)
    {
        // Do nothing
    }

    public override bool ShouldSerializeValue(object component)
    {
        return false;
    }
}

public class MainForm : Form
{
    private PropertyGrid propertyGrid;
    private MyObject myObject;

    public MainForm()
    {
        this.myObject = new MyObject
        {
            Name = "Example Object",
            CreatedDate = DateTime.Now
        };

        TypeDescriptor.AddProvider(new ReadOnlyTypeDescriptionProvider(typeof(MyObject)), typeof(MyObject));

        this.propertyGrid = new PropertyGrid
        {
            Dock = DockStyle.Fill,
            SelectedObject = this.myObject
        };

        this.Controls.Add(this.propertyGrid);
    }

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new MainForm());
    }
}

总结

  • 使用 Browsable 和 ReadOnly 属性:简单且直接,适用于大多数情况。
  • 自定义 TypeConverter:提供更复杂的转换逻辑。
  • 使用 PropertyDescriptor 和 TypeDescriptionProvider:更细粒度地控制属性的行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值