2

私は建築会社で働いており、設計を支援する 3D モデリング プログラムのプラグインを作成しています。BuildingクラスとFloorクラスがあります。建物には、フロアのFloorListコレクションへの参照が含まれています。コレクションを編集するためのインターフェイスを作成するために必要な作業量を最小限に抑えるために、 FloorListコレクションのベースとなるものを見つけようとしています。

Floorコレクションは、互いに積み重ねられた一連の建物の床を表します。各Floorには、読み書き可能なFloor.Heightプロパティと、読み取り専用で現在のFloorより下の床の高さを合計して設定されるFloor.Elevationプロパティがあります。したがって、Floorがコレクションで追加、削除、移動、または変更されるたびに、Floor.Elevationプロパティを更新する必要があります。

さらに、このコレクションを編集するための UI を作成したいと考えています。各フロアがその高さとその他のプロパティと共にコントロールの行としてリストされているDataGridコントロールを使用することを考えていました。ユーザーは、コントロールを使用してフロアを追加、削除、並べ替えできる必要があります。これをできるだけ簡単かつ柔軟に設定したいと思います。つまり、Floor のコレクションをDataGridにバインドし、 Floorのプロパティに基づいてDataGridの列を設定できるようにしたいということです。クラス。可能であれば、コレクションとDataGridの間に一連のイベント関係を設定する必要なく、 DataGrid コントロールの組み込みの追加/削除 UI インターフェイスを利用できるようにしたいと考えています。

将来的に事態をさらに複雑にするために、ユーザーがフロアにカスタム プロパティを動的に追加できるようにする必要があります。これらのプロパティは、 DataGridでも表示および編集できるようにする必要があります。FloorクラスにIExtenderProviderを実装させることで、それを行うことになると思います。したがって、最終的にDataGridは次のようになります。

初期プロパティ 将来のカスタム ユーザー プロパティ

標高 ProgramType UnitType UnitCount  
15' 70' レジデンシャル ラグジュアリー 5
15' 55' レジデンシャル ラグジュアリー 5
15' 40' 住宅予算 10
20' 20' 小売 該当なし 2
20' 0' 小売 該当なし 3

私の質問は、この機能を可能にするために、 FloorListコレクションを何に基づいて作成する必要があるかということです。私が検討しているオプションは次のとおりです。

1) リスト(フロア)から継承

  • Add/Remove などのメソッドは仮想的ではないため、それらをオーバーライドして標高を更新することはできません

2) IList(フロア) を実装する

  • OnChange イベントは組み込まれていないため、リストが変更された場合、DataGrid は更新されません (私は思いますか?)

  • これがおそらく最良の選択肢だと思いますが、FloorListコレクションまたはDataGridへの変更が互いに同期されるようにするにはどうすればよいでしょうか?

3) BindingList(Floor) から継承

  • 追加/削除などのメソッドは仮想ではないため、それらを変更して床の高さを更新することはできません。

4) IBindingList を実装する

  • IBindinglist はジェネリックではなく、コレクションにFloorオブジェクトのみを含めたい
4

3 に答える 3

1

コレクションに BindingList を使用するか、IBindingList を実装する必要があります。これにより、リスト内の変更が DataGridView に通知されます。

次に、Floor クラスの INotifyPropertyChanged インターフェイスを実装します。これにより、個々の Floor アイテムと DataGridView の間で TwoWay バインディング モードが可能になります。

エリック、このようなこともできます

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

この方法では、PropertyChanged ではなく、HeightChanged 変数をサブスクライブするだけで済みます。PropertyChanged は、TwoWay バインディングを維持するために DataGridView によって消費されます。私はこの方法がよりきれいだと信じています。

デリゲートを変更して、アイテムを送信者として渡すこともできます。

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);
        }
于 2009-07-16T20:22:21.800 に答える
0

IList(Floor) を実装し、新しいコレクションにもINotifyPropertyChangedインターフェイスを実装します。

于 2009-07-16T20:20:50.993 に答える
0

ObservableCollection<Floor>クラスを含むデータのプロパティを公開してみてください。また、UI からの双方向バインディングをサポートするために、Floorオブジェクトを実装する必要があります。INotifyPropertyChanged

于 2009-07-16T20:24:38.473 に答える