Создание пользовательской коллекции, которая может быть связана с DataGrid - PullRequest
2 голосов
/ 16 июля 2009

Я работаю в архитектурной фирме и создаю плагин для программы 3D-моделирования, чтобы помочь дизайну. У меня есть класс Building и класс Floor . Здание содержит ссылку на коллекцию этажей FloorList . Я пытаюсь выяснить, на чем основывать коллекцию FloorList , чтобы я мог минимизировать объем работы, которую мне нужно сделать, чтобы создать интерфейс для редактирования коллекции.

Коллекция Этаж представляет собой серию этажей зданий, уложенных друг на друга. Каждое Этаж имеет свойство Floor.Height , предназначенное для чтения и записи, и свойство Floor.Elevation , которое доступно только для чтения и устанавливается путем суммирования высот этажа ниже ток этаж . Таким образом, всякий раз, когда Floor добавляется, удаляется, перемещается или изменяется в коллекции, свойства Floor.Elevation необходимо обновлять.

Кроме того, я хочу создать пользовательский интерфейс для редактирования этой коллекции. Я думал об использовании элемента управления DataGrid , где каждый Этаж указан со своими Высота и другими свойствами в качестве строки элемента управления. Пользователь должен иметь возможность добавлять, удалять и переупорядочивать этажи с помощью элемента управления. Я бы хотел, чтобы это было максимально простым и гибким. Это означает, что я хотел бы просто иметь возможность привязать коллекцию этажей к DataGrid и иметь заполненные столбцы DataGrid на основе свойств Floor учебный класс. Если возможно, я бы хотел использовать встроенный интерфейс добавления / удаления пользовательского интерфейса элемента управления DataGrid без необходимости возиться с настройкой связки событий между моей коллекцией и DataGrid .

Чтобы еще больше усложнить ситуацию в будущем, я должен иметь возможность позволить пользователю динамически добавлять пользовательские свойства в Этажи , которые я хочу, чтобы они могли видеть и редактировать в DataGrid . Я думаю, что в конечном итоге я сделаю это, если Floor class реализует IExtenderProvider . Таким образом, в конечном итоге DataGrid будет выглядеть примерно так:

Initial Properties      Future Custom User Properties

Height    Elevation     ProgramType    UnitType  UnitCount  
15'       70'           Residential    Luxury    5
15'       55'           Residential    Luxury    5
15'       40'           Residential    Budget    10
20'       20'           Retail         N/A       2
20'       0'            Retail         N/A       3

Мой вопрос сейчас заключается в том, на чем я должен основывать свою коллекцию FloorList , чтобы использовать эту функцию? Варианты, которые я рассматриваю, следующие:

1) Наследовать от Списка (Этаж)

  • Такие методы, как Add / Remove, не являются vitrual, и поэтому я не могу не переопределить их для обновления высот

2) Реализация IList (Этаж)

  • Событие OnChange не встроено, поэтому при изменении списков DataGrid не будет обновляться (я думаю?)

  • Я думаю, что это, вероятно, лучший вариант, но что мне нужно сделать, чтобы изменения в коллекции FloorList или DataGrid синхронизировались друг с другом?

3) Наследование от BindingList (Floor)

  • Такие методы, как Добавить / Удалить, не являются виртуальными, поэтому я не могу изменить их для обновления высот этажа.

4) Реализация IBindingList

  • IBindinglist не является универсальным, и я хочу, чтобы моя коллекция содержала Floor objects

Ответы [ 3 ]

1 голос
/ 17 июля 2009

Вы должны использовать BindingList для своей коллекции или реализовать IBindingList, поскольку это будет уведомлять DataGridView о любых изменениях в списке.

Затем реализуйте интерфейс INotifyPropertyChanged для класса Floor, это позволит создать режим привязки TwoWay между вашими отдельными элементами Floor и DataGridView.

Эрик, ты тоже мог бы сделать что-то подобное

   public class MyFloorCollection : BindingList<Floor>
            {
                public MyFloorCollection()
                    : base()
                {
                    this.ListChanged += new ListChangedEventHandler(MyFloorCollection_ListChanged);

                }

                void MyFloorCollection_ListChanged(object sender, ListChangedEventArgs e)
                {

                 if (e.ListChangedType == ListChangedType.ItemAdded)
                 {

                    Floor newFloor = this[e.NewIndex] as Floor;

                    if (newFloor != null)
                    {
                        newFloor.HeightChanged += new Floor.HeightChangedEventHandler(newFloor_HeightChanged);
                    }
                  }

                }

                void newFloor_HeightChanged(int newValue, int oldValue)
                {
                    //recaluclate
                }


            }

Конечно, вы можете создать свой собственный HeightChangedEvent и подписаться на него, чтобы вам не приходилось указывать имена свойств в операторе if.

Так что ваш класс Этаж будет выглядеть так

 public class Floor : INotifyPropertyChanged
        {
            private int _height;

            public int Height
            {
                get { return _height; }
                set 
                {
                    if (HeightChanged != null)
                        HeightChanged(value, _height);

                    _height = value;
                    OnPropertyChanged("Height");

                }
            }




            public int Elevation { get; set; }

            private void OnPropertyChanged(string property)
            {
                if (this.PropertyChanged != null)
                    this.PropertyChanged(this, new PropertyChangedEventArgs(property));
            }

            #region INotifyPropertyChanged Members

            public event PropertyChangedEventHandler PropertyChanged;

            #endregion

            public delegate void HeightChangedEventHandler(int newValue, int oldValue);
            public event HeightChangedEventHandler HeightChanged;
        }

таким образом, вам нужно только подписаться на переменную HeightChanged, а не на PropertyChanged. PropertyChanged будет использоваться DataGridView для сохранения привязки TwoWay. Я верю, что этот путь чище.

Вы также можете изменить делегата и передать его в качестве отправителя.

public delegate void HeightChangedEventHandler(Floor sender, int newValue, int oldValue);

РЕДАКТИРОВАТЬ: Чтобы отписаться от события HeightChanged, вам необходимо переопределить RemoveItem

  protected override void RemoveItem(int index)
        {
            if (index > -1)
                this[index].HeightChanged -= newFloor_HeightChanged;

            base.RemoveItem(index);
        }
0 голосов
/ 17 июля 2009

Вы можете попробовать выставить свойство ObservableCollection<Floor> для некоторых данных, содержащих класс. Кроме того, объект Floor должен был бы реализовать INotifyPropertyChanged для поддержки двусторонней привязки из пользовательского интерфейса.

0 голосов
/ 17 июля 2009

Реализация IList (Floor), и ваша новая коллекция также реализует интерфейс INotifyPropertyChanged .

...