/// <summary>
 /// Raises the CellFilling event.
 /// </summary>
 /// <param name="e">A DataGridViewControllerCellEventArgs object.</param>
 protected virtual void OnCellFilling(DataGridViewControllerCellEventArgs <T> e)
 {
     if (this.CellFilling != null)
     {
         this.CellFilling(this, e);
     }
 }
        /// <summary>
        /// The method used to handle the PropertyChanged event of a data object.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected virtual void OnObjectPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            T      info         = (T)sender;
            string propertyName = e.PropertyName;

            if (string.IsNullOrWhiteSpace(propertyName))
            {
                this.Update(info);
            }
            else
            {
                DataGridViewRow row = (from r in this.DataGridView.Rows.Cast <DataGridViewRow>()
                                       where object.Equals(r.Tag, info)
                                       select r).FirstOrDefault();
                PropertyInfo property = (from p in this.m_properties
                                         where p.Name.Equals(propertyName)
                                         select p).FirstOrDefault();
                if (row != null && property != null)
                {
                    this.m_isFillingCell = true;
                    DataGridViewCell cell = row.Cells[propertyName];
                    DataGridViewControllerCellEventArgs <T> cellEvent = new DataGridViewControllerCellEventArgs <T>(cell, info, propertyName, property.GetValue(info, null));
                    this.OnCellFilling(cellEvent);
                    cell.Value           = cellEvent.Value;
                    this.m_isFillingCell = false;
                }
            }
        }
        /// <summary>
        /// Initialize a new instance of DataGridViewEditableController.
        /// </summary>
        /// <param name="dataGridView">A DataGridView.</param>
        /// <param name="isAutomaticUpdateView">Whether automatic update this DataGridView when the underlying object have changed.</param>
        /// <param name="isAutomaticUpdateDataSource">Whether automatic update data source when the value of cell has changed.</param>
        /// <exception cref="System.ArgumentException"><paramref name="dataGridView"/> is null.</exception>
        public DataGridViewEditableController(DataGridView dataGridView, bool isAutomaticUpdateView, bool isAutomaticUpdateDataSource)
            : base(dataGridView, isAutomaticUpdateView)
        {
            this.DataGridView.ReadOnly = false;
            if (this.IsAutomaticUpdateDataSource = isAutomaticUpdateDataSource)
            {
                this.DataGridView.CellValueChanged += delegate(object sender, DataGridViewCellEventArgs e) {
                    if (e.RowIndex < 0 || e.ColumnIndex < 0 || this.m_isFillingCell)
                    {
                        return;
                    }

                    DataGridViewRow    row      = this.DataGridView.Rows[e.RowIndex];
                    DataGridViewColumn column   = this.DataGridView.Columns[e.ColumnIndex];
                    PropertyInfo       property = (from p in this.m_properties
                                                   where p.Name.Equals(column.Name)
                                                   select p).FirstOrDefault();
                    if (row.Tag is T && property != null)
                    {
                        T info = (T)row.Tag;
                        DataGridViewCell cell = row.Cells[property.Name];
                        DataGridViewControllerCellEventArgs <T> cellEvent = new DataGridViewControllerCellEventArgs <T>(cell, info, property.Name, cell.Value);
                        this.OnCellPicking(cellEvent);
                        property.SetValue(info, cellEvent.Value, null);
                    }
                };
            }
        }
        /// <summary>
        /// Initialize the associated object by the specified row.
        /// </summary>
        /// <param name="row">A DataGridViewRow.</param>
        /// <returns>The associated object.</returns>
        protected virtual T FromRow(DataGridViewRow row)
        {
            T info = (T)row.Tag;

            DataGridViewCell           cell           = null;
            DataGridViewCellCollection cells          = row.Cells;
            DataGridViewControllerCellEventArgs <T> e = null;

            foreach (PropertyInfo property in this.m_properties)
            {
                if ((cell = cells[property.Name]).ReadOnly && !this.IsPickReadOnlyValue)
                {
                    continue;
                }

                this.OnCellPicking(e = new DataGridViewControllerCellEventArgs <T>(cell, info, property.Name, cell.Value));
                property.SetValue(info, e.Value, null);
            }

            return(info);
        }
        /// <summary>
        /// Fill the specified row.
        /// </summary>
        /// <param name="info">The data.</param>
        /// <param name="row">The row.</param>
        protected void FillRow(T info, DataGridViewRow row)
        {
            DataGridViewCellCollection cells          = row.Cells;
            DataGridViewControllerCellEventArgs <T> e = null;

            row.Tag = info;
            this.OnPreFillRow(new DataGridViewControllerRowEventArgs <T>(row, info));
            this.m_isFillingCell = true;
            DataGridViewCell cell = null;

            foreach (PropertyInfo property in this.m_properties)
            {
                this.OnCellFilling(e = new DataGridViewControllerCellEventArgs <T>(cell = cells[property.Name], info, property.Name, property.GetValue(info, null)));

                cell.Value = e.Value;
            }
            this.m_isFillingCell = false;
            this.OnPostFillRow(new DataGridViewControllerRowEventArgs <T>(row, info));

            if (this.IsAutomaticUpdateView)
            {
                ((INotifyPropertyChanged)info).PropertyChanged += new PropertyChangedEventHandler(this.OnObjectPropertyChanged);
            }
        }