Jan Kinable

Hey there,

I've created a custom (generic) DataGridViewTextBoxColumn/Cell to be able to format the text differently from the normal view vs editmode. Everything works fine, but now I want to change the backcolor of the cell when there is no value.

So the next step, I thought so, was to subscribe to the DataGridView.CellFormatting event.

Every 'normal' cell enters the eventhandling except of the custom one.

Is there anything I skipped during development to enable the custom cell to hit the event

Note : I'm using an interface (ITextBoxGridEvents) to communicate with the hosted control.

Here is the code for the cell. Maybe the generic approach is the problem

Code Snippet

public class DataGridViewTextBaseColumn<T> : DataGridViewTextBoxColumn

where T : TextBoxBase, ITextBoxGridEvents

{

private T _control;

public DataGridViewTextBaseColumn(T controlTemplate)

{

_control = controlTemplate;

_control.IsInDataGrid = true;

this.CellTemplate = new DataGridViewTextBaseCell<T>();

//force the valuetype to be a string !!

this.ValueType = typeof(string);

}

//Disable the set of the valuetype

new public Type ValueType

{

get { return base.ValueType; }

set { /*do nothing */}

}

public override object Clone()

{

return new DataGridViewTextBaseColumn<T>(_control);

}

public T ControlTemplate

{

get { return _control; }

}

}

internal class DataGridViewTextBaseCell<T> : DataGridViewTextBoxCell

where T : TextBoxBase, ITextBoxGridEvents

{

public DataGridViewTextBaseCell()

{

}

public override Type EditType

{

get

{

return typeof(DataGridViewTextBaseEditingControlWrapper<T>);

}

}

public override Type ValueType

{

get

{

return typeof(string);

}

}

#region Private Methods

private void CopyDataGridViewEditValues(T original, DataGridViewTextBaseEditingControlWrapper<T> editingControl)

{

T wrappedControl = (T)editingControl.GetType().GetProperty("WrappedControl").GetValue(editingControl, null);

this.CopyValues(original, wrappedControl);

}

private void CopyValues(T source, T destination)

{

PropertyInfo[] props = source.GetType().GetProperties();

foreach (PropertyInfo prop in props)

{

DataGridViewEditingControlValueAttribute[] attrs = (DataGridViewEditingControlValueAttribute[])

prop.GetCustomAttributes(typeof(DataGridViewEditingControlValueAttribute), false);

if (attrs.Length > 0)

{

destination.GetType().GetProperty(prop.Name).SetValue(destination, prop.GetValue(source, null), null);

}

}

}

#endregion

protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, System.ComponentModel.TypeConverter valueTypeConverter, System.ComponentModel.TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)

{

if (value != null)

{

if (value == System.DBNull.Value)

{

return string.Empty;

}

else

{

T formattingControl = typeof(T).Assembly.CreateInstance(typeof(T).FullName) as T;

this.CopyValues(((DataGridViewTextBaseColumn<T>)this.OwningColumn).ControlTemplate, formattingControl);

formattingControl.Text = value.ToString();

//force the formatting

formattingControl.RaiseGotFocus();

formattingControl.RaiseLostFocus();

return formattingControl.Text;

}

}

return base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context);

}

public override object ParseFormattedValue(object formattedValue, DataGridViewCellStyle cellStyle, System.ComponentModel.TypeConverter formattedValueTypeConverter, System.ComponentModel.TypeConverter valueTypeConverter)

{

T formattingControl = typeof(T).Assembly.CreateInstance(typeof(T).FullName) as T;

this.CopyValues(((DataGridViewTextBaseColumn<T>)this.OwningColumn).ControlTemplate, formattingControl);

formattingControl.IsInDataGrid = true;

return ((ITextBoxGridEvents)formattingControl).ParseFormattedValue(formattedValue);

}

public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)

{

base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);

DataGridViewTextBaseEditingControlWrapper<T> editingControl = base.DataGridView.EditingControl as DataGridViewTextBaseEditingControlWrapper<T>;

//initialize the wrappercontrol if needed so

if (this.Value == null || this.Value.ToString().Length == 0)

editingControl.ReNew();

CopyDataGridViewEditValues(((DataGridViewTextBaseColumn<T>)this.OwningColumn).ControlTemplate, editingControl);

editingControl.LostFocus += new EventHandler(editingControl_LostFocus);

editingControl.WrappedControl.Text = initialFormattedValue as string;

editingControl.Text = editingControl.WrappedControl.Text;

}

void editingControl_LostFocus(object sender, EventArgs e)

{

if (IsInEditMode)

{

System.Diagnostics.Debug.WriteLine("Cell set value : '" + ((TextBoxBase)sender).Text + "'");

this.SetValue(this.RowIndex, ((TextBoxBase)sender).Text);

}
}

}

... and a Editing class (to much blabla to show here), since the editing part works fine.




Re: Windows Forms Data Controls and Databinding Custom DataGridViewTextBoxColumn doesn't cause DataGridView.CellFormatting event to fire

Jan Kinable

I noticed that this thread still was unfinished, so no time like now to close this !

Earlier I found the solution and it was that simple that I overlooked it.

During the ParseFormattedValue method I forgot to call the base method...

Code Block

object formatted = ((ITextBoxGridEvents)formattingControl).ParseFormattedValue(formattedValue);

return base.ParseFormattedValue(formatted, cellStyle, formattedValueTypeConverter, valueTypeConverter);

After this I could apply any formatting I like.