New to Telerik UI for WinForms? Download free 30-day trial

Custom items

RadListView allows you to create and use your own custom visual items. This article demonstrates how to achieve it.

Custom items in ListView ViewType

This can be done by making use of the VisualItemCreating event. The following example demonstrates creating a visual item with two buttons in it.

Figure 1: Custom SimpleListViewVisualItem

WinForms RadListView Custom SimpleListViewVisualItem

First let's create a custom visual item by inheriting from the SimpleListViewVisualItem class:

Creating custom item


public class MyCustomVisualItem : SimpleListViewVisualItem
{
    private RadButtonElement buttonElement1;
    private RadButtonElement buttonElement2;
    private LightVisualElement contentElement;
    private StackLayoutPanel stackLayout;

    protected override void CreateChildElements()
    {
        base.CreateChildElements();

        this.stackLayout = new StackLayoutPanel();
        this.stackLayout.Orientation = Orientation.Horizontal;
        this.stackLayout.EqualChildrenWidth = true;
        this.stackLayout.ShouldHandleMouseInput = false;
        this.stackLayout.NotifyParentOnMouseInput = true;

        this.contentElement = new LightVisualElement();
        this.contentElement.StretchHorizontally = true;
        this.contentElement.MinSize = new Size(120, 0);
        this.contentElement.ShouldHandleMouseInput = false;
        this.contentElement.NotifyParentOnMouseInput = true;
        this.stackLayout.Children.Add(this.contentElement);

        this.buttonElement1 = new RadButtonElement();
        this.buttonElement1.Text = "Button1";
        this.stackLayout.Children.Add(this.buttonElement1);

        this.buttonElement2 = new RadButtonElement();
        this.buttonElement2.Text = "Button2";
        this.stackLayout.Children.Add(this.buttonElement2);

        this.Children.Add(this.stackLayout);
    }

    protected override void SynchronizeProperties()
    {
        base.SynchronizeProperties();

        this.Text = "";
        this.contentElement.Text = Convert.ToString(this.Data["Name"]);
        this.buttonElement1.Text = "Call " + Convert.ToString(this.Data["Phone"]);
        this.buttonElement2.Text = "Fax " + Convert.ToString(this.Data["Fax"]);
    }

    protected override Type ThemeEffectiveType
    {
        get
        {
            return typeof(SimpleListViewVisualItem);
        }
    }
}

To use the newly created items, you should handle the VisualItemCreating event as shown below:

Use the Custom Item


void radListView1_VisualItemCreating(object sender, ListViewVisualItemCreatingEventArgs e)
{
    if (this.radListView1.ViewType == ListViewType.ListView)
    {
        e.VisualItem = new MyCustomVisualItem();
    }
}

Custom items in IconsView ViewType

Figure 2: Custom IconListViewVisualItem

WinForms RadListView Custom IconListViewVisualItem

We should create a custom visual item inheriting the IconListViewVisualItem. The following example demonstrates how to add custom elements to the IconListViewVisualItem.Children collection:

Creating custom item


public class MyCustomIconListViewVisualItem :IconListViewVisualItem       
{
    protected override Type ThemeEffectiveType     
    { 
        get    
        { 
            return typeof(IconListViewVisualItem);     
        }
    }

    LightVisualElement imageElement = new LightVisualElement();
    RadButtonElement buttonElement = new RadButtonElement();
    StackLayoutElement stack = new StackLayoutElement();

    protected override void CreateChildElements()
    {
        base.CreateChildElements();

        stack.Orientation = Orientation.Vertical;
        imageElement.Image = Image.FromFile(@"..\..\Resources\email.png");
        buttonElement.Image = Image.FromFile(@"..\..\Resources\file.png");
        buttonElement.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageAboveText;

        stack.Children.Add(imageElement);
        stack.Children.Add(buttonElement);
        this.Children.Add(stack);
    }

    protected override void SynchronizeProperties()
    {
        base.SynchronizeProperties();
        this.Text = string.Empty;
        this.buttonElement.Text = this.Data.Text;
    }
}

To use the newly created item, you should subscribe to the VisualItemCreating event and replace the default item with your custom one:


void VisualItemCreating(object sender, ListViewVisualItemCreatingEventArgs e)
{
    if (this.radListView1.ViewType == ListViewType.IconsView)
    {
        e.VisualItem = new MyCustomIconListViewVisualItem();
    }
}

Custom Items in DetailsView ViewType

Since the DetailsView provides a grid-like interface, it displays a cell for each data field. In order to create custom cells you need to subscribe to the CellCreating event and replace the default DetailListViewDataCellElement with your own cell implementation.

Figure 3: Custom DetailListViewDataCellElement

WinForms RadListView Custom DetailListViewDataCellElement

First let's populate RadListView with items and set its ViewType property to DetailsView:

radListView1.ViewType = ListViewType.DetailsView;
DataTable dt = new DataTable();
dt.Columns.Add("Id", typeof(int));
dt.Columns.Add("Name", typeof(string));
for (int i = 0; i < 50; i++)
{
    dt.Rows.Add(i, "Item " + i);
}
this.radListView1.DataSource = dt;

Now let`s create our custom cell element containing a RadButtonElement. Additionally, we should inherit the DetailListViewDataCellElement class:


public class CustomDetailListViewDataCellElement : DetailListViewDataCellElement
{
    private RadButtonElement button;

    public CustomDetailListViewDataCellElement(DetailListViewVisualItem owner,
        ListViewDetailColumn column) : base(owner, column)
    {
    }

    protected override void CreateChildElements()
    {
        base.CreateChildElements();

        this.button = new RadButtonElement();
        this.Children.Add(this.button);
    }

    protected override Type ThemeEffectiveType
    {
        get
        {
            return typeof(DetailListViewHeaderCellElement);
        }
    }

    public override void Synchronize()
    {
        base.Synchronize();
        this.Text = "";
        DataRowView rowView = this.Row.DataBoundItem as DataRowView;
        this.button.Text = rowView.Row["Name"].ToString();
    }

    public override bool IsCompatible(ListViewDetailColumn data, object context)
    {
        if (data.Name != "Name")
        {
            return false;
        }
        return base.IsCompatible(data, context);
    }
}

Due to the virtualization mechanism of the RadListView control, the default cell of the control is compatible with all columns. When the control is scrolled, the default cell could override the custom one. To apply the custom cell when the control is scrolled is necessary to create another DetailListViewDataCellElement which is not compatible with your custom item.


public class DefaultCell : DetailListViewDataCellElement
{
    public DefaultCell(DetailListViewVisualItem owner, ListViewDetailColumn column) : base(owner, column)
    {
    }
    protected override Type ThemeEffectiveType
    {
        get
        {
            return typeof(DetailListViewHeaderCellElement);
        }
    }
    public override bool IsCompatible(ListViewDetailColumn data, object context)
    {
        if (data.Name != "Name")
        {
            return true;
        }
        return false;
    }
}      

Finally, we should handle the CellCreating event and substitute the default cell element with our own or return the default cell for the other columns:


private void radListView1_CellCreating(object sender, ListViewCellElementCreatingEventArgs e)
{
    DetailListViewDataCellElement cell = e.CellElement as DetailListViewDataCellElement;
    if (cell != null && cell.Data.Name == "Name")
    {
        e.CellElement = new CustomDetailListViewDataCellElement(cell.RowElement, e.CellElement.Data);
    }
    else if (cell != null && cell.Data.Name != "Name")
    {
        e.CellElement = new DefaultCell(cell.RowElement, e.CellElement.Data);
    }
}