Edit this page

Binding to a Collection of Interfaces

There may be a case where you want to bind RadGridView to a collection of interfaces in order to be as abstract as possible or due to other reasons. RadGridView does not support this out of the box since when a new item is added its parameterless constructor is being invoked and interfaces cannot be created in such a way. The solution is to override the AddNew method of the GridViewListSource.

First, we will need to create a custom GridViewListSource:

public class MyGrid : RadGridView
{
    protected override RadGridViewElement CreateGridViewElement()
    {
        return new MyGridViewElement();
    }
}
public class MyGridViewElement : RadGridViewElement
{
    protected override MasterGridViewTemplate CreateTemplate()
    {
        return new MyMasterGridViewTemplate();
    }
    protected override Type ThemeEffectiveType
    {
        get
        {
            return typeof(RadGridViewElement);
        }
    }
}
public class MyMasterGridViewTemplate : MasterGridViewTemplate
{
    protected override GridViewListSource CreateListSource()
    {
        return new MyGridViewListSource(this);
    }
}
public class MyGridViewListSource : GridViewListSource
{
    private GridViewTemplate template;
    public MyGridViewListSource(GridViewTemplate template)
        : base(template)
    {
        this.template = template;
    }
    public override GridViewRowInfo AddNew()
    {
        GridObj gridObj = new GridObj();
        IList list = (this as ICurrencyManagerProvider).CurrencyManager.List;
        list.Add(gridObj);
        IDataItem dataItem = (this.template as IDataItemSource).NewItem();
        if (this.IsDataBound)
        {
            this.InitializeBoundRow((GridViewRowInfo)dataItem, gridObj);
        }
        return dataItem as GridViewRowInfo;
    }
}

Public Class MyGrid
    Inherits RadGridView
    Protected Overrides Function CreateGridViewElement() As RadGridViewElement
        Return New MyGridViewElement()
    End Function
End Class
Public Class MyGridViewElement
    Inherits RadGridViewElement
    Protected Overrides Function CreateTemplate() As MasterGridViewTemplate
        Return New MyMasterGridViewTemplate()
    End Function
    Protected Overrides ReadOnly Property ThemeEffectiveType() As Type
        Get
            Return GetType(RadGridViewElement)
        End Get
    End Property
End Class
Public Class MyMasterGridViewTemplate
    Inherits MasterGridViewTemplate
    Protected Overrides Function CreateListSource() As GridViewListSource
        Return New MyGridViewListSource(Me)
    End Function
End Class
Public Class MyGridViewListSource
    Inherits GridViewListSource
    Private template As GridViewTemplate
    Public Sub New(template As GridViewTemplate)
        MyBase.New(template)
        Me.template = template
    End Sub
    Public Overrides Function AddNew() As GridViewRowInfo
        Dim gridObj As New GridObj()
        Dim list As IList = TryCast(Me, ICurrencyManagerProvider).CurrencyManager.List
        list.Add(gridObj)
        Dim dataItem As IDataItem = TryCast(Me.template, IDataItemSource).NewItem()
        If Me.IsDataBound Then
            Me.InitializeBoundRow(DirectCast(dataItem, GridViewRowInfo), gridObj)
        End If
        Return TryCast(dataItem, GridViewRowInfo)
    End Function
End Class

The GridObj type is a type, which implements the interface, which you have bound your RadGridView. Consider the following example:

public BindingToCollectionOfInterfaces()
{
    InitializeComponent();
    MyGrid grid = new MyGrid();
    this.Controls.Add(grid);
    grid.Dock = DockStyle.Fill;
    IEnumerable<IGridObj> dataSource = new BindingList<IGridObj>();
    grid.DataSource = dataSource;
    grid.AllowAddNewRow = true;
}
public interface IGridObj
{
    int Id { get; set; }
    string Name { get; set; }
}
public class GridObj : IGridObj
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string RandomString { get; set; }
}

Public Sub New()
    InitializeComponent()
    Dim grid As New MyGrid()
    Me.Controls.Add(grid)
    grid.Dock = DockStyle.Fill
    Dim dataSource As IEnumerable(Of IGridObj) = New BindingList(Of IGridObj)()
    grid.DataSource = dataSource
    grid.AllowAddNewRow = True
End Sub
Public Interface IGridObj
    Property Id() As Integer
    Property Name() As String
End Interface
Public Class GridObj
    Implements IGridObj
    Public Property Id() As Integer Implements BindingToCollectionOfInterfaces.IGridObj.Id
        Get
            Return m_Id
        End Get
        Set(value As Integer)
            m_Id = value
        End Set
    End Property
    Private m_Id As Integer
    Public Property Name() As String Implements BindingToCollectionOfInterfaces.IGridObj.Name
        Get
            Return m_Name
        End Get
        Set(value As String)
            m_Name = value
        End Set
    End Property
    Private m_Name As String
    Public Property RandomString() As String
        Get
            Return m_RandomString
        End Get
        Set(value As String)
            m_RandomString = value
        End Set
    End Property
    Private m_RandomString As String
End Class

You will notice that we are creating a BindingList of IGridObject, because the new items are manually added and this way the grid will be notified for the new objects.

See Also