0

Иногда полезно наследовать базовую форму или базовый пользовательский элемент управления, который поставляет источник привязки для наследников.Как решить ошибку «время создания элемента данных» с наследственным источником привязки

Унаследованные классы могут, например, установить источник данных на свой конкретный тип во время разработки или связывать элементы управления - все без написания специального кода в каждом унаследованном элементе управления для управления источником привязки. Вы можете даже использовать master-detail, добавив источники привязки дочерних элементов к набору свойств элемента данных.

Ребенок обязывает работать во время исполнения, но, к сожалению, дизайнер отправляется на это во время разработки при открытии сохраненного дочернего элемента управления. Вместо фактического выполнения кода в InitializeComponent дизайнер использует десериализаторы для интерпретации текста. В этом случае источник привязки базового класса еще не настроен, когда дочерний класс пытается найти элемент данных на нем.

Короткий рассказ: совершенный код времени выполнения, но ошибка времени разработки «Элемент данных не найден в источнике данных».

ответ

1

Одним из решений является подкласс BindingSource. Получившийся класс по-прежнему будет BindingSource, поэтому разработчик будет знать, что он не добавляет дополнительный источник привязки между ним и связанным элементом управления.

Во время разработки любые дескрипторы свойств, которые дизайнер ожидает найти, будут созданы на лету. Их не запомнят. Дизайнер завершит инициализацию и открытие, и все будет как ожидается.

Во время выполнения InheritableBindingSource ведет себя точно так же, как BindingSource.

public class InheritableBindingSource : BindingSource 
{ 
    public override PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors) 
    { 
     if (this.DesignMode) 
     { 
      var baseProperties = base.GetItemProperties(listAccessors); 
      var array = new PropertyDescriptor[baseProperties.Count]; 
      baseProperties.CopyTo(array, 0); 
      // Return an identical class, but with a modified Find behaviour. 
      return new DesignerPropertyDescriptorCollection(array); 
     } 

     // At runtime, InheritedBindingClass does nothing special. 
     return base.GetItemProperties(listAccessors); 
    } 


    class DesignerPropertyDescriptorCollection : PropertyDescriptorCollection 
    { 
     public DesignerPropertyDescriptorCollection(PropertyDescriptor[] properties) 
      : base(properties, readOnly: true) 
     { 
     } 

     public override PropertyDescriptor Find(string name, bool ignoreCase) 
     { 
      // Guaranteed to return a descriptor for any property that is being looked up, whether it has any meaning or not. 
      return base.Find(name, ignoreCase) ?? new DummyPropertyDescriptor(name); 
     } 
    } 


    // A property descriptor that has no state whatsoever. 
    class DummyPropertyDescriptor : PropertyDescriptor 
    { 
     public DummyPropertyDescriptor(string name) 
      : base(name, new Attribute[0]) 
     { 
     } 

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

     public override Type ComponentType 
     { 
      get { return typeof(object); } 
     } 

     public override object GetValue(object component) 
     { 
      return null; 
     } 

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

     public override Type PropertyType 
     { 
      get { return typeof(object); } 
     } 

     public override void ResetValue(object component) 
     { 
     } 

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

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