Databinding DataGridView to business object

T

t.mall10

Hi,

I'm attempting to code my own data access layer class; it's been about
a month of coding, following examples, searching Wikipedia and UseNet,
and my efforts have met with some success. Right now I'm implementing
IList, but I may change it to a derived class depending on what I can
do with certain implementations regarding the DataGridView.

In addition to IList, is there another interface that will enable the
DataGridView (DGV) to display the empty datarow at the bottom of the
grid? This may have been covered in another post, but from what I can
tell, the DGV binds to a business through a BindingSource - but is
that the only place that one has the ability to manipulate the DGV to
display the blank data entry row?

Any help regarding this would greatly be appreciated; like I
mentioned, I have about a month's worth of work vested in learning and
coding, and it's no big deal to re-vamp it to accomodate databinding
to form data (I read that in order for the grids to use objects for
data, they needed to implement IList, and that's what I did, not
realizing that that was just the tip of the iceberg).

Regards,

TMall
 
M

Morten Wennevik [C# MVP]

Hi TMall,

If you have a custom list, this list needs to implement IBindingList. As
for displaying business objects in a DataGridView you typically create a
BindingList<MyBusinessClass> and use that as a DataSource, no further action
is needed. However, your business object HAS TO have an empty constructor so
if you overloaded the constructor you need to add the empty one as well.
 
T

t.mall10

Hi Morten,

Thank-you for the reply; I was going to add this code before, and then
saw your reply. It's code I downloaded from a URL referenced in MSDN,
and as you'll see, the code does implement IBindingList, but the
constructor is completely empty. It sets a private type field that's
later used in the IBindingList.AddNew() implemented function:

public class MyCollection : ArrayList, IBindingList, ITypedList
{
private Type finalType = typeof(MyData);

public MyCollection() { }

bool IBindingList.AllowNew
{
get { return true ; }
}
object IBindingList.AddNew()
{
return finalType.GetConstructor(new Type[]{}).Invoke(null);
}
// Additional implementation of IBindingList
}

public class FakeData
{
private FakeData(){}
public static MyCollection GetData()
{
MyCollection collection = new MyCollection();
for (int i = 0; i < 10; i++)
{
MyData ii = new MyData();
ii.ID = i;
ii.FirstName = "aaa" + i.ToString();
ii.LastName = "bbb" + i.ToString();
collection.Add(ii);
}
return collection;
}
}

public class MyData
{
private int id = 0;
private string firstName = null;
private string lastName = null;

public MyData() {}
public int ID
{
get{ return id; }
set{ id = value; }
}
public string FirstName
{
get{ return firstName; }
set{ firstName = value; }
}
public string LastName
{
get{ return lastName; }
set{ lastName = value; }
}
}

public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.DataGrid dataGrid1;
private DataGridView dataGrid1;
private DataGridView dataGrid2;

BindingList<MyData> arrList2 = new BindingList<MyData>();
MyData myData1 = new MyData();

public Form1()
{
InitializeComponent();
myData1.ID = 1;
myData1.FirstName = "ccc";
myData1.LastName = "cccc";
arrList2.Add(myData1);

dataGrid1.DataSource = FakeData.GetData();
dataGrid2.DataSource = arrList2;
}
}

Even though MyCollection implements IBindingList, the
IBindingList.AddNew() never gets called because dataGrid1 doesn't show
the new empty row, while dataGrid2 does.

MyCollection appears to also implement ITypedList, although I haven't
made heads or tails of what's all involved there yet.

So is dataGrid1 basically just binding to an ArrayList here?
 
M

Marc Gravell

Your AddNew has *created* a new object, but it hasn't *added* it.

object obj = Activator.CreateInstance(finalType);
Add(obj);
return obj;

Any better?

Out of idle curiosity, why not use generics (with the new()
constraint)? Or the existing List<T> / BindingList<T>? Any huge issue
you are trying to avoid?

Marc
 
T

t.mall10

For info, the following has some examples of this (look at figure
5/6); OK it is in VB, but we'll forgive it...http://msdn.microsoft.com/msdnmag/issues/05/08/CollectionsandDataBind...

Marc

Thanks for the URL reference - turns out that the implemented
IBindingList property SupportsChangeNotification was set to "false" in
MyCollection; changing that to "true" allowed the grid to show the new
row, but now an infinite loop error is popping up, so it's time for
some more debugging, but at least the new row is visible now.

I remember seeing that that the AllowNew property had to be set to
true, but didn't make the connection that this other property also had
to be true.

In answer to your other post, I actually am using List<T> in the base
class of this data access layer, but I want to add databinding, and
that's where I wasn't sure to start over and derive from
BindingList<T>, or to keep going in the same vein of things and tack
on IBindingList, and other interfaces if/when necessary.

Thanks again for all the replies, TMall
 
T

t.mall10

Your AddNew has *created* a new object, but it hasn't *added* it.

object obj = Activator.CreateInstance(finalType);
Add(obj);
return obj;

Any better?

Out of idle curiosity, why not use generics (with the new()
constraint)? Or the existing List<T> / BindingList<T>? Any huge issue
you are trying to avoid?

Marc

BTW, you were absolutely right about adding the object to the list; it
solved the infinite error I was getting. Thanks again!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top