Custom Items
By default, RadDropDownList displays text and image in its drop-down items. However, the default layout might not be suitable for you, and in this case you can use the flexible mechanism it features for creating visual items with custom content elements, functionality and properties.
This article demonstrates how to display detailed information for each employee from the Northwind.Employees table which is used as data source.
1. Create a class that inherits from RadListVisualItem. Override its CreateChildElements method where you can add the desired content elements. The custom item will have no styles, because there are no defined styles for its type in the themes. You can apply the RadListVisualItem’s styles to it by defining its ThemeEffectiveType.
2. Override the Synchronize method in order to match the displayed data in the content elements with the respective DataBoundItem. As the “Photo” column in the Northwind.Employees table contains a byte array, we should convert it to Image:
Custom RadListVisualItem
public class CustomVisualItem : RadListVisualItem
{
Font boldFont = new Font("Arial",10f, FontStyle.Bold);
Font italicFont = new Font("Arial",10f, FontStyle.Italic);
DockLayoutPanel mainContainer;
StackLayoutElement leftColumn;
StackLayoutElement rightColumn;
LightVisualElement titleElement;
LightVisualElement photoElement;
LightVisualElement nameElement;
LightVisualElement addressElement;
LightVisualElement phoneElement;
protected override Type ThemeEffectiveType
{
get
{
return typeof(RadListVisualItem);
}
}
protected override void CreateChildElements()
{
base.CreateChildElements();
mainContainer = new DockLayoutPanel();
leftColumn = new StackLayoutElement();
rightColumn = new StackLayoutElement();
titleElement = new LightVisualElement();
photoElement = new LightVisualElement();
nameElement = new LightVisualElement();
addressElement = new LightVisualElement();
phoneElement = new LightVisualElement();
this.Children.Add(mainContainer);
mainContainer.LastChildFill = true;
leftColumn.Orientation = Orientation.Vertical;
leftColumn.Children.Add(photoElement);
photoElement.DrawBorder = true;
rightColumn.Orientation = Orientation.Vertical;
rightColumn.Children.Add(nameElement);
nameElement.Font = boldFont;
rightColumn.Children.Add(addressElement);
rightColumn.Children.Add(phoneElement);
rightColumn.Children.Add(titleElement);
titleElement.DrawBorder = true;
titleElement.Font = italicFont;
titleElement.BorderBoxStyle = Telerik.WinControls.BorderBoxStyle.FourBorders;
titleElement.BorderLeftWidth = 0;
titleElement.BorderTopWidth = 1;
titleElement.BorderRightWidth = 0;
titleElement.BorderBottomWidth = 0;
mainContainer.Children.Add(leftColumn);
mainContainer.Children.Add(rightColumn);
DockLayoutPanel.SetDock(leftColumn, Telerik.WinControls.Layouts.Dock.Left);
DockLayoutPanel.SetDock(rightColumn, Telerik.WinControls.Layouts.Dock.Right);
leftColumn.NotifyParentOnMouseInput = true;
rightColumn.NotifyParentOnMouseInput = true;
titleElement.NotifyParentOnMouseInput = true;
photoElement.NotifyParentOnMouseInput = true;
nameElement.NotifyParentOnMouseInput = true;
addressElement.NotifyParentOnMouseInput = true;
phoneElement.NotifyParentOnMouseInput = true;
}
public override void Synchronize()
{
base.Synchronize();
this.Text = string.Empty;
DataRowView rowView = this.Data.DataBoundItem as DataRowView;
if (rowView != null)
{
this.photoElement.Image = GetImageFromData(rowView.Row["Photo"] as byte[]);
this.titleElement.Text = rowView.Row["Title"].ToString();
this.nameElement.Text = rowView.Row["FirstName"].ToString() + " " + rowView.Row["LastName"].ToString();
this.addressElement.Text = "Address: " + rowView.Row["Address"].ToString().Replace(System.Environment.NewLine, " ");
this.phoneElement.Text = "Phone: " + rowView.Row["HomePhone"].ToString();
}
}
private Image GetImageFromData(byte[] imageData)
{
const int OleHeaderLength = 78;
MemoryStream memoryStream = new MemoryStream();
if (HasOleContainerHeader(imageData))
{
memoryStream.Write(imageData, OleHeaderLength, imageData.Length - OleHeaderLength);
}
else
{
memoryStream.Write(imageData, 0, imageData.Length);
}
Bitmap bitmap = new Bitmap(memoryStream);
return bitmap.GetThumbnailImage(55, 65, null, new IntPtr());
}
private bool HasOleContainerHeader(byte[] imageByteArray)
{
const byte OleByte0 = 21;
const byte OleByte1 = 28;
return (imageByteArray[0] == OleByte0) && (imageByteArray[1] == OleByte1);
}
}
Public Class CustomVisualItem
Inherits RadListVisualItem
Private boldFont As Font
Private italicFont As Font
Private mainContainer As DockLayoutPanel
Private leftColumn As StackLayoutElement
Private rightColumn As StackLayoutElement
Private titleElement As LightVisualElement
Private photoElement As LightVisualElement
Private nameElement As LightVisualElement
Private addressElement As LightVisualElement
Private phoneElement As LightVisualElement
Protected Overrides ReadOnly Property ThemeEffectiveType() As Type
Get
Return GetType(RadListVisualItem)
End Get
End Property
Protected Overrides Sub CreateChildElements()
MyBase.CreateChildElements()
boldFont = New Font("Arial", 10.0F, FontStyle.Bold)
italicFont = New Font("Arial", 10.0F, FontStyle.Italic)
mainContainer = New DockLayoutPanel()
leftColumn = New StackLayoutElement()
rightColumn = New StackLayoutElement()
titleElement = New LightVisualElement()
photoElement = New LightVisualElement()
nameElement = New LightVisualElement()
addressElement = New LightVisualElement()
phoneElement = New LightVisualElement()
Me.Children.Add(mainContainer)
mainContainer.LastChildFill = True
leftColumn.Orientation = Orientation.Vertical
leftColumn.Children.Add(photoElement)
photoElement.DrawBorder = True
rightColumn.Orientation = Orientation.Vertical
rightColumn.Children.Add(nameElement)
nameElement.Font = boldFont
rightColumn.Children.Add(addressElement)
rightColumn.Children.Add(phoneElement)
rightColumn.Children.Add(titleElement)
titleElement.DrawBorder = True
titleElement.Font = italicFont
titleElement.BorderBoxStyle = Telerik.WinControls.BorderBoxStyle.FourBorders
titleElement.BorderLeftWidth = 0
titleElement.BorderTopWidth = 1
titleElement.BorderRightWidth = 0
titleElement.BorderBottomWidth = 0
mainContainer.Children.Add(leftColumn)
mainContainer.Children.Add(rightColumn)
DockLayoutPanel.SetDock(leftColumn, Telerik.WinControls.Layouts.Dock.Left)
DockLayoutPanel.SetDock(rightColumn, Telerik.WinControls.Layouts.Dock.Right)
leftColumn.NotifyParentOnMouseInput = True
rightColumn.NotifyParentOnMouseInput = True
titleElement.NotifyParentOnMouseInput = True
photoElement.NotifyParentOnMouseInput = True
nameElement.NotifyParentOnMouseInput = True
addressElement.NotifyParentOnMouseInput = True
phoneElement.NotifyParentOnMouseInput = True
End Sub
Public Overrides Sub Synchronize()
MyBase.Synchronize()
Me.Text = String.Empty
Dim rowView As DataRowView = TryCast(Me.Data.DataBoundItem, DataRowView)
If rowView IsNot Nothing Then
Me.photoElement.Image = GetImageFromData(TryCast(rowView.Row("Photo"), Byte()))
Me.titleElement.Text = rowView.Row("Title").ToString()
Me.nameElement.Text = rowView.Row("FirstName").ToString() & " " & rowView.Row("LastName").ToString()
Me.addressElement.Text = "Address: " & rowView.Row("Address").ToString().Replace(System.Environment.NewLine, " ")
Me.phoneElement.Text = "Phone: " & rowView.Row("HomePhone").ToString()
End If
End Sub
Private Function GetImageFromData(imageData As Byte()) As Image
Const OleHeaderLength As Integer = 78
Dim memoryStream As New MemoryStream()
If HasOleContainerHeader(imageData) Then
memoryStream.Write(imageData, OleHeaderLength, imageData.Length - OleHeaderLength)
Else
memoryStream.Write(imageData, 0, imageData.Length)
End If
Dim bitmap As New Bitmap(memoryStream)
Return bitmap.GetThumbnailImage(55, 65, Nothing, New IntPtr())
End Function
Private Function HasOleContainerHeader(imageByteArray As Byte()) As Boolean
Const OleByte0 As Byte = 21
Const OleByte1 As Byte = 28
Return (imageByteArray(0) = OleByte0) AndAlso (imageByteArray(1) = OleByte1)
End Function
End Class
3. Subscribe to the CreatingVisualListItem event before populating the RadDropDownList with data and replace the default item with your custom one:
Custom RadListVisualItem
private void radDropDownList1_CreatingVisualListItem(object sender, Telerik.WinControls.UI.CreatingVisualListItemEventArgs args)
{
args.VisualItem = new CustomVisualItem();
}
Private Sub radDropDownList1_CreatingVisualListItem(sender As Object, args As Telerik.WinControls.UI.CreatingVisualListItemEventArgs)
args.VisualItem = New CustomVisualItem()
End Sub
4. The last thing we need to do is to set the RadDropDownList.AutoSizeItems property to false and specify the ItemHeight:
Custom RadListVisualItem
this.radDropDownList1.AutoSizeItems = false;
this.radDropDownList1.DropDownListElement.ListElement.ItemHeight = 90;
Me.RadDropDownList1.AutoSizeItems = False
Me.RadDropDownList1.DropDownListElement.ListElement.ItemHeight = 90