Apr 29, 2013

Object cloning

Object cloning

How to perform shallow copy of complex type?
http://msdn.microsoft.com/en-us/library/system.object.memberwiseclone.aspx

Apr 11, 2013

Windows forms data binding tutorial

http://www.codeproject.com/Articles/24656/A-Detailed-Data-Binding-Tutorial

Windows Forms / DataGridView / End row edit upon value change

I've created DataGridView in windows forms app with check box and text box.
When I click on checkbox I want some action executed - another button clicked.
I require that editing of row in which click occurred finishes its editing session  so that underlying BindingSource is updated to latest change.
So if my click unchecked or checked given field I wish to have it in my underlying DataTable so some other logic can immediately use it.
This proved to bit a bit tricky.
Note that in this scenario Checkboxcolumn in question is expected exactly at columnindex 0.


public EditorGUI()
        {
            InitializeComponent();

gridTables.CellContentClick += ( o, e ) =>
{
if ( e.ColumnIndex > 0 ) return;
gridTables.CommitEdit( DataGridViewDataErrorContexts.Commit );
};
gridTables.CellValueChanged += ( o, e ) => btnQuicksrch_Click( this, null );
        }

Here is second scenario. There are two grids - gridColumns & gridSelFields.
They both reflect same data but filter it in different way.
When user clicks and checks/unchecks checkbox in gridColumns second grid should immediately get  updated since they reflect same data.

private delegate void AfterDirtyStateChangedDelegate();
private void  MyForm()
...


       gridColumns.CurrentCellDirtyStateChanged += gridColumns_CurrentCellDirtyStateChanged;
       gridColumns.CellValueChanged += gridColumns_CellValueChanged;


First event to detect click and SPACE on checkbox is CurrentCellDirtyStateChanged:


void gridColumns_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            if ((sender as DataGridView).IsCurrentCellDirty)
            {
                BeginInvoke(new AfterDirtyStateChangedDelegate(DirtyStateChanged));
            }
        }


If cell "dirty" (change occured) async invoke committing of changes to underlying data list.


private void DirtyStateChanged()
        {
            Debug.Print("DirtyStateChanged()");
            gridColumns.CommitEdit(DataGridViewDataErrorContexts.Commit);
            gridColumns.EndEdit();
            bindSrcColumns.EndEdit();
        }


In DirtyStateChanged all three commits must execute to make sure our change is commited.
Above committing will finally raise CellValueChanged event.


void gridColumns_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {        
            UpdateIsSelectedToSelFields(e);
            GridColumnsFieldSelection(e.RowIndex);
        }

Only at this point we are sure that binding source of Columns is updated so we can use it.

...

var selField_SelRow_IsSelected = (bindSrcSelFields.DataSource as DataTable).Rows.Find(col_SelRow[EDITORCOLUMN_FIELDNAME])[EDITORCOLUMN_ISSELECTED];          
            (bindSrcSelFields.DataSource as DataTable).Rows.Find(col_SelRow[EDITORCOLUMN_FIELDNAME])[EDITORCOLUMN_ISSELECTED] = !Convert.ToBoolean(selField_SelRow_IsSelected);

...

Watch it ! In above this DOES NOT work :

selField_SelRow_IsSelected = !Convert.ToBoolean(selField_SelRow_IsSelected);

There is at the moment still active bug with DataGridView. When you press SPACE on checkbox field and handle CellContentClick you get exception.
Here it is explained:

http://connect.microsoft.com/VisualStudio/feedback/details/780347/nullreferenceexception-in-notifymassclient-after-checking-unchecking-a-checkbox-in-datagridview-with-spacebar#details

That's where I got above delegate thing.

There is only one misbehavior with above scenario. When you use SPACE key you cannot check and immediately uncheck same record. After first SPACE leave current row and come back.

This is due to fact that after first SPACE we ended EditMode and only by leaving and getting focus again will enter Edit mode again.

Furthermore consider  DataGridView.EditMode

http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&l=EN-US&k=k(System.Windows.Forms.DataGridView.CellContentClick);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5);k(DevLang-csharp)&rd=true

Apr 8, 2013

Custom type comparing

You have custom type EditorColumn:

public class EditorColumns
{

        public bool IsSelected { get; set; }
        public string FieldName { get; set; }
        public int? OrderId { get; set; }

}

I want to do lambda expression that checks whether MyCollection that is collection of EditorColumn's contains seleted MyEditorColumn of type EditorColumns.
LINQ lambda for this is:   Contains

What is equality criteria for this?
How do you define that MyEditiorColumn has its matches in collection?
Since this is not value type by default .NET will use type reference.

Let's say that two EditorColumn's are equal if their fieldname's exactly match.

This has to be  designed into our EditorColumn like this:


internal class FieldNameComparer : IEqualityComparer<EditorColumn>
        {
            public bool Equals(EditorColumn x, EditorColumn y)
            {
                return x.FieldName.ToLowerInvariant() == y.FieldName.ToLowerInvariant();
            }

            public int GetHashCode(EditorColumn obj)
            {
                return 0;
            }
        }

There is no rule but I suggest that above class is placed inside EditorColumn type def.

Now we can write something like this:

var optionalDefs = defaultColumns.Where(dc => !userDefEdCols.Contains<EditorColumn>(dc,new EditorColumn.FieldNameComparer())).ToList<EditorColumn>();


Here is some more info:

http://www.code-magazine.com/Article.aspx?quickid=100083