2009-06-09 Ivan N. Zlatev <contact@i-nz.net>
authorIvan Zlatev <ivan@ivanz.com>
Tue, 9 Jun 2009 15:56:21 +0000 (15:56 -0000)
committerIvan Zlatev <ivan@ivanz.com>
Tue, 9 Jun 2009 15:56:21 +0000 (15:56 -0000)
* DataGridViewComboBoxCell.cs, DataGridViewComboBoxColumn.cs:
Implement items syncing in the non-databound scenario.
[Fixes bug #494031]

svn path=/trunk/mcs/; revision=135770

mcs/class/Managed.Windows.Forms/System.Windows.Forms/ChangeLog
mcs/class/Managed.Windows.Forms/System.Windows.Forms/DataGridViewComboBoxCell.cs
mcs/class/Managed.Windows.Forms/System.Windows.Forms/DataGridViewComboBoxColumn.cs

index 0eb976bc5dfdcf7dd1f7dc50569f5bff5d6f05a5..105cb7c89bb354015000c77b73aaba9e81df2e04 100644 (file)
@@ -1,3 +1,9 @@
+2009-06-09  Ivan N. Zlatev  <contact@i-nz.net>
+
+       * DataGridViewComboBoxCell.cs, DataGridViewComboBoxColumn.cs: 
+       Implement items syncing in the non-databound scenario.
+       [Fixes bug #494031]
+
 2009-06-09  Ivan N. Zlatev  <contact@i-nz.net>
 
        * DataGridView.cs: Call OnCellValidating and OnCellValidated and 
index 44fdaabc1034626c7a2254ae731d19dc399069b3..7374b39a65afeb305109345123bcd1e30a29f82b 100644 (file)
@@ -46,6 +46,7 @@ namespace System.Windows.Forms {
                private int maxDropDownItems;
                private bool sorted;
                private string valueMember;
+               private DataGridViewComboBoxColumn owningColumnTemlate;
 
                public DataGridViewComboBoxCell () : base() {
                        autoComplete = true;
@@ -57,6 +58,7 @@ namespace System.Windows.Forms {
                        items = new ObjectCollection(this);
                        maxDropDownItems = 8;
                        sorted = false;
+                       owningColumnTemlate = null;
                }
 
                [DefaultValue (true)]
@@ -129,11 +131,11 @@ namespace System.Windows.Forms {
                        get {
                                if (DataGridView != null && DataGridView.BindingContext != null 
                                    && DataSource != null && !String.IsNullOrEmpty (ValueMember)) {
-                                       items.Clear ();
+                                       items.ClearInternal ();
                                        CurrencyManager dataManager = (CurrencyManager) DataGridView.BindingContext[DataSource];
                                        if (dataManager != null && dataManager.Count > 0) {
                                                foreach (object item in dataManager.List)
-                                                       items.Add (item);
+                                                       items.AddInternal (item);
                                        }
                                }
 
@@ -175,6 +177,12 @@ namespace System.Windows.Forms {
                        get { return typeof(string); }
                }
 
+               // Valid only for template Cells and used as a bridge to push items
+               internal DataGridViewComboBoxColumn OwningColumnTemplate {
+                       get { return owningColumnTemlate; }
+                       set { owningColumnTemlate = value; }
+               }
+
                public override object Clone () {
                        DataGridViewComboBoxCell cell = (DataGridViewComboBoxCell) base.Clone();
                        cell.autoComplete = this.autoComplete;
@@ -185,7 +193,7 @@ namespace System.Windows.Forms {
                        cell.displayStyleForCurrentCellOnly = this.displayStyleForCurrentCellOnly;
                        cell.dropDownWidth = this.dropDownWidth;
                        cell.flatStyle = this.flatStyle;
-                       cell.items.AddRange(this.items);
+                       cell.items.AddRangeInternal(this.items);
                        cell.maxDropDownItems = this.maxDropDownItems;
                        cell.sorted = this.sorted;
                        return cell;
@@ -214,9 +222,32 @@ namespace System.Windows.Forms {
                                editingControl.DisplayMember = DisplayMember;
                        } else {
                                editingControl.Items.AddRange (this.Items);
+                               if (FormattedValue != null && editingControl.Items.IndexOf (FormattedValue) != -1)
+                                       editingControl.SelectedItem = FormattedValue;
                        }
                }
 
+               internal void SyncItems ()
+               {
+                       if (DataSource != null || OwningColumnTemplate == null)
+                               return;
+
+                       if (OwningColumnTemplate.DataGridView != null) {
+                               DataGridViewComboBoxEditingControl editor = OwningColumnTemplate.DataGridView.EditingControl
+                                                                           as DataGridViewComboBoxEditingControl;
+                               if (editor != null) {
+                                       object selectedItem = editor.SelectedItem;
+                                       editor.Items.Clear ();
+                                       editor.Items.AddRange (items);
+                                       if (editor.Items.IndexOf (selectedItem) != -1)
+                                               editor.SelectedItem = selectedItem;
+                               }
+                       }
+
+                       // Push the new items to the column
+                       OwningColumnTemplate.SyncItems (Items);
+               }
+
                public override bool KeyEntersEditMode (KeyEventArgs e)
                {
                        if (e.KeyCode == Keys.Space)
@@ -365,15 +396,19 @@ namespace System.Windows.Forms {
                        return button_area;
                }
 
+               // IMPORTANT: Only call the internal methods from within DataGridViewComboBoxCell
+               // for adding/removing/clearing because the other methods invoke an update of the 
+               // column items collection and you might end up in an endless loop.
+               //
                [ListBindable (false)]
                public class ObjectCollection : IList, ICollection, IEnumerable {
 
                        private ArrayList list;
+                       private DataGridViewComboBoxCell owner;
 
-                       //private DataGridViewComboBoxCell owner;
-
-                       public ObjectCollection (DataGridViewComboBoxCell owner) {
-                               //this.owner = owner;
+                       public ObjectCollection (DataGridViewComboBoxCell owner)
+                       {
+                               this.owner = owner;
                                list = new ArrayList();
                        }
 
@@ -399,26 +434,71 @@ namespace System.Windows.Forms {
 
                        public virtual object this [int index] {
                                get { return list[index]; }
-                               set { list[index] = value; }
+                               set {
+                                       ThrowIfOwnerIsDataBound ();
+                                       list[index] = value;
+                               }
+                       }
+
+                       public int Add (object item)
+                       {
+                               ThrowIfOwnerIsDataBound ();
+                               int index = AddInternal (item);
+                               SyncOwnerItems ();
+                               return index;
+                       }
+                       
+                       internal int AddInternal (object item)
+                       {
+                               return list.Add (item);
+                       }
+
+                       internal void AddRangeInternal (ICollection items)
+                       {
+                               list.AddRange (items);
+                       }
+
+                       public void AddRange (ObjectCollection value)
+                       {
+                               ThrowIfOwnerIsDataBound ();
+                               AddRangeInternal (value);
+                               SyncOwnerItems ();
                        }
 
-                       public int Add (object item) {
-                               return list.Add(item);
+                       private void SyncOwnerItems ()
+                       {
+                               ThrowIfOwnerIsDataBound ();
+                               if (owner != null)
+                                       owner.SyncItems ();
                        }
 
-                       public void AddRange (ObjectCollection value) {
-                               list.AddRange(value.list);
+                       public void ThrowIfOwnerIsDataBound ()
+                       {
+                               if (owner != null && owner.DataGridView != null && owner.DataSource != null)
+                                       throw new ArgumentException ("Cannot modify collection if the cell is data bound.");
                        }
 
-                       public void AddRange (params object[] items) {
-                               list.AddRange(items);
+                       public void AddRange (params object[] items)
+                       {
+                               ThrowIfOwnerIsDataBound ();
+                               AddRangeInternal (items);
+                               SyncOwnerItems ();
                        }
 
-                       public void Clear () {
-                               list.Clear();
+                       public void Clear ()
+                       {
+                               ThrowIfOwnerIsDataBound ();
+                               ClearInternal ();
+                               SyncOwnerItems ();
                        }
 
-                       public bool Contains (object value) {
+                       internal void ClearInternal ()
+                       {
+                               list.Clear ();
+                       }
+
+                       public bool Contains (object value)
+                       {
                                return list.Contains(value);
                        }
 
@@ -432,26 +512,51 @@ namespace System.Windows.Forms {
                                list.CopyTo (destination, arrayIndex);
                        }
 
-                       public IEnumerator GetEnumerator () {
+                       public IEnumerator GetEnumerator ()
+                       {
                                return list.GetEnumerator();
                        }
 
-                       public int IndexOf (object value) {
+                       public int IndexOf (object value)
+                       {
                                return list.IndexOf(value);
                        }
 
-                       public void Insert (int index, object item) {
-                               list.Insert(index, item);
+                       public void Insert (int index, object item)
+                       {
+                               ThrowIfOwnerIsDataBound ();
+                               InsertInternal (index, item);
+                               SyncOwnerItems ();
+                       }
+
+                       internal void InsertInternal (int index, object item)
+                       {
+                               list.Insert (index, item);
                        }
 
-                       public void Remove (object value) {
-                               list.Remove(value);
+                       public void Remove (object value)
+                       {
+                               ThrowIfOwnerIsDataBound ();
+                               RemoveInternal (value);
+                               SyncOwnerItems ();
                        }
 
-                       public void RemoveAt (int index) {
-                               list.RemoveAt(index);
+                       internal void RemoveInternal (object value)
+                       {
+                               list.Remove (value);
                        }
 
+                       public void RemoveAt (int index)
+                       {
+                               ThrowIfOwnerIsDataBound ();
+                               RemoveAtInternal (index);
+                               SyncOwnerItems ();
+                       }
+
+                       internal void RemoveAtInternal (int index)
+                       {
+                               list.RemoveAt (index);
+                       }
 
                        int IList.Add (object item)
                        {
index 5cbaca856c92dc2873f286a2a86af59a21735b8e..1fb5608ecb5cfd1dd96c97a2ff64d5a09e9b888f 100644 (file)
@@ -26,6 +26,7 @@
 
 #if NET_2_0
 
+using System.Collections;
 using System.ComponentModel;
 using System.Drawing.Design;
 using System.Drawing;
@@ -45,6 +46,7 @@ namespace System.Windows.Forms {
                public DataGridViewComboBoxColumn ()
                {
                        CellTemplate = new DataGridViewComboBoxCell();
+                       ((DataGridViewComboBoxCell) CellTemplate).OwningColumnTemplate = this;
                        SortMode = DataGridViewColumnSortMode.NotSortable;
                        autoComplete = true;
                        displayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton;
@@ -62,7 +64,15 @@ namespace System.Windows.Forms {
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                public override DataGridViewCell CellTemplate {
                        get { return base.CellTemplate; }
-                       set { base.CellTemplate = value as DataGridViewComboBoxCell; }
+                       set {
+
+                               DataGridViewComboBoxCell cellTemplate = value as DataGridViewComboBoxCell;
+                               if (cellTemplate == null)
+                                       throw new InvalidCastException ("Invalid cell tempalte type.");
+
+                               cellTemplate.OwningColumnTemplate = this;
+                               base.CellTemplate = cellTemplate;
+                       }
                }
 
                [AttributeProvider (typeof (IListSource))]
@@ -201,6 +211,20 @@ namespace System.Windows.Forms {
                        }
                }
 
+               internal void SyncItems (IList items)
+               {
+                       if (DataSource != null || DataGridView == null)
+                               return;
+
+                       for (int i = 0; i < DataGridView.RowCount; i++) {
+                               DataGridViewComboBoxCell comboCell = DataGridView.Rows[i].Cells[base.Index] as DataGridViewComboBoxCell;
+                               if (comboCell != null) {
+                                       comboCell.Items.ClearInternal ();
+                                       comboCell.Items.AddRangeInternal (this.Items);
+                               }
+                       }
+               }
+
                public override object Clone ()
                {
                        DataGridViewComboBoxColumn col = (DataGridViewComboBoxColumn) base.Clone();