Bind a DataGridViewComboBoxColumn to a DataGridView column

601 views Asked by At

I am struggling a few days with this problem and I can not fix it by myself.

I have 3 datagridviews

  • Alphabet
  • State
  • Transition

Alphabet contains one column with only chars for example 'a', 'b' and 'c'

State contains three columns: 'Name'; 'is start state' and 'is end state'. The first is just string column. The other two are checkbox columns.

Transition contains three columns. From (combobox), To (combobox), Symbol (combobox)

My goal is to use the data that the user entered in the state & alphabet tables for my comboboxes.

For example: The user entered in the alphabet the folowing data: 'a' and 'b' The user entered in the state the folowing data:

  • LR_0; is start state; is no end state
  • LR_1; is no start state; is no end state
  • LR_2; is no start state; is end state

When the user want to fill the transitions they can choose for the column 'from' and 'to' de folowing options: LR_0; LR_1 or LR_2. For symbol they can use 'a' or 'b'.

Now comes the tricky part. When the user rename LR_0 to LR_3 the comboboxes also need to update. And when the user removes the LR_0 row the rows in transitions which contains LR_0 also needs to remove.

I've used a lot of posibilities but none is working 100% correct.

Option 1 Use a intern list and bind bind that to the comboboxes and everytime there is a row added I also add it to the list. When there is a row removed I remove it also from the list and remove every row in transitions which contains that value.

Problems: It is sometimes unknown when there is a value changed and when the value is added. It is also difficult to change the value in the comboboxes

Option 2 Use a iList interface and make a enumerator with the folowing datagridview information .Rows.Count = length and .Rows[0].Cells[0].Value = value.

Problems: When there is information changed. The combobox isn't updated

Option 3 Use a iBindingList interface with the same setup as option 2. This is something that is almost correct. The list is changed when I remove something or add something. The only problem is that the comboboxes don't change its value when that specific row is changed.

I have at the moment this. DataTableColumnSource

using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace Gui
{
    public class DataTableColumnSource<T> : IBindingList
    {
        public event ListChangedEventHandler ListChanged;
        public DataGridView dataTable { get; set; }
        public int column { get; set; }


        public DataTableColumnSource(ref DataGridView dataTable, int column)
        {
            this.dataTable = dataTable;
            this.column = column;
        }

        public void PosibleChange(ListChangedType type, int index)
        {
            if (ListChanged != null)
            {
                ListChanged(this, new ListChangedEventArgs(type, index));

            }
        }

        public void AddIndex(PropertyDescriptor property)
        {
            throw new NotImplementedException();
        }

        public object AddNew()
        {
            return new Comboboxitem<T>(default(T), -1); ;
        }

        public bool AllowEdit
        {
            get { throw new NotImplementedException(); }
        }

        public bool AllowNew
        {
            get { return true; }
        }

        public bool AllowRemove
        {
            get { throw new NotImplementedException(); }
        }

        public void ApplySort(PropertyDescriptor property, ListSortDirection direction)
        {
            throw new NotImplementedException();
        }

        public int Find(PropertyDescriptor property, object key)
        {
            throw new NotImplementedException();
        }

        public bool IsSorted
        {
            get { throw new NotImplementedException(); }
        }

        public void RemoveIndex(PropertyDescriptor property)
        {
            throw new NotImplementedException();
        }

        public void RemoveSort()
        {
            throw new NotImplementedException();
        }

        public ListSortDirection SortDirection
        {
            get { throw new NotImplementedException(); }
        }

        public PropertyDescriptor SortProperty
        {
            get { throw new NotImplementedException(); }
        }

        public bool SupportsChangeNotification
        {
            get { return true; }
        }

        public bool SupportsSearching
        {
            get { return false; }
        }

        public bool SupportsSorting
        {
            get { return false; }
        }

        public int Add(object value)
        {
            throw new NotImplementedException();
        }

        public void Clear()
        {
            throw new NotImplementedException();
        }

        public bool Contains(object value)
        {
            throw new NotImplementedException();
        }

        public int IndexOf(object value)
        {
            throw new NotImplementedException();
        }

        public void Insert(int index, object value)
        {
            throw new NotImplementedException();
        }

        public bool IsFixedSize
        {
            get { throw new NotImplementedException(); }
        }

        public bool IsReadOnly
        {
            get { throw new NotImplementedException(); }
        }

        public void Remove(object value)
        {
            throw new NotImplementedException();
        }

        public void RemoveAt(int index)
        {
            throw new NotImplementedException();
        }

        public object this[int index]
        {
            get
            {
                if (this.dataTable.Rows[index].Cells[this.column].Value == null)
                    return null;

                T w =(T) Convert.ChangeType(this.dataTable.Rows[index].Cells[this.column].Value, typeof(T));
                return w;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public void CopyTo(Array array, int index)
        {
            throw new NotImplementedException();
        }

        public int Count
        {
            get
            {
                return this.dataTable.Rows.Count -1;
            }
        }

        public bool IsSynchronized
        {
            get { throw new NotImplementedException(); }
        }

        public object SyncRoot
        {
            get { throw new NotImplementedException(); }
        }

        public System.Collections.IEnumerator GetEnumerator()
        {
            int c = Count;
            for (int i = 0; i < c; i++)
                yield return this[i];
        }
    }
}

GUI

public partial class FrmNDFA : Form
    {

        DataTableColumnSource<char> alphabetSource;
        DataTableColumnSource<string> stateSource;
        int lastDeletedIndex;

        public FrmNDFA()
        {
            InitializeComponent();

            alphabetSource = new DataTableColumnSource<char>(ref this.dgvAlphabet, 0);
            stateSource = new DataTableColumnSource<string>(ref this.dgvStates, 0);

            DataGridViewComboBoxColumn column = (DataGridViewComboBoxColumn)this.dgvTransitions.Columns[0];
            BindingSource clm1BS = new BindingSource();
            clm1BS.DataSource = stateSource;
            column.DataSource = clm1BS;
            column.ValueType = typeof(string);

            column = (DataGridViewComboBoxColumn)this.dgvTransitions.Columns[1];
            BindingSource clm2BS = new BindingSource();
            clm2BS.DataSource = stateSource;
            column.DataSource = clm2BS;
            column.ValueType = typeof(string);

            column = (DataGridViewComboBoxColumn)this.dgvTransitions.Columns[2];
            BindingSource clm3BS = new BindingSource();
            clm3BS.DataSource = alphabetSource;
            column.DataSource = clm3BS;
            column.ValueType = typeof(char);

        }

        private void dgvAlphabet_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
        {
            lastDeletedIndex = e.Row.Index;
        }

        private void dgvAlphabet_UserDeletedRow(object sender, DataGridViewRowEventArgs e)
        {
            DataGridViewRow row = e.Row;
            string value = (row.Cells[0].Value != null)? row.Cells[0].Value.ToString() : "";

            alphabetSource.PosibleChange(ListChangedType.ItemDeleted, lastDeletedIndex);

            List<DataGridViewRow> removeRows = new List<DataGridViewRow>();
            //Update transitions
            foreach (DataGridViewRow dataRow in this.dgvTransitions.Rows)
            {
                if (dataRow.Cells[2].Value != null && dataRow.Cells[2].Value.ToString().Equals(value))
                    removeRows.Add(dataRow);
            }


            foreach(DataGridViewRow dataRow in removeRows)
            {
                this.dgvTransitions.Rows.Remove(dataRow);
            }
        }

        private void dgvAlphabet_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            if(this.dgvAlphabet.Rows[e.RowIndex].IsNewRow)
                alphabetSource.PosibleChange(ListChangedType.ItemAdded, e.RowIndex);
            else
                alphabetSource.PosibleChange(ListChangedType.ItemChanged, e.RowIndex);

        }

        private void dgvAlphabet_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
        {
            e.Cancel = e.FormattedValue != null && e.FormattedValue.ToString().Length > 1;
        }

        private void dgvStates_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
        {
            lastDeletedIndex = e.Row.Index;
        }

        private void dgvStates_UserDeletedRow(object sender, DataGridViewRowEventArgs e)
        {
            DataGridViewRow row = e.Row;
            string value = (row.Cells[0].Value != null) ? row.Cells[0].Value.ToString() : "";
            stateSource.PosibleChange(ListChangedType.ItemDeleted, this.dgvStates.Rows.IndexOf(e.Row));

            List<DataGridViewRow> removeRows = new List<DataGridViewRow>();
            //Update transitions
            foreach (DataGridViewRow dataRow in this.dgvTransitions.Rows)
            {
                if (dataRow.Cells[0].Value != null && dataRow.Cells[0].Value.Equals(value))
                    removeRows.Add(dataRow);
                else if (dataRow.Cells[1].Value != null && dataRow.Cells[1].Value.Equals(value))
                    removeRows.Add(dataRow);
            }

            foreach(DataGridViewRow dataRow in removeRows)
            {
                this.dgvTransitions.Rows.Remove(dataRow);
            }
        }

        private void dgvStates_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            if (e.ColumnIndex != 0)
                return;
            stateSource.PosibleChange(ListChangedType.ItemChanged, e.RowIndex);

        }
    }
0

There are 0 answers