I want to add a column to the GridView that will allow me to assign and display multiple values for an item.
For example, imagine you want to track the types (home, office, cell) of telephone numbers for users. Note, this is not my actual requirement. A user can have multiple telephone number types. I don't want to display two separate rows in the GridView for the same user, though. I want to display one row per user, and have the telephone types column allow the display and assignment of multiple telephone number types (e.g., home, office, cell).
A co-worker came up with the idea of creating a User Control that would contain a combobox control to allow the user to select the telephone number types in the combobox and display the selected values in a listbox below it. I specifically chose types for this example, because there's a limited, known set of them-- that's where the idea of the combobox control came in, that is, I need to choose from a limited set of choices.
I looked at the Forums blog titled, "Possible to Add a User Control a A Grid Column," at the following url:
http://www.telerik.com/community/forums/winforms/gridview/possible-to-add-a-user-control-to-a-grid-column.aspx
. . . and tried to implement the solution therein, but when I tried defining a variable of type GridViewDataColumn I got the following design-time error message:
'New' cannot be used on a class that is declared 'MustInherit'.
I also tried defining a variable of GridViewColumn, but got the same error message.
Is there a way to add a User Control to a GridView?
As a separate, but related issue, can I add a LinkLabel control to the GridView, and can the GridViewComboBoxColumn display multiple selections?
21 Answers, 1 is accepted
I've provided a solution like this in the past, but you don't really need a new column, you can simply define and use a custom editor for that kind of cells, please take a look at the example I've provided here and also this KB Article on how to add custom elements inside a cell when in design mode.
Hope this helps, if you have any other questions or comments, please let me know,
Best Regards,
Emanuel Varga
Telerik WinForms MVP
You can show multiple values in a cell by placing a list element inside. It will add an automatic scrolling when there are more items than the cell can show. Please consider the following sample:
DataTable table =
new
DataTable();
table.Columns.Add(
"ID"
,
typeof
(
int
));
table.Columns.Add(
"Name"
,
typeof
(
string
));
table.Columns.Add(
"Phones"
,
typeof
(
string
));
table.Rows.Add(1,
"John Smith"
,
"431-235-235\n235-255-333\n233-323-323"
);
table.Rows.Add(2,
"Tomas Wright"
,
"431-235-235\n235-255-333"
);
table.Rows.Add(2,
"Lewis Anderson"
,
""
);
this
.radGridView1.DataSource = table;
this
.radGridView1.TableElement.RowHeight = 80;
this
.radGridView1.AllowAddNewRow =
false
;
this
.radGridView1.Columns.Remove(
"Phones"
);
this
.radGridView1.Columns.Add(
new
ListBoxColumn(
"Phones"
));
this
.radGridView1.Columns[
"Name"
].Width = 90;
this
.radGridView1.Columns[
"Phones"
].Width = 150;
public
class
ListBoxColumn : GridViewDataColumn
{
public
ListBoxColumn(
string
name)
:
base
(name)
{
}
public
override
Type GetCellType(GridViewRowInfo row)
{
if
(row
is
GridViewDataRowInfo)
{
return
typeof
(ListBoxCell);
}
return
base
.GetCellType(row);
}
}
public
class
ListBoxCell : GridDataCellElement
{
RadListElement listElement;
public
ListBoxCell(GridViewColumn column, GridRowElement row)
:
base
(column, row)
{
}
protected
override
void
CreateChildElements()
{
base
.CreateChildElements();
listElement =
new
RadListElement();
this
.Children.Add(listElement);
}
protected
override
void
SetContentCore(
object
value)
{
listElement.Items.Clear();
if
(value !=
null
&& value != DBNull.Value)
{
string
[] phones = value.ToString().Split(
'\n'
);
foreach
(
string
phone
in
phones)
{
listElement.Items.Add(
new
RadListDataItem(phone));
}
}
}
public
override
bool
IsCompatible(GridViewColumn data,
object
context)
{
return
data.Name ==
"Phones"
&& context
is
GridDataRowElement;
}
}
I hope it helps. If you need further assistance with this task, we will be glad to help.
Greetings,
Jack
the Telerik team
Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>
In essence, though, I want to be able to display multiple values (listbox aspect). When I edit, I want to have a combobox control to choose one of several possible choices, when I choose the item in the combobox, that item gets added to the listbox for display.
I also thought I would need two LinkLabel controls (one that displays Done, another displays Remove), perhaps located under the listbox. Clicking on Done would close editing, and leave the listbox as the display control. Clicking on Remove while editing, removes a selected item from the listbox.
So to recap, a combobox (perhaps located at the top during editing) for adding items, listbox (located just below the combobox) for displaying items, and two link labels (Done and Remove).
Thanks for your prompt reply,
Hector
Thank you for these details. I modified my example to include link labels and a drop down list as you have required. Please consider the code below:
public
class
LinkItem : LightVisualElement
{
static
Font linkFont =
new
Font(
"Segoe UI"
, 9f, FontStyle.Underline);
public
LinkItem(
string
text)
{
this
.Text = text;
}
protected
override
void
InitializeFields()
{
base
.InitializeFields();
this
.Font = linkFont;
this
.ForeColor = Color.Blue;
this
.StretchHorizontally =
false
;
this
.StretchVertically =
false
;
this
.Alignment = ContentAlignment.MiddleRight;
}
}
public
class
ListBoxCell : GridDataCellElement
{
RadListElement listElement;
LinkItem linkDone;
LinkItem linkRemove;
StackLayoutElement linksContainer;
RadDropDownListElement dropDownListElement;
public
ListBoxCell(GridViewColumn column, GridRowElement row)
:
base
(column, row)
{
}
protected
override
void
CreateChildElements()
{
base
.CreateChildElements();
StackLayoutElement stack =
new
StackLayoutElement();
stack.Orientation = Orientation.Vertical;
stack.StretchHorizontally =
true
;
stack.StretchVertically =
true
;
this
.Children.Add(stack);
dropDownListElement =
new
RadDropDownListElement();
dropDownListElement.Visibility = ElementVisibility.Collapsed;
dropDownListElement.StretchVertically =
false
;
stack.Children.Add(dropDownListElement);
listElement =
new
RadListElement();
listElement.StretchVertically =
true
;
listElement.StretchHorizontally =
true
;
stack.Children.Add(listElement);
linksContainer =
new
StackLayoutElement();
linksContainer.StretchVertically =
false
;
linksContainer.StretchHorizontally =
true
;
linksContainer.Visibility = ElementVisibility.Collapsed;
stack.Children.Add(linksContainer);
linkDone =
new
LinkItem(
"Done"
);
linksContainer.Children.Add(linkDone);
linkRemove =
new
LinkItem(
"Remove"
);
linksContainer.Children.Add(linkRemove);
}
public
override
void
UpdateInfo()
{
base
.UpdateInfo();
if
(linksContainer !=
null
)
{
linksContainer.Visibility = RowInfo.IsCurrent ? ElementVisibility.Visible : ElementVisibility.Collapsed;
dropDownListElement.Visibility = RowInfo.IsCurrent ? ElementVisibility.Visible : ElementVisibility.Collapsed;
}
}
protected
override
void
SetContentCore(
object
value)
{
listElement.Items.Clear();
if
(value !=
null
&& value != DBNull.Value)
{
string
[] phones = value.ToString().Split(
'\n'
);
foreach
(
string
phone
in
phones)
{
listElement.Items.Add(
new
RadListDataItem(phone));
}
}
}
protected
override
SizeF MeasureOverride(SizeF availableSize)
{
if
(linksContainer.Visibility == ElementVisibility.Visible)
{
listElement.MaxSize =
new
System.Drawing.Size(0, (
int
)availableSize.Height - 40);
}
else
{
listElement.MaxSize = Size.Empty;
}
return
base
.MeasureOverride(availableSize);
}
public
override
bool
IsCompatible(GridViewColumn data,
object
context)
{
return
data.Name ==
"Phones"
&& context
is
GridDataRowElement;
}
}
Could you please describe in detail the exact behavior and look that you want to achieve. This will help me to better understand the scenario and to assist you further.
Best wishes,
Jack
the Telerik team
Q2’11 SP1 of RadControls for WinForms is available for download (see what's new); also available is the Q3'11 Roadmap for Telerik Windows Forms controls.
Jack,
thanks for your prompt reply. I've implemented your example as you instructed to make sure I got the plumbing (or wiring) correct, before changing it to work with my actual data.
I may leave it the way you designed it, but, just in case, can the ListBoxCell be made to expand, showing the RadDropDownListElement and LinkItems only when the cell is clicked?
How can I populate the RadDropDownListElement with the list of possible choices?
Follow-up:
I presented the custom ListBoxCell to a user for review. Following is the user's commments:
The drop-down blends in to the listbox, which appears just below it. How can I provide some spacing (padding) between the drop-down and the listbox?
When the drop-down is selected, the list that drops down blends into the next data row's listbox values. Perhaps setting a different background color to the drop-down list during selection would help. What do you suggest?
Can the Done link be aligned left, while the Remove link be aligned right?
Thanks in advance,
Hector
Directly to your questions:
Yes, you can "expand" the current row by handling the CurrentRowChanged event. Consider the following code:
this
.radGridView1.CurrentRowChanged +=
new
CurrentRowChangedEventHandler(radGridView1_CurrentRowChanged);
if
(
this
.radGridView1.CurrentRow !=
null
)
{
this
.radGridView1.CurrentRow.Height = 100;
}
void
radGridView1_CurrentRowChanged(
object
sender, CurrentRowChangedEventArgs e)
{
if
(e.OldRow !=
null
)
{
e.OldRow.Height = 23;
}
if
(e.CurrentRow !=
null
)
{
e.CurrentRow.Height = 100;
}
}
In addition, I modified the UpdateInfo method to hide the cell content until the row becomes current:
public
override
void
UpdateInfo()
{
base
.UpdateInfo();
if
(linksContainer !=
null
)
{
linksContainer.Visibility = RowInfo.IsCurrent ? ElementVisibility.Visible : ElementVisibility.Collapsed;
dropDownListElement.Visibility = RowInfo.IsCurrent ? ElementVisibility.Visible : ElementVisibility.Collapsed;
this
.Children[0].Visibility = RowInfo.IsCurrent ? ElementVisibility.Visible : ElementVisibility.Collapsed;
}
}
You can populate the RadDropDownListElement when handling the CreateChildItems event. Here is an example:
DataTable table =
new
DataTable();
table.Columns.Add(
"ID"
,
typeof
(
int
));
table.Columns.Add(
"Name"
,
typeof
(
string
));
table.Rows.Add(1,
"one"
);
table.Rows.Add(2,
"two"
);
table.Rows.Add(3,
"three"
);
dropDownListElement.DisplayMember =
"Name"
;
dropDownListElement.ValueMember =
"ID"
;
dropDownListElement.DataSource = table;
To add spacing, you can use the ElementSpacing property of StackLayoutElement:
StackLayoutElement stack =
new
StackLayoutElement();
//...
stack.ElementSpacing = 3;
or you can add Margin in RadDropDownListElement:
dropDownListElement.Margin =
new
System.Windows.Forms.Padding(0, 0, 0, 4);
You can customize almost every aspect of our controls by using the Visual Style Builder tool and modifying any of our existing themes. However, if you prefer to use code, you can customize the background color for the popup by using the following code:
dropDownListElement.ListElement.BackColor = Color.LightGray;
dropDownListElement.ListElement.GradientStyle = GradientStyles.Solid;
You can align the link buttons by adding a stretchable element between them, as demonstrated below:
linkDone =
new
LinkItem(
"Done"
);
linksContainer.Children.Add(linkDone);
LightVisualElement stretchElement =
new
LightVisualElement();
stretchElement.StretchHorizontally =
true
;
linksContainer.Children.Add(stretchElement);
linkRemove =
new
LinkItem(
"Remove"
);
linksContainer.Children.Add(linkRemove);
I attached the modified code here for your convenience. I hope it helps.
Greetings,
Jack
the Telerik team
Q2’11 SP1 of RadControls for WinForms is available for download (see what's new); also available is the Q3'11 Roadmap for Telerik Windows Forms controls.
thanks for your prompt reply. Regarding expanding the row, I only want to expand it when the specific cell column is selected (that is, I'm editing the cell). In our example, it would be the "Phones" column.
By the way, FYI . . . I'm developing in VB.NET, so the code won't exactly help. But don't worry about converting it to VB.NET, I'm doing it while I read you code snippets.
About the Visual Style Builder (VSB) is that a separate tool (I guess I can research this on my own)? Considering we're creating the control programmatically, can I still incorporate the VSB?
Thanks in advance for your reply,
Hector
I took a look at the modified code because I wanted to find out where you placed the code that performs the following:
if(this.radGridView1.CurrentRow != null) {...}
However, I did not find that (nor any of the other new code snippets) in the attached file.
Thnx,
Hector
After reviewing the new updates (spacing, background color, etc.), the user requested that i get rid of the Remove link, replacing it by adding a column to the listbox with an "x" that can be clicked on to remove the item.
I figured the solution would be to use a GridView (instead of adding a column to the listbox), so I tried adding a RadGridViewElement instead of a RadListElement. Unfortunately, I couldn't figure out how to define the columns for the RadGridViewElement. Perhaps I don't understand the relation between the RadGridViewElement and the RadGridView.
Can you help?
My first issue appeared when I changed the way I populated the dropdownlistelement. Initially, I was populating it by hardcoding the data using Columns.Add. Then I changed it to call a subroutine that calls a stored procedure in the database using a DataReader. I called the subroutine from the CreateChildElements method. Using this approach, I got the following error message: 'Invalid attempt to call FieldCount when reader is closed.'
I'm writing this from home right now so I don't have access to the code.
Any suggestions would be greatly appreciated.
Regards,
Hector
Regarding your questions:
If you want to expand the row only when clicking on a specific cell, you have to use the CurrentCellChanged event instead of CurrentRowChanged event. Here is a sample:
Private
Sub
radGridView1_CurrentCellChanged(sender
As
Object
, e
As
CurrentCellChangedEventArgs)
Handles
RadGridView1.CurrentCellChanged
If
e.NewCell IsNot
Nothing
Then
If
e.CurrentCell IsNot
Nothing
AndAlso
Not
e.CurrentCell.RowInfo.Equals(e.NewCell.RowInfo)
Then
e.CurrentCell.RowInfo.Height = 23
End
If
If
e.NewCell.ColumnInfo.Name =
"Phones"
Then
e.NewCell.RowInfo.Height = 100
Else
e.NewCell.RowInfo.Height = 23
End
If
ElseIf
e.CurrentCell IsNot
Nothing
Then
e.CurrentCell.RowInfo.Height = 23
End
If
End
Sub
Yes, Visual Style Builder is a separate tool used to create or modify new themes. You cannot use it directly from your application, however you can create a theme. Please consider the following help article.
I added the code which checks whether the CurrentRow is Nothing in Form's OnLoad event after setting the data source. This code ensures that the CurrentRow will have the correct size in all cases.
You cannot use RadGridViewElement in the same way you are using RadListElement. The best option in this case is to use custom visual elements in the list box. Here is the code:
Public
Class
CustomListElement
Inherits
RadListVisualItem
Private
buttonX
As
RadButtonElement
Protected
Overrides
ReadOnly
Property
ThemeEffectiveType()
As
Type
Get
Return
GetType
(RadListVisualItem)
End
Get
End
Property
Protected
Overrides
Sub
CreateChildElements()
MyBase
.CreateChildElements()
buttonX =
New
RadButtonElement()
buttonX.Alignment = ContentAlignment.MiddleRight
buttonX.StretchHorizontally =
False
buttonX.StretchVertically =
False
buttonX.Text =
"x"
AddHandler
buttonX.Click,
AddressOf
buttonX_Click
Me
.Children.Add(buttonX)
End
Sub
Private
Sub
buttonX_Click(sender
As
Object
, e
As
EventArgs)
Dim
listElement
As
RadListElement =
Me
.FindAncestor(Of RadListElement)()
listElement.Items.Remove(Data)
End
Sub
End
Class
You should handle also the CreatingVisualItem event to replace the default visual item:
AddHandler
listElement.CreatingVisualItem,
AddressOf
listElement_CreatingVisualItem
Private
Sub
listElement_CreatingVisualItem(sender
As
Object
, args
As
CreatingVisualListItemEventArgs)
args.VisualItem =
New
CustomListElement()
End
Sub
Regarding the last issue, I am not sure what causes it. Could you please send me your application. This will help me to locate the issue and provide you with accurate support.
Greetings, Jack
the Telerik team
Q2’11 SP1 of RadControls for WinForms is available for download (see what's new); also available is the Q3'11 Roadmap for Telerik Windows Forms controls.
I will try your last suggestions shortly. However, for now, here is some information on the exception I'm getting:
InvalidOperationException was unhandled by user code
View Detail:
- InnerException: "Invalid attempt to call FieldCount when reader is closed."
- StackTrace:
at System.Data.SqlClient.SqlDataReader.get_FieldCount()
at System.Data.Common.DbEnumerator.BuildSchemaInfo()
at System.Data.Common.DbEnumerator.MoveNext()
at Telerik.WinControls.Data.RadListSource`1.BindToEnumerable()
...
Note: above is an excerpt of the StackTrace. I can provide the full StackTrace if you wish.
...
My HandleException method, showed me that the statement that caused the exception to occur is the following (from PopulateDatabaseDependentControls() method in code, see code block, below):
Me.dgBidItems.DataSource = bsBidItems
Note, I change the following statement in the CreateChildElements method:
From:
PopulateDropDownListElement__FromDatabase()
'PopulateDropDownListElement__UsingHardCodedValues() ' COMMENTED OUT; NOT CURRENTLY USED
To:
'PopulateDropDownListElement__FromDatabase() ' COMMENTED OUT; NOT CURRENTLY USED
PopulateDropDownListElement__UsingHardCodedValues()
... and it works!
FYI . . . Stored Procedure Returns data as such:
BidItemID CustomerDesc Plants DateCreated
14 TestSaveItem201108121517a PLAA, PLBB 08/12/2011
19 TestSaveItem201108121517b PLAA, PLBB, PLCC 08/18/2011
Code Excerpt:
Private Sub InitializeBidItemsDataGrid()
' called by CustomInitialization after call to InitializeComponent() in New() constructor
Try
With Me.dgBidItems
' Set Location, Size
.Left = 6 ' X
.Top = 22 ' Y: space for the Group Box Text
.Height = Me.gpItems.Height - 24
.Width = Me.gpItems.Width - 12
.TableElement.RowHeight = 60
' Disable 'Click here to add a new row' row
.AllowAddNewRow = False
' Disable 'Drag a column here to group by that column' row
.ShowGroupPanel = False
Dim gvdCol As tlrkUI.GridViewDataColumn
gvdCol = New tlrkUI.GridViewCheckBoxColumn("colSelected")
gvdCol.HeaderText = ".."
gvdCol.Width = 20
.Columns.Add(gvdCol)
gvdCol = New tlrkUI.GridViewTextBoxColumn("BidItemID")
gvdCol.HeaderText = "BidItemID"
gvdCol.Width = 70
.Columns.Add(gvdCol)
gvdCol = New tlrkUI.GridViewTextBoxColumn("CustomerDesc")
gvdCol.HeaderText = "CustomerDesc"
gvdCol.Width = 140
.Columns.Add(gvdCol)
'
' PlantsV9
'
'' comebackhere
.Columns.Remove("Plants")
gvdCol = New CustomGridViewColumn("Plants")
gvdCol.HeaderText = "Plants"
gvdCol.Width = 90
.Columns.Add(gvdCol)
gvdCol = New tlrkUI.GridViewTextBoxColumn("DateCreated")
gvdCol.HeaderText = "DateCreated"
gvdCol.Width = 70
.Columns.Add(gvdCol)
End With
Catch ex As Exception
HandleException(ex)
End Try
End Sub
Private Sub PopulateDatabaseDependentControls()
' called in response to handling User Control Load event
If Me.iBidHeaderID <= 0 Then
Exit Sub
End If
Dim startTime As DateTime = DateTime.Now
Try
Dim cmd As New SqlCommand
Dim ds As DataSet = New DataSet()
Dim da As SqlDataAdapter
' [sp_APP_BidItem_Get_ByBidHeaderID]
Dim sSql As String = "dbo.sp_APP_GetBidItemsByBidHeaderID"
Using dbconn As New SqlConnection(sMainConnectionString)
Try
dbconn.Open()
cmd.CommandType = CommandType.StoredProcedure
cmd.Connection = dbconn
cmd.CommandText = sSql
cmd.Parameters.Add("@BidHeaderID", System.Data.SqlDbType.Int).Value = Me.iBidHeaderID
da = New SqlDataAdapter(cmd)
da.Fill(ds, "BidItems")
If ds IsNot Nothing AndAlso ds.Tables IsNot Nothing AndAlso ds.Tables.Count > 0 Then
' assign data binding data soures
bsBidItems = New BindingSource()
bsBidItems.DataSource = ds.Tables("BidItems").DefaultView()
' * * * * * NOTE: FOLLOWING IS THE STATEMENT THAT THE EXCEPTION OCCURS ON * * * * * *
Me.dgBidItems.DataSource = bsBidItems ' * * * * * NOTE: THIS IS THE STATEMENT THAT THE EXCEPTION OCCURS ON * * * * * *
' * * * * * NOTE: ABOVE IS THE STATEMENT THAT THE EXCEPTION OCCURS ON * * * * * *
End If
Catch sqlEx As SqlException
HandleException(sqlEx)
Finally
End Try
End Using
Catch ex As Exception
HandleException(ex)
End Try
End Sub
#Region "Assign Plants Using CustomGridViewCellElement"
Public Class CustomGridViewCellElement
Inherits tlrkUI.GridDataCellElement
Private listElement As Telerik.WinControls.UI.RadListElement
Private linkDone As CustomLinkItem
Private linkRemove As CustomLinkItem
Private dropDownListElement As Telerik.WinControls.UI.RadDropDownListElement
Private linksContainer As Telerik.WinControls.UI.StackLayoutElement
Public Sub New(ByVal column As tlrkUI.GridViewColumn, ByVal row As tlrkUI.GridRowElement)
MyBase.New(column, row)
End Sub
Protected Overrides Sub CreateChildElements()
MyBase.CreateChildElements()
Try
Dim mainContainer As Telerik.WinControls.UI.StackLayoutElement = New Telerik.WinControls.UI.StackLayoutElement()
With mainContainer
.Orientation = Orientation.Vertical
.StretchHorizontally = True
.StretchVertically = True
.ElementSpacing = 3
End With
Me.Children.Add(mainContainer)
dropDownListElement = New Telerik.WinControls.UI.RadDropDownListElement()
With dropDownListElement
.Visibility = Telerik.WinControls.ElementVisibility.Collapsed
.StretchVertically = False
.ListElement.BackColor = Color.PaleGoldenrod
.ListElement.GradientStyle = Telerik.WinControls.GradientStyles.Solid
End With
mainContainer.Children.Add(dropDownListElement)
listElement = New Telerik.WinControls.UI.RadListElement
With listElement
.StretchHorizontally = True
.StretchVertically = True
End With
mainContainer.Children.Add(listElement)
linksContainer = New tlrkUI.StackLayoutElement()
With linksContainer
.StretchHorizontally = True
.StretchVertically = False
End With
linksContainer.Visibility = Telerik.WinControls.ElementVisibility.Collapsed
linkDone = New CustomLinkItem("Done")
linksContainer.Children.Add(linkDone)
linkRemove = New CustomLinkItem("Remove")
linksContainer.Children.Add(linkRemove)
mainContainer.Children.Add(linksContainer)
'
' Populate DropDownListElement
'
PopulateDropDownListElement__FromDatabase()
'PopulateDropDownListElement__UsingHardCodedValues()
Catch ex As Exception
HandleException(ex)
End Try
End Sub
Public Overrides Sub UpdateInfo()
MyBase.UpdateInfo()
Try
If (linksContainer IsNot Nothing) Then
If RowInfo.IsCurrent Then
linksContainer.Visibility = Telerik.WinControls.ElementVisibility.Visible
dropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Visible
Else
linksContainer.Visibility = Telerik.WinControls.ElementVisibility.Collapsed
dropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed
End If
End If
Catch ex As Exception
HandleException(ex)
End Try
End Sub
Private Sub HandleException(ByVal ex As Exception, Optional ByVal bLogException As Boolean = True)
If bLogException AndAlso sbLog IsNot Nothing Then
modAppMain.LogException(ex, sName & "." & sSourceMethod & " Log: " & sbLog.ToString(), _
"Exception", sName, True)
End If
End Sub
Private Sub PopulateDropDownListElement__UsingHardCodedValues()
dropDownListElement.Items.Add(New tlrkUI.RadListDataItem("PLAA", 1))
dropDownListElement.Items.Add(New tlrkUI.RadListDataItem("PLBB", 2))
dropDownListElement.Items.Add(New tlrkUI.RadListDataItem("PLCC", 3))
dropDownListElement.Items.Add(New tlrkUI.RadListDataItem("PLDD", 4))
End Sub
Private Sub PopulateDropDownListElement__FromDatabase()
sSourceMethod = "PopulateDropDownListElement__FromDatabase"
Dim sbSQL As StringBuilder = New StringBuilder("select distinct plantid, plantcode")
sbSQL.Append(" from Plant") ' NOT ACTUAL SQL
Dim cmd As New SqlCommand
Dim reader As SqlDataReader
Try
Using dbconn As New SqlConnection(APP.My.Settings.dbConnOAM)
Try
dbconn.Open()
cmd.CommandType = CommandType.Text
cmd.Connection = dbconn
cmd.CommandText = sbSQL.ToString()
reader = cmd.ExecuteReader()
If reader.HasRows Then
dropDownListElement.DataSource = reader
dropDownListElement.DisplayMember = "plantcode"
dropDownListElement.ValueMember = "plantid"
End If
reader.Close()
Catch sqlEx As SqlException
HandleException(sqlEx)
Finally
End Try
End Using
Catch ex As Exception
HandleException(ex)
End Try
dropDownListElement.Text = "Select a Plant"
End Sub
Protected Overrides Sub SetContentCore(ByVal value As Object)
sSourceMethod = "SetContentCore"
Try
listElement.Items.Clear()
If ((value IsNot Nothing) AndAlso (value IsNot DBNull.Value)) Then
Dim arValues() As String = value.ToString().Split(",")
For Each val As String In arValues
listElement.Items.Add(New Telerik.WinControls.UI.RadListDataItem(val))
Next
End If
Catch ex As Exception
HandleException(ex)
End Try
End Sub
Protected Overrides Function MeasureOverride(ByVal availableSize As System.Drawing.SizeF) As System.Drawing.SizeF
sSourceMethod = "MeasureOverride"
Try
If linksContainer.Visibility = Telerik.WinControls.ElementVisibility.Visible Then
listElement.MaxSize = New System.Drawing.Size(0, System.Convert.ToInt32(availableSize.Height - 40))
Else
listElement.MaxSize = Size.Empty
End If
Catch ex As Exception
HandleException(ex)
End Try
Return MyBase.MeasureOverride(availableSize)
End Function
Public Overrides Function IsCompatible(ByVal data As Telerik.WinControls.UI.GridViewColumn, ByVal context As Object) As Boolean
'Return MyBase.IsCompatible(data, context)
sSourceMethod = "IsCompatible"
Try
If ((data.Name = "Plants") AndAlso (TypeOf context Is Telerik.WinControls.UI.GridDataRowElement)) Then
Return True
End If
Catch ex As Exception
HandleException(ex)
End Try
Return False
End Function
End Class
Public Class CustomGridViewColumn
Inherits tlrkUI.GridViewDataColumn
Private sName As String = "ucBidItemsList"
Private sSourceMethod As String
Private sbLog As StringBuilder = New StringBuilder("ucBidItemsList.CustomGridViewColumn Log:" & vbCrLf)
Public Sub New(ByVal sFieldName As String)
MyBase.New(sFieldName)
sSourceMethod = "CustomGridViewColumn.New"
sbLog.AppendLine("Reached " & sName & "." & sSourceMethod)
sbLog.AppendLine(" - sFieldName: " & sFieldName)
End Sub
Public Overrides Function GetCellType(ByVal row As Telerik.WinControls.UI.GridViewRowInfo) As System.Type
sSourceMethod = "CustomGridViewColumn.GetCellType"
sbLog.AppendLine("Reached " & sName & "." & sSourceMethod)
sbLog.AppendLine(" - TypeOf row: " & row.GetType().ToString)
Try
If (TypeOf row Is Telerik.WinControls.UI.GridViewDataRowInfo) Then
sbLog.AppendLine(" before Return GetType(CustomGridViewCellElement)")
Return GetType(CustomGridViewCellElement)
End If
If sbLog IsNot Nothing Then
modAppMain.LogMessage(sbLog.ToString(), sName)
End If
Catch ex As Exception
HandleException(ex)
End Try
Return MyBase.GetCellType(row)
End Function
Private Sub HandleException(ByVal ex As Exception, Optional ByVal bLogException As Boolean = True)
'If (ex.InnerException IsNot Nothing) Then
' MessageBox.Show(sSourceMethod & ". Exception: " & ex.Message & vbCrLf & _
' " - - - - - - - - - - " & vbCrLf & _
' " Inner Exception: " & vbCrLf & ex.InnerException.Message)
'Else
' MessageBox.Show(sSourceMethod & ". Exception: " & ex.Message)
'End If
If bLogException AndAlso sbLog IsNot Nothing Then
modAppMain.LogException(ex, sName & "." & sSourceMethod & " Log: " & sbLog.ToString(), _
"Exception", sName, True)
End If
End Sub
End Class
Private Sub dgBidItems_CurrentRowChanged(ByVal sender As Object, ByVal e As Telerik.WinControls.UI.CurrentRowChangedEventArgs) Handles dgBidItems.CurrentRowChanged
If e.OldRow IsNot Nothing Then
e.OldRow.Height = 40
End If
If e.CurrentRow IsNot Nothing Then
e.CurrentRow.Height = 120
End If
End Sub
#End Region
Thanks in advance for your help,
Hector
P.S. In a way I think you've answered my initial question, and the rest has been detail implementation issues. Should I mark one of the previous responses as an answer, or wait till the final solution?
In Emanuel Varga's example, he wired up the Click event handler to the RadButtonElement in the CellBeginEdit event for the GridView.
In your design where would I wire up the event handlers for the dropdownlistElement's SelectedIndexChanged event and the Done and Remove CustomLinkItem(s) Click events?
Thanks in advance for your help,
Hector
Telerik WinControls Newbie, :-)
I got rid of the CurrentRowChanged event handler, replacing it with the CurrentCellChanged event handler, and added the code which checks whether the CurrentRow is Nothing in a method called in response to the OnLoad event handler, setting the CurrentRow.Height to my default height as you suggested.
However, when the form initially appears and the data grid displays, the custom cell column displays the dropDownListElement and the listbox (displaying only the first value) for the default selected row. All other rows display just the listElement. When I select a different row, the same thing happens. FYI, I don't know if this affecta anything, but I added the following statement to set the first selection in the dropDownListElement:
dropDownListElement.Text = "Select a Plant"
I want the custom cell element to expand showing all elements only when the user clicks in that specific row and column's cell (i.e., the custom cell element).
How can I limit the height of the drop-down list aspect of the dropDownListElement when the user clicks on the drop-down arrow?
How can I restore the custom cell element to display only the listElement when the user clicks or tabs away from the the custom cell element (e.g., it loses focus). This will allow me to get rid of the Done link altogether.
Regarding the exception, it seems to be a generic data binding exception caused by the SqlDataReader used in your application. I found this thread which discusses the issue.
You have to change the UpdateInfo method in the custom cell element in order to hide the cell contents when the cell is not current:
Public
Overrides
Sub
UpdateInfo()
MyBase
.UpdateInfo()
If
linksContainer IsNot
Nothing
Then
linksContainer.Visibility =
If
(RowInfo.IsCurrent, ElementVisibility.Visible, ElementVisibility.Collapsed)
dropDownListElement.Visibility =
If
(RowInfo.IsCurrent, ElementVisibility.Visible, ElementVisibility.Collapsed)
Me
.Children(0).Visibility =
If
(IsCurrent, ElementVisibility.Visible, ElementVisibility.Collapsed)
End
If
End
Sub
This code will display the list element only when the cell is current.
To restrict the drop down height, you should set DropDownMinSize and DropDownMaxSize properties:
dropDownListElement.DropDownMinSize = new Size(0, 150)
dropDownListElement.DropDownMaxSize = new Size(0, 150)
Feel free to mark this response as an answer when all your questions are answered. If you have any other questions, do not hesitate to open new threads.
All the best,
Jack
the Telerik team
Q2’11 SP1 of RadControls for WinForms is available for download (see what's new); also available is the Q3'11 Roadmap for Telerik Windows Forms controls.
Jack,
thanks for the info on the SqlDataReader generic data binding exception. I will investigate that further at a later time.
I've managed to implement a similar fix in UpdateInfo, with the following code:
If (linksContainer IsNot Nothing) Then
If RowInfo.IsCurrent AndAlso ColumnInfo.IsCurrent AndAlso (Not bChangingRowInfoHeight) Then
linksContainer.Visibility = Telerik.WinControls.ElementVisibility.Visible
dropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Visible
Else
linksContainer.Visibility = Telerik.WinControls.ElementVisibility.Collapsed
dropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed
End If
End If
I added the Boolean, bChangingRowInfoHeight, so I don't set properties to .Visible when I've set RowInfo.Height to default (minimized, only listElement Visible, height) in the the done link event handler (when I click on the Done linkItem). I'm considering whether I even need the Done link anymore.
Thanks for the info on setting the drop-down height.
Regards,
Hector
P.S. Can I get the e-mail address of your supervisor(s), so I can tell them what a great job you've done.
I am glad that I could help. Your code seems OK and will also does the job. I am not allowed to provide you with the e-mail of my supervisor here, because this is public forum thread. However, I made him aware of this thread and your feedback. If you still want to share something about our support services, please find my response in a ticket called "Add User Control to GridView Column Ticket" that you can find in Your Account.
Please do not hesitate to contact me if you have any further questions.
Greetings,
Jack
the Telerik team
Q2’11 SP1 of RadControls for WinForms is available for download (see what's new); also available is the Q3'11 Roadmap for Telerik Windows Forms controls.
I have the following Code, that draw a RadDropDownListElement in second and third row.
But when I execute, and I scrollbar the datagrid, the RadDropDownListElement is displayed in others rows?
Meanwhile if I make the grid bigger size, it's displayed normal.
Why? and how to solve it
And how to not allow write or edit in the RadDropDownListElement, but just select an item.
Private Sub RadGridView1_CellFormatting(sender As System.Object, e As Telerik.WinControls.UI.CellFormattingEventArgs) Handles RadGridView1.CellFormatting
If e.RowIndex <> -1 Then
If e.ColumnIndex = 0 Then
If e.RowIndex = 2 Then
Dim vars As New ArrayList
vars.Add("AY@12@" & 2014)
vars.Add("Semester@12@" & 1)
Dim dt = Programs.ExecuteReturnProcedure(Programs.Company.ID, "GetStudents", vars).Tables(0)
Dim cc As New RadDropDownListElement()
cc.DataSource = dt
cc.DisplayMember = "Number"
cc.ValueMember = "Id"
e.CellElement.Children.Add(cc)
ElseIf e.RowIndex = 3 Then
Dim dt As New DataTable()
dt.Columns.Add("Number")
dt.Columns.Add("Id")
Dim dr = dt.NewRow()
dr("Number") = "One"
dr("Id") = "One"
dt.Rows.Add(dr)
dr = dt.NewRow()
dr("Number") = "two"
dr("Id") = "two"
dt.Rows.Add(dr)
dt.AcceptChanges()
Dim cc As New RadDropDownListElement()
cc.DataSource = dt
cc.DisplayMember = "Number"
cc.ValueMember = "Id"
e.CellElement.Children.Add(cc)
End If
End If
End If
End Sub
Thank you for writing.
Due to the UI virtualization in RadGridView, cell elements are created only for currently visible cells and are being reused during operations like scrolling, filtering, grouping and so on. That is why you may obtain unexpected behavior like undesired style for some cells. In addition, the CellFormatting event is appropriate for customizing cell's visual design (with the appropriate reset option), not for modifying the internal cell's structure, which may lead to performance issues as well. The recommended approach for achieving the described functionality is creating custom cell. Here is a sample approach:
public
Form1()
{
InitializeComponent();
CustomColumn col =
new
CustomColumn(
"Column"
);
this
.radGridView1.Columns.Add(col);
for
(
int
i = 0; i < 20; i++)
{
this
.radGridView1.Rows.Add(
"item1"
);
}
this
.radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
}
public
class
CustomCellElement : GridDataCellElement
{
public
CustomCellElement(GridViewColumn column, GridRowElement row) :
base
(column, row)
{
}
RadDropDownListElement dropDown;
protected
override
void
CreateChildElements()
{
base
.CreateChildElements();
dropDown =
new
RadDropDownListElement();
dropDown.DropDownStyle = RadDropDownStyle.DropDownList;
this
.Children.Add(dropDown);
}
protected
override
void
SetContentCore(
object
value)
{
dropDown.DataSource =
new
List<
string
>() {
"item1"
,
"item2"
,
"item3"
};
}
protected
override
Type ThemeEffectiveType
{
get
{
return
typeof
(GridDataCellElement);
}
}
public
override
bool
IsCompatible(GridViewColumn data,
object
context)
{
GridDataRowElement rowElement = context
as
GridDataRowElement;
return
data
is
CustomColumn && rowElement !=
null
&& (rowElement.RowInfo.Index % 2 == 0);
}
}
public
class
CustomColumn : GridViewDataColumn
{
public
CustomColumn(
string
fieldName) :
base
(fieldName)
{
}
public
override
Type GetCellType(GridViewRowInfo row)
{
if
(row
is
GridViewDataRowInfo)
{
if
(row.Index % 2 == 0)
{
return
typeof
(CustomCellElement);
}
else
{
return
typeof
(GridDataCellElement);
}
}
return
base
.GetCellType(row);
}
}
However, note that our RadDropDownListElement hosts the Microsoft TextBox in its editable part when the DropDownStyle is DropDown. Using controls in grid cells may slow down the scrolling and will cause visual glitches (similar to the one demonstrated in your first screenshot). A better option would be using RadDropDownListEditor for specific cells, which can be specified in the EditorRequired event.
I hope this information helps. Should you have further questions, I would be glad to help.
Regards,
Desislava
Telerik
Reference to the subject it is stated that i am facing some issue in Radgridview. i want to insert RadialGauge in Gridview in Telerik UI winform using in Desktop App but it's not working.
it is requested that help / guidance may be provided that how to insert Radial gauge in Rad gridview in Winform.
RadGridView provides a very convenient API for creating custom cells. Thus, you can insert any element that you need, e.g. RadRadialGaugeElement. The following help article demonstrates a sample approach: https://docs.telerik.com/devtools/winforms/controls/gridview/cells/creating-custom-cells
The specific part here is that the gauge needs an XML to load its predefined layout. You can store such a file in advance and then reuse it for the gauge element in the custom cell: https://docs.telerik.com/devtools/winforms/controls/gauges/radialgauge/save-and-load-layout
I hope this information helps. If you need any further assistance please don't hesitate to contact me.
Regards,
Dess | Tech Support Engineer, Sr.
Progress Telerik