2015-03-09 3 views
1

У меня есть интерфейс с кучей свойств, некоторые из которых определены как неизменяемые, например:Readonly свойство на интерфейсе редактирования в PropertyGrid

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

Класс, который реализует этот интерфейс имеет государственные set методы, для использовать в другом месте, но потребитель этого интерфейса не должен устанавливать эти свойства. Теперь я создаю тестового потребителя и выставляю объект через элемент управления PropertyGrid. Поскольку он привязан к классу с помощью методов общедоступных множеств, свойства, которые только для чтения могут касаться потребителя, редактируются в сетке.

я могу решить эту проблему двумя способами, во-первых, делая сеттеры internal или пометив свойства с атрибутом [ReadOnly], однако это не похоже, «право», так как в теории что-то еще может реализовать этот интерфейс из из моего контроля, с теми, которые предположительно readonly свойства затем изменяемые через сетку свойств.

Я попытался явно приведение к интерфейсу при назначении объекта в таблицу свойств, но это не помогло:

propGrid.SelectedObject = (IActivity)obj; 

Есть ли способ заставить контроль PropertyGrid уважать Контракт Интерфейс, вместо того, чтобы менять конкретные классы?

+0

Сетка, вероятно, использует отражение, чтобы определить, какие столбцы она должна отображать и могут ли эти столбцы редактироваться или нет. Поскольку объект, который вы передаете, имеет тип, который позволяет редактировать свойства, вы не можете сделать это очень много. И приведение его к некоторому более ограниченному типу не поможет, потому что 'SelectedObject' ожидает« объект »в любом случае. – poke

+0

Да, это то, что я понял, оно должно быть отражено с учетом других атрибутов, которые вы можете применить для изменения поведения в сетке. Просто надеялся, что может быть способ заставить его следовать интерфейсу –

ответ

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); 

Я d по-прежнему интересно, если есть другой, более автоматический способ достижения этого, а не поддерживать другой класс.

1

Ответ Джеймса правильный. Я только добавлю, что если ваш 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.

+0

В моем случае он действительно реализует 'INotifyPropertyChanged'. У меня нет кода, который передо мной в данный момент - я вернусь завтра, чтобы посмотреть, что я на самом деле сделал с этим, - я думаю, это, вероятно, в значительной степени, так как вы получили его здесь. –

+0

Просто проверено - действительно было почти то же самое, но было сделано inline в конструкторе с анонимной функцией лямбда. –