C# 如何根据属性网格中另一个属性的值公开一个属性?

发布于 2024-10-12 05:06:35 字数 114 浏览 2 评论 0原文

我的课程具有多个属性。有时,可以在属性网格中编辑属性 (A)。但有时属性 A 可能无法编辑。这取决于另一个属性的值。

我该怎么做?

编辑: 抱歉,我忘记提及我希望在设计时做到这一点。

I have class with multiple properties. Sometimes a property (A) may be edited in a propertygrid. But sometimes property A may not be edited. This depends on a value of another property.

How can I do this?

EDIT:
I am sorry, I forget to mention that I want this in design-time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我不会写诗 2024-10-19 05:06:36

我过去通过 此堆栈解决方案。它使用自定义属性,并有条件地忽略在设计时与运行时进行更改的尝试,但我确信可以通过应用您自己的“标准”来更改 SETter 中的更改以允许更改...

I've offered a similar solution in the past via this stack solution. It makes use of a custom property, and conditionally ignores an attempt to change at design-time vs run-time, but I'm sure could be altered in the SETter by applying your own "criteria" to allow it being changed...

☆獨立☆ 2024-10-19 05:06:35

运行时属性模型是一个高级主题。对于PropertyGrid,最简单的方法是编写一个继承自ExpandableObjectConverter 的TypeConverter。重写 GetProperties,并将有问题的属性替换为自定义属性。

从头开始编写 PropertyDescriptor 是一件苦差事;但在这种情况下,您主要只需将所有方法链接(“装饰器”)到原始(反射)描述符。只需重写 IsReadOnly 即可返回您想要的布尔值。

绝不是微不足道的,而是可以实现的。


using System;
using System.ComponentModel;
using System.Windows.Forms;
static class Program
{
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.Run(new Form { Text = "read only",
            Controls = {
                new PropertyGrid { Dock = DockStyle.Fill, SelectedObject = new Foo { IsBarEditable = false }}
            }
        });
        Application.Run(new Form { Text = "read write",
            Controls = {
                new PropertyGrid { Dock = DockStyle.Fill, SelectedObject = new Foo { IsBarEditable = true }}
            }
        });
    }

}

[TypeConverter(typeof(Foo.FooConverter))]
class Foo
{
    [Browsable(false)]
    public bool IsBarEditable { get; set; }
    public string Bar { get; set; }
    private class FooConverter : ExpandableObjectConverter
    {
        public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
        {
            var props = base.GetProperties(context, value, attributes);
            if (!((Foo)value).IsBarEditable)
            {   // swap it
                PropertyDescriptor[] arr = new PropertyDescriptor[props.Count];
                props.CopyTo(arr, 0);
                for (int i = 0; i < arr.Length; i++)
                {
                    if (arr[i].Name == "Bar") arr[i] = new ReadOnlyPropertyDescriptor(arr[i]);
                }
                props = new PropertyDescriptorCollection(arr);
            }
            return props;
        }
    }
}
class ReadOnlyPropertyDescriptor : ChainedPropertyDescriptor
{
    public ReadOnlyPropertyDescriptor(PropertyDescriptor tail) : base(tail) { }
    public override bool IsReadOnly
    {
        get
        {
            return true;
        }
    }
    public override void SetValue(object component, object value)
    {
        throw new InvalidOperationException();
    }
}
abstract class ChainedPropertyDescriptor : PropertyDescriptor
{
    private readonly PropertyDescriptor tail;
    protected PropertyDescriptor Tail { get {return tail; } }
    public ChainedPropertyDescriptor(PropertyDescriptor tail) : base(tail)
    {
        if (tail == null) throw new ArgumentNullException("tail");
        this.tail = tail;
    }
    public override void AddValueChanged(object component, System.EventHandler handler)
    {
        tail.AddValueChanged(component, handler);
    }
    public override AttributeCollection Attributes
    {
        get
        {
            return tail.Attributes;
        }
    }
    public override bool CanResetValue(object component)
    {
        return tail.CanResetValue(component);
    }
    public override string Category
    {
        get
        {
            return tail.Category;
        }
    }
    public override Type ComponentType
    {
        get { return tail.ComponentType; }
    }
    public override TypeConverter Converter
    {
        get
        {
            return tail.Converter;
        }
    }
    public override string Description
    {
        get
        {
            return tail.Description;
        }
    }
    public override bool DesignTimeOnly
    {
        get
        {
            return tail.DesignTimeOnly;
        }
    }
    public override string DisplayName
    {
        get
        {
            return tail.DisplayName;
        }
    }
    public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter)
    {
        return tail.GetChildProperties(instance, filter);
    }
    public override object GetEditor(Type editorBaseType)
    {
        return tail.GetEditor(editorBaseType);
    }
    public override object GetValue(object component)
    {
        return tail.GetValue(component);
    }
    public override bool IsBrowsable
    {
        get
        {
            return tail.IsBrowsable;
        }
    }
    public override bool IsLocalizable
    {
        get
        {
            return tail.IsLocalizable;
        }
    }
    public override bool IsReadOnly
    {
        get { return tail.IsReadOnly; }
    }
    public override string Name
    {
        get
        {
            return tail.Name;
        }
    }
    public override Type PropertyType
    {
        get { return tail.PropertyType; }
    }
    public override void RemoveValueChanged(object component, EventHandler handler)
    {
        tail.RemoveValueChanged(component, handler);
    }
    public override void ResetValue(object component)
    {
        tail.ResetValue(component);
    }
    public override void SetValue(object component, object value)
    {
        tail.SetValue(component, value);
    }
    public override bool ShouldSerializeValue(object component)
    {
        return tail.ShouldSerializeValue(component);
    }
    public override bool SupportsChangeEvents
    {
        get
        {
            return tail.SupportsChangeEvents;
        }
    }
}

Runtime property models are an advanced topic. For PropertyGrid the easiest route would be to write a TypeConverter, inheriting from ExpandableObjectConverter. Override GetProperties, and swap the property in question for a custom one.

Writing a PropertyDescriptor from scratch is a chore; but in this case you mainly just need to chain ("decorator") all the methods to the original (reflective) descriptor. And just override IsReadOnly to return the bool you want.

By no means trivial, but achievable.


using System;
using System.ComponentModel;
using System.Windows.Forms;
static class Program
{
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.Run(new Form { Text = "read only",
            Controls = {
                new PropertyGrid { Dock = DockStyle.Fill, SelectedObject = new Foo { IsBarEditable = false }}
            }
        });
        Application.Run(new Form { Text = "read write",
            Controls = {
                new PropertyGrid { Dock = DockStyle.Fill, SelectedObject = new Foo { IsBarEditable = true }}
            }
        });
    }

}

[TypeConverter(typeof(Foo.FooConverter))]
class Foo
{
    [Browsable(false)]
    public bool IsBarEditable { get; set; }
    public string Bar { get; set; }
    private class FooConverter : ExpandableObjectConverter
    {
        public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
        {
            var props = base.GetProperties(context, value, attributes);
            if (!((Foo)value).IsBarEditable)
            {   // swap it
                PropertyDescriptor[] arr = new PropertyDescriptor[props.Count];
                props.CopyTo(arr, 0);
                for (int i = 0; i < arr.Length; i++)
                {
                    if (arr[i].Name == "Bar") arr[i] = new ReadOnlyPropertyDescriptor(arr[i]);
                }
                props = new PropertyDescriptorCollection(arr);
            }
            return props;
        }
    }
}
class ReadOnlyPropertyDescriptor : ChainedPropertyDescriptor
{
    public ReadOnlyPropertyDescriptor(PropertyDescriptor tail) : base(tail) { }
    public override bool IsReadOnly
    {
        get
        {
            return true;
        }
    }
    public override void SetValue(object component, object value)
    {
        throw new InvalidOperationException();
    }
}
abstract class ChainedPropertyDescriptor : PropertyDescriptor
{
    private readonly PropertyDescriptor tail;
    protected PropertyDescriptor Tail { get {return tail; } }
    public ChainedPropertyDescriptor(PropertyDescriptor tail) : base(tail)
    {
        if (tail == null) throw new ArgumentNullException("tail");
        this.tail = tail;
    }
    public override void AddValueChanged(object component, System.EventHandler handler)
    {
        tail.AddValueChanged(component, handler);
    }
    public override AttributeCollection Attributes
    {
        get
        {
            return tail.Attributes;
        }
    }
    public override bool CanResetValue(object component)
    {
        return tail.CanResetValue(component);
    }
    public override string Category
    {
        get
        {
            return tail.Category;
        }
    }
    public override Type ComponentType
    {
        get { return tail.ComponentType; }
    }
    public override TypeConverter Converter
    {
        get
        {
            return tail.Converter;
        }
    }
    public override string Description
    {
        get
        {
            return tail.Description;
        }
    }
    public override bool DesignTimeOnly
    {
        get
        {
            return tail.DesignTimeOnly;
        }
    }
    public override string DisplayName
    {
        get
        {
            return tail.DisplayName;
        }
    }
    public override PropertyDescriptorCollection GetChildProperties(object instance, Attribute[] filter)
    {
        return tail.GetChildProperties(instance, filter);
    }
    public override object GetEditor(Type editorBaseType)
    {
        return tail.GetEditor(editorBaseType);
    }
    public override object GetValue(object component)
    {
        return tail.GetValue(component);
    }
    public override bool IsBrowsable
    {
        get
        {
            return tail.IsBrowsable;
        }
    }
    public override bool IsLocalizable
    {
        get
        {
            return tail.IsLocalizable;
        }
    }
    public override bool IsReadOnly
    {
        get { return tail.IsReadOnly; }
    }
    public override string Name
    {
        get
        {
            return tail.Name;
        }
    }
    public override Type PropertyType
    {
        get { return tail.PropertyType; }
    }
    public override void RemoveValueChanged(object component, EventHandler handler)
    {
        tail.RemoveValueChanged(component, handler);
    }
    public override void ResetValue(object component)
    {
        tail.ResetValue(component);
    }
    public override void SetValue(object component, object value)
    {
        tail.SetValue(component, value);
    }
    public override bool ShouldSerializeValue(object component)
    {
        return tail.ShouldSerializeValue(component);
    }
    public override bool SupportsChangeEvents
    {
        get
        {
            return tail.SupportsChangeEvents;
        }
    }
}
满地尘埃落定 2024-10-19 05:06:35

这个答案假设您正在谈论 WinForms。如果您想根据另一个属性更改一个属性的只读状态,则需要让您的对象 实现 ICustomTypeDescriptor。这不是一件简单的事情,但是它将为您的类在属性网格中的显示方式提供很大的灵活性。

This answer assumes you are talking about WinForms. If you would like to change one property's readonly state based on another, you will need to have your object implement ICustomTypeDescriptor. This isn't a simple thing to do, but it will give you lots of flexibility about how your class is displayed in the propertygrid.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文