Cześć, mam kontrolkę - ComboBox z kolumnami. Chcę móc za jej pomocą edytować wartości w komórce DataGridView. Kontrolka potrzebuje do poprawnego działania jakichś danych - w moim wypadku jest to lista. Stworzyłem sobie własny typ kolumny i wszystkie inne potrzebne rzeczy, ale problemem jest to, że jak opuszczam edytowaną komórkę, to w ParseFormattedValue dostaję błąd:

An exception of type 'System.ArgumentException' occurred in System.Windows.Forms.dll but was not handled in user code
Additional information: Sformatowana wartość komórki ma nieprawidłowy typ.

Kod jest wzięty ze stron MS i przerobiony na moje potrzeby:

 
//kolumna
public class MultiColComboColumn: DataGridViewColumn
    {
        //dane do comboBoxa
        private List<GroupRecord> m_DataSource = null;
        public List<GroupRecord> DataSource
        {
            get { return m_DataSource; }
            set { m_DataSource = value; }
        }
        
        public MultiColComboColumn(): base(new MultiColComboCell())
        {

        }

        public override DataGridViewCell CellTemplate
        {
            get
            {
                return base.CellTemplate;
            }

            set
            {
                if (value != null &&
                    !value.GetType().IsAssignableFrom(typeof(MultiColComboCell)))
                {
                    throw new InvalidCastException("Must be a MultiColComboCell");
                }
                base.CellTemplate = value;
            }
        }
    }


   //komórka
    public class MultiColComboCell: DataGridViewTextBoxCell
    {
       
        public MultiColComboCell()
            : base()
        {

        }

        public override void InitializeEditingControl(int rowIndex, object 
            initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
        {
            // Set the value of the editing control to the current cell value. 
            base.InitializeEditingControl(rowIndex, initialFormattedValue, 
                dataGridViewCellStyle);
            MultiColComboEditingControl ctl =
                DataGridView.EditingControl as MultiColComboEditingControl;

            MultiColComboColumn col = OwningColumn as MultiColComboColumn;
            
            if(col.DataSource != null)
            {
                //tutaj ustawiam odpowiednio comboboxa
                ctl.DataSource = col.DataSource;
                ctl.SetVisibleCols("Symbol", "Name");
                ctl.DisplayMember = "Name";
                ctl.ValueMember = "Symbol";
            }

            // Use the default row value when Value property is null. 
            if (this.Value == null)
            {
                ctl.SelectedItem = (GroupRecord)this.DefaultNewRowValue;
            }
            else
            {
                ctl.SelectedItem = (GroupRecord)this.Value;
            }
        }

        public override Type EditType
        {
            get
            {
                // Return the type of the editing control that CalendarCell uses. 
                return typeof(MultiColComboEditingControl);
            }
        }

        public override Type ValueType
        {
            get
            {
                // Return the type of the value that CalendarCell contains. 

                return typeof(GroupRecord);
            }
        }

        public override object DefaultNewRowValue
        {
            get
            {
                // Use the current date and time as the default value. 
                return new GroupRecord(0, "Symbol", "Wybierz...", false);
            }
        }
    }

    
    //kontrolka edycyjna
    class MultiColComboEditingControl: MultiColumnComboBox, IDataGridViewEditingControl
    {
        DataGridView dataGridView;
        private bool valueChanged = false;
        int rowIndex;

        public MultiColComboEditingControl()
        {
            
        }

        // Implements the IDataGridViewEditingControl.EditingControlFormattedValue  
        // property. 
        public object EditingControlFormattedValue
        {
            get
            {
                return (GroupRecord)this.SelectedItem;
                //return ((GroupRecord)this.SelectedItem).Name;
            }
            set
            {
                //kod z MS - zakomentowałem. Tutaj nawet nigdy nie wchodzi
                //if (value is String)
                //{
                //    try
                //    {
                //        // This will throw an exception of the string is  
                //        // null, empty, or not in the format of a date. 
                //        //this.Value = DateTime.Parse((String)value);
                //        SelectedText = "ABC";
                //    }
                //    catch
                //    {
                //        // In the case of an exception, just use the  
                //        // default value so we're not left with a null 
                //        // value. 
                        
                //    }
                //}
            }
        }

        // Implements the  
        // IDataGridViewEditingControl.GetEditingControlFormattedValue method. 
        public object GetEditingControlFormattedValue(
            DataGridViewDataErrorContexts context)
        {
            return EditingControlFormattedValue;
        }

        // Implements the  
        // IDataGridViewEditingControl.ApplyCellStyleToEditingControl method. 
        public void ApplyCellStyleToEditingControl(
            DataGridViewCellStyle dataGridViewCellStyle)
        {
            this.Font = dataGridViewCellStyle.Font;
        }

        // Implements the IDataGridViewEditingControl.EditingControlRowIndex  
        // property. 
        public int EditingControlRowIndex
        {
            get
            {
                return rowIndex;
            }
            set
            {
                rowIndex = value;
            }
        }

        // Implements the IDataGridViewEditingControl.EditingControlWantsInputKey  
        // method. 
        public bool EditingControlWantsInputKey(
            Keys key, bool dataGridViewWantsInputKey)
        {
            // Let the DateTimePicker handle the keys listed. 
            switch (key & Keys.KeyCode)
            {
                case Keys.Left:
                case Keys.Up:
                case Keys.Down:
                case Keys.Right:
                case Keys.Home:
                case Keys.End:
                case Keys.PageDown:
                case Keys.PageUp:
                    return true;
                default:
                    return !dataGridViewWantsInputKey;
            }
        }


        // Implements the IDataGridViewEditingControl 
        // .RepositionEditingControlOnValueChange property. 
        public bool RepositionEditingControlOnValueChange
        {
            get
            {
                return false;
            }
        }

        // Implements the IDataGridViewEditingControl 
        // .EditingControlDataGridView property. 
        public DataGridView EditingControlDataGridView
        {
            get
            {
                return dataGridView;
            }
            set
            {
                dataGridView = value;
            }
        }

        // Implements the IDataGridViewEditingControl 
        // .EditingControlValueChanged property. 
        public bool EditingControlValueChanged
        {
            get
            {
                return valueChanged;
            }
            set
            {
                valueChanged = value;
            }
        }

        // Implements the IDataGridViewEditingControl 
        // .EditingPanelCursor property. 
        public Cursor EditingPanelCursor
        {
            get
            {
                return base.Cursor;
            }
        }



        protected override void OnSelectedIndexChanged(EventArgs e)
        {
            base.OnSelectedIndexChanged(e);
            valueChanged = true;
            this.EditingControlDataGridView.NotifyCurrentCellDirty(true);            
        }
        
    }

I wszystko prawie działa. Na początku jest w komórce jakaś tam wartość, przechodzę w tryb edycji, pojawia się Combo, które jest odpowiednio wypełnione danymi. Jak wybieram jakiś element, element pokazuje się w Combo jako selected. Dopiero jak opuszczam komórkę, pojawia się wyżej wspomniany błąd. Nie mam pojęcia, jak zrobić to dobrze.

GroupRecord to po prostu klasa z kilkoma polami i metodą ToString().

[EDIT]
OK, wreszcie się udało! Rozwiązaniem jest:

  1. W MultiColComboEditingControl.EditingControlFormattedValue() zwrócić stringa, który będzie miał wszystkie pola w sobie (np.: "0|1|ABC|True")
  2. Stworzyć klasę dziedziczącą po TypeConverter
  3. Odpowiednio oprogramować klasę z pkt. 2. Mając wszystkie pola w stringu, można zwrócić odpowiedni obiekt, który będzie wartością komórki.