【问题标题】:Readonly property on interface is editable in PropertyGrid界面上的只读属性在 PropertyGrid 中是可编辑的
【发布时间】:2015-05-10 11:58:11
【问题描述】:

我有一个带有一堆属性的接口,其中一些属性被定义为只读,例如:

public interface IActivity {
  string Id { get; }
  bool IsEnabled { get; }
}

实现这个接口的类有公共的set方法,可以在别处使用,但是这个接口的使用者应该不能设置这些属性。我现在正在构建一个测试使用者,并通过 PropertyGrid 控件公开对象。因为它是通过公共 set 方法绑定到类的,所以就消费者而言应该是只读的属性在网格中是可编辑的。

我可以通过两种方式解决此问题,首先通过设置设置器internal,或通过使用[ReadOnly] 属性标记属性,但这似乎并不“正确”,因为理论上其他东西可以实现这个界面不受我的控制,那些所谓的只读属性可以通过属性网格进行更改。

在将对象分配给属性网格时,我尝试显式转换为接口,但这也无济于事:

propGrid.SelectedObject = (IActivity)obj;

有没有办法强制 PropertyGrid 控件遵守接口的约定,而不必更改具体的类?

【问题讨论】:

  • 网格可能使用反射来确定它应该显示哪些列以及这些列是否可编辑。由于您传入的对象是允许编辑属性的类型,因此您无能为力。并且将其转换为更受限制的类型也无济于事,因为 SelectedObject 无论如何都需要 object
  • 是的,这就是我的想法,它必须反映给您可以应用的其他属性来更改网格中的行为。只是希望有一种方法可以强制它遵循界面

标签: c# winforms propertygrid


【解决方案1】:

我通过创建一个与接口规范完全匹配的包装类来解决这个问题:

class ActivityWrapper : IActivity {
    private readonly IActivity _activity;
    public ActivityWrapper(IActivity activity) {
        _activity = activity;
    }

    public string Id
    {
        get { return _activity.Id; }
    }
    public bool IsEnabled
    {
        get { return _activity.IsEnabled; }
    }
}

在将对象暴露给属性网格时使用它:

propGrid.SelectedObject = new ActivityWrapper((IActivity)obj);

如果有一种不同的、更自动的方式来实现这一点,而不是维护另一个类,我仍然会感兴趣。

【讨论】:

    【解决方案2】:

    詹姆斯的回答是正确的。我将补充一点,如果您的 IActivity 实现了 INotifyPropertyChanged,您必须以这种方式路由事件:

    class ActivityWrapper : IActivity
    {
        private readonly IActivity _activity;
        public ActivityWrapper(IActivity activity)
        {
            _activity = activity;
            _activity.PropertyChanged += _activity_PropertyChanged;
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        void _activity_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, e);
        }
    
        public string Id
        {
            get { return _activity.Id; }
        }
        public bool IsEnabled
        {
            get { return _activity.IsEnabled; }
        }
    }
    

    我认为实现自动化的唯一方法是使用 Reflection.Emit 生成这个包装器。

    【讨论】:

    • 就我而言,它确实实现了INotifyPropertyChanged。目前我面前没有代码 - 我明天会回来看看我实际上做了什么 - 我想它可能和你在这里得到的差不多。
    • 刚刚检查过 - 确实几乎相同,但在构造函数中使用匿名 lambda 函数内联完成。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-15
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 2010-12-05
    • 1970-01-01
    相关资源
    最近更新 更多