I'm looking to resolve databinding to a Winforms datagridview using C# & .Net3.5. It's a bit involved and encompasses a few classes which I will provide code.
I have have an Interface defined as such:
public interface MyElement : IEditableObject {
string Name { get; set; }
string Description { get; set; }
}
I next have an abstaract class that inherits from MyElement defined as such:
abstract public class MyElementAdapter : MyElement {
private string myName;
private string myDescription;
private ModelElement myParent;
public MyElementAdapter(MyElement parent) {
myName = "New_Element";
myDescription = string.Empty;
}
virtual public string Name {
get { return myName; }
set { myName = value; }
}
virtual public string Description {
get { return myDescription; }
set { myDescription = value; }
}
public MyElement Parent {
get { return myParent; }
set { myParent = value; }
}
public void BeginEdit() {
// code to begin edit
}
public void CancelEdit() {
// code to cancel edit
}
public void EndEdit() {
// code to end edit
}
}
There is a generic list of the interface type that is defined as such - its very basic and just retains a generic list of MyElements:
public class MyElementList : List<MyElement> {
public MyElementList() {
}
}
There is an inherited class named MyField which derives from MyElementAdapter defined as such:
public class MyField : MyElementAdapter {
private int size;
public MyField(MyElement parent) : base(parent) {
size = 1;
}
public string MyFieldName {
get { return this.Name; }
set { this.Name = value;}
}
public string MyFieldDescription {
get { return this.Description; }
set { this.Description = value;}
}
public int Size {
get { return size; }
set { size = value; }
}
}
There is a class which uses MyElementList where MyField is the List type:
public class MyRecordOfFields : MyElementAdapter {
private MyElementList myMembers;
public MyRecordOfFields(MyElement parent) : base(parent) {
myMembers = new MyElementList();
}
public MyElementList MyMembers {
get { return myMembers; }
set { myMembers = value; }
}
}
And finally, there is a form that I am using to edit an object of type MyRecordOfFields.
public class Form1 : Form {
private BindingSource bindingSource1;
private MyRecordOfFields myLocalFields;
private DataGridView dgv;
private Form1_Load() {
myLocalFields = new MyRecordOfFields(null);
MyField field1 = new MyField(null);
field1.MyFieldName = "Field_1";
field1.MyFieldDescription = "Description1";
field1.Size = 3;
myLocalFields.MyMembers.Add(field1);
MyField field2 = new MyField(null);
field2.MyFieldName = "Field_2";
field2.MyFieldDescription = "Description2";
field2.Size = 3;
myLocalFields.MyMembers.Add(field2);
MyField field3 = new MyField(null);
field3.MyFieldName = "Field_3";
field3.MyFieldDescription = "Description3";
field3.Size = 3;
myLocalFields.MyMembers.Add(field3);
bindingSource1 = new BindingSource();
bindingSource1.AllowNew = true;
dgv.AutoGenerateColumns = false;
int colIndex = dgv.Columns.Add("MyFieldName", "MyFieldName");
dgv.Columns[colIndex].DataPropertyName = "MyFieldName";
colIndex = dgv.Columns.Add("MyFieldDescription", "MyFieldDescription");
dgv.Columns[colIndex].DataPropertyName = "MyFieldDescription";
colIndex = dgv.Columns.Add("Size", "Size");
dgv.Columns[colIndex].DataPropertyName = "Size";
dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
dgv.AutoResizeColumns();
bindingSource1.DataSource = myLocalFields.MyMembers;
dgv.DataSource = bindingSource1;
dgv.Invalidate();
}
}
When this form is loaded, everything compiles and runs however when the form is displayed, the datagridview has 3 row but all blank. I am trying to directly set the datagridview's datasource to the MyElementList in the MyRecordOfFields class however nothing is displayed expect for the number of rows added to the list.
When I don't set the datagridview's datasource to the list, but add each element in that list in a loop, data is displayed as it should.
The following line:
bindingSource1.DataSource = myLocalFields.MyMembers;
Changed to a loop:
foreach (MyElement me in myLocalFields.MyMembers) {
// No casting needed due to inheritance
bindingSource1.Add(me);
}
And after I changed to a loop, I had to add event handlers for adding, deleting, and updating to the underlying data source which is myLocalFields (MyRecordOfFields.MyMembers).
Is there something I am missing or not doing correctly in my scenario?? I know it's a bit involved with the Interface & abstract classes, but I'm working from predefined implementations and so changing these underlying/basic classes is not an option. Thank you in advance.
- Lorentz
UPDATE: I've tried a few suggestion and to no avail nothing. So my question is this: Is it possible for me to expose the inherited properties (like I designed the datagridview [columns]) of MyField by setting the bindingSource1.DataSource to the MyElementLIst in MyRecordOfFields.MyMembers property??
This is where I need some guidance: MyElement is an interface; MyElementAdapter is an abstract derived from MyElement; MyElementList is a generic list of MyElement; and MyField is derived from MyElementAdapter. Adding MyElement or any derived class (ie MyField) to MyElementList works. Yet it is these derived classes' properties I want to expose in the UI (datagridview, controls, etc.).
UPDATE#2: Now that I have my datagridview bounded to my MyElementList everything is working fine. I am now working on adding/deleting/updating myLocalFields.MyMembers list. I've added a button with the following code:
private void AddItem_Click(object sender, EventArgs e) {
MyField field1 = new MyField(null);
field1.MyFieldName = "Field_" + myLocalFields.MyMembers.Count + 1;
field1.MyFieldDescription = "Description" + myLocalFields.MyMembers.Count + 1;
field1.Size = myLocalFields.MyMembers.Count + 1;
myLocalFields.MyMembers.Add(field1);
((BindingSource)dataGridView1.DataSource).ResetBindings(false);
}
When this method is done, I see that my underlying data (myLocalField.MyMembers) changes, but bindingSource1 and dataGridView1 do not. In the past, any updates to the underlying data was done to the underlying data as well as the bindingsource - I would like to make changes to the underlying data and have that propogate to the bindingsource/datagridview.
I figured the following would take care of any changes to the datagridview but it doesn not:
((BindingSource)dataGridView1.DataSource).ResetBindings(false);
Is there another method that I need to use in order for me to update the datagridview without adding additional datagridview events?