Adding derived classes to a Binding Source of a Da

2020-04-21 03:50发布

问题:

Using MVC Pattern in WinForms with C#

Three business object - an abstract LibraryItem Class ,a Book class and a journal class , both derives from LibraryItem

//LibraryItem Class
public abstract class LibraryItem
{
    public string Title { get; set; }

    private static int _nextCallNum = 1000;

    public int CallNum { get; private set; }

    public int NumCopies { get; set; }
}

//Journal Class
 public class Journal : LibraryItem
{
    public int Vol { get; set; }
}

//Book Class
 public class Book : LibraryItem
{
    public string Author { get; set; }
}


//LibraryController Class 
  public class LibrayController
{

    //a List that can hold both books and journals
    private List<LibraryItem> items;

     //adds a book object to items
     public void AddBookItem(string title, int numCopies , string author) {.....}

      //adds a journal object to items
     public void AddJournal(string title, int vol, int numCopies){}

      //returns a List contaning books and journals to the View
      public List<LibraryItem> GetAllItems()
    {
        return items;
    }
}   

In Win Forms , using a DataGridView to display list of LibraryItems

dataGridViewItems.DataSource = null;

booksbindingSource = new BindingSource();

 foreach (LibraryItem anitem in controller.GetAllItems())
        {

            LibraryItem aLibraryItem = (LibraryItem) anitem;

            booksbindingSource.Add(aLibraryItem);
        }

dataGridViewItems.DataSource = booksbindingSource;

When adding a book after journal, or a journal after book to the binding source, I get InvalidOperationException Objects added to a BindingSource's list must all be of the same type.

The description is self-explanatory. I need a way to display LibraryItems in a datagrid than can be both books and journals. I only need to display the base class properties(Title, CallNum and NumCopies of LibraryItem) in the datagrid.

回答1:

If the DataSource property of BindingSource has not already been set, then the first object added to the list defines the type for the list, and then all items that you want to add to the list, should be of the type of first object, because the internal list must contain homogeneous types as mentioned in documentations.

Instead of adding items to BindingSource using Add method, set its DataSource property to the list which you get from controller:

var bs = new BindingSource();
var list = controller.GetAllItems();
bs.DataSource = list;
this.dataGridView1.DataSource = bs;

Note

To solve the problem, its enough and recommended to use above method, but to see the affect of setting DataSource, you can set DataSource property to typeof(LibraryItem) and you will see it also works as expected:

bs.DataSource = typeof(LibraryItem);
foreach (var item in list)
{
    bs.Add(item);
}
this.dataGridView1.DataSource = bs;