Hello,
I had a question in regards to how you need to bind/set the data type of a GridView. When I'm doing column creation, you need to set the data type of the column to all be of one type (i.e. text, date, drop down list, etc). Is there a way around this? Basically I want to have one column be of a general Data type and have each row determine what to put into the cell.
I've attached an image of the "gridview" that I'm trying to recreate in winforms. Any and all help is very much appreciated!
Thanks
45 Answers, 1 is accepted
RadGridView provides a variety of visual cells (all inheriting from GridCellElement) with different functionality and purpose. All these cover the standard cases of the control usage. In case you need to implement more specific and custom scenario, you can create a custom cell. RadGridView provides a powerful and flexible mechanism for creating cell types with custom content elements, functionality and properties. The following help article demonstrates a sample approach how to create a custom cell: https://docs.telerik.com/devtools/winforms/gridview/cells/creating-custom-cells
In the CreateChildElements you can create all possible elements that can be displayed in the column. Then, in the SetContentCore method you can control which elements to be visible or not considering the data row. You can show/hide a certain child element by manipulating its Visibility property. Note that 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. In order to prevent showing some undesired elements for the incorrect data rows, make sure that you hide/show the respective child elements in the SetContentCore method.
I hope this information helps.
Regards,
Dess
Progress Telerik
Thanks for your reply! My only question lies in the part of generating the CellElement object inside the constructor:
Since the constructor requires a column and row parameter, how do they call a parameterless constructor in the CreateChildElements override?
public ProgressBarCellElement(GridViewColumn column, GridRowElement row) : base(column, row)
{
}
private RadProgressBarElement radProgressBarElement;
protected override void CreateChildElements()
{
base.CreateChildElements();
radProgressBarElement = new RadProgressBarElement();
this.Children.Add(radProgressBarElement);
}
My visual studio shows an error that says: There is no argument given that corresponds to the required formal parameter 'column' of 'PNUDFCellElement.PNUDFCellElement(GridViewColumn, GridRowElement)'
Let me know if you have a solution. Thanks!
Here's my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Telerik.WinControls.UI;
namespace Legacymfg.Komodo.PN
{
public class PNUDFCellElement : GridDataCellElement
{
public PNUDFCellElement(GridViewColumn column, GridRowElement row) : base(column, row)
{
}
private PNUDFCellElement udfCellElement;
protected override void CreateChildElements()
{
base.CreateChildElements();
udfCellElement = new PNUDFCellElement();
this.Children.Add(udfCellElement);
}
}
}
The CreateChildElements method is called before the constructor is executed. As it is demonstrated in the referred help article, you need to pass the column and the row in the constructor. I have attached a sample project for your reference.
You can refer to our Demo application >> GridView >> Columns >> Column Types example where the last column is a custom one where the child elements in the cells are added in the CellFormatting event. You can also explore the code by selecting C# or VB on the top right side.
Feel free to use this approach which suits your requirement best.
I hope this information helps.
Regards,
Dess
Progress Telerik
Thank you! I think I was just getting confused since the class is ProgressBarCellElement and then when you're adding child elements it's a RadProgressBarElement... after reading your first reply again I think I understand more.
I think I can figure it out from here -- but I will reply back if I can't! I appreciate the help.
Braden
After looking at the custom (progressbar) example code, I still don't understand how I will bind different data types (datetime, drop down list, text box) into my one column. Here is their code for creating the column:
GridViewDataColumn commandColumn = new GridViewTextBoxColumn();
commandColumn.HeaderText = "Custom";
commandColumn.Name = "ProgressBar";
commandColumn.DataType = typeof(int);
commandColumn.ReadOnly = true;
commandColumn.Width = 100;
this.radGridView1.Columns.Add(commandColumn);
However, my data type will not always be int...is there a way around this? Can I just not set the column data type? Thanks!
To update, I have tried creating a custom cell and populating the children with the proper data controls:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Telerik.WinControls.UI;
namespace Legacymfg.Komodo.PN
{
public class PNUDFCellElement : GridDataCellElement
{
public PNUDFCellElement(GridViewColumn column, GridRowElement row) : base(column, row)
{
}
private RadDropDownListElement radDropDownListElement;
private RadDateTimeEditorElement radDateTimeEditorElement;
private RadTextBoxElement radTextBoxElement;
protected override void CreateChildElements()
{
base.CreateChildElements();
radDropDownListElement = new RadDropDownListElement();
radDateTimeEditorElement = new RadDateTimeEditorElement();
radTextBoxElement = new RadTextBoxElement();
this.Children.Add(radDropDownListElement);
this.Children.Add(radDateTimeEditorElement);
this.Children.Add(radTextBoxElement);
}
protected override void SetContentCore(object value)
{
base.SetContentCore(value);
}
public class CustomDataColumn : GridViewDataColumn
{
public CustomDataColumn(string fieldName) : base(fieldName)
{
}
public override Type GetCellType(GridViewRowInfo row)
{
if (row is GridViewDataRowInfo)
{
return typeof(PNUDFCellElement);
}
return base.GetCellType(row);
}
}
}
}
However, when I try to add the column it is formatted strangely (like there is a big white box over the editable text field -- see attached picture).
GridViewTextBoxColumn Name = new GridViewTextBoxColumn();
Name.Name = "Name_Column";
Name.HeaderText = "Name";
Name.DataType = typeof(string);
Name.MinWidth = 250;
UserDefinedFieldsGridView.MasterTemplate.Columns.Add(Name);
CustomDataColumn customDataColumn = new CustomDataColumn("Data Column");
customDataColumn.HeaderText = "Data";
customDataColumn.Name = "Data_Column";
customDataColumn.DataType = typeof(PNUDFCellElement);
customDataColumn.ReadOnly = true;
customDataColumn.Width = 250;
UserDefinedFieldsGridView.MasterTemplate.Columns.Add(customDataColumn);
Basically my end goal is this: determine which of the 3 options to display for the cell data type (i.e. if the "name" column is DateAdded then the "data" column should be a date time picker. if the name column is something that refers to a drop down list of options, the data column should be a drop down list....etc) and then populate the data column with the appropriate control. If you have an example of something like that it would help a lot! Thanks so much for your help
The ProgressBarCellElement class represents the custom implementation of the cell element in RadGridView. The added RadProgressBarElement is the custom element that is added to Children collection of the cell. It can be any other element that you would like to add, e.g. RadButtonElement, RadLabelElement, RadDateTimePickerElement etc. It is possible to add all of the 3 elements inside a StackLayoutElement which is used as a container. You can find below a sample code snipept demonstrating how to add 3 different elements and show each of them and hiding the rest considering the row index.
public
class
PNUDFCellElement : GridDataCellElement
{
public
PNUDFCellElement(GridViewColumn column, GridRowElement row) :
base
(column, row)
{
}
private
StackLayoutElement stack;
private
RadDropDownListElement radDropDownListElement;
private
RadDateTimeEditorElement radDateTimeEditorElement;
private
RadTextBoxControlElement radTextBoxElement;
protected
override
void
CreateChildElements()
{
base
.CreateChildElements();
stack =
new
StackLayoutElement();
stack.StretchHorizontally =
true
;
stack.Orientation = Orientation.Horizontal;
radDropDownListElement =
new
RadDropDownListElement();
radDropDownListElement.DropDownStyle = Telerik.WinControls.RadDropDownStyle.DropDownList;
radDropDownListElement.StretchHorizontally =
true
;
radDateTimeEditorElement =
new
RadDateTimeEditorElement();
radDateTimeEditorElement.StretchHorizontally =
true
;
radTextBoxElement =
new
RadTextBoxControlElement();
radTextBoxElement.StretchHorizontally =
true
;
stack.Children.Add(radDropDownListElement);
stack.Children.Add(radDateTimeEditorElement);
stack.Children.Add(radTextBoxElement);
this
.Children.Add(stack);
}
protected
override
void
SetContentCore(
object
value)
{
this
.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
this
.radDateTimeEditorElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
this
.DrawText =
false
;
if
(
this
.RowIndex % 3 == 0)
{
this
.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
this
.radDropDownListElement.Text =
this
.Value +
""
;
}
else
if
(
this
.RowIndex % 3 == 1)
{
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
this
.radTextBoxElement.Text =
this
.Value +
""
;
}
else
{
this
.radDateTimeEditorElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
}
base
.SetContentCore(value);
}
public
class
CustomDataColumn : GridViewDataColumn
{
public
CustomDataColumn(
string
fieldName) :
base
(fieldName)
{
}
public
override
Type GetCellType(GridViewRowInfo row)
{
if
(row
is
GridViewDataRowInfo)
{
return
typeof
(PNUDFCellElement);
}
return
base
.GetCellType(row);
}
}
}
However, it is important to note that RadDropDownListElement, RadTextBoxElement and RadDateTimePickerElement host the MS TextBox. Using controls in grid cells may slow down the scrolling and will cause visual glitches as they do not support clipping. This is the result you obtained in the screenshot. Instead of using RadTextBoxElement, feel free to use a RadTextBoxControlElement which doesn't host the MS TextBox. For the RadDropDownListElement, you can set the DropDownStyle property to DropDownList. Thus, the hosted MS TextBox will be hidden and you will be able to select the items from the drop down only. As to the RadDateTimePickerElement, there is not suitable mode that I can suggest in order to hide the hosted TextBox. A better option would be using custom editors. Thus, you can construct the desired editor and activate it for the respective cell.
https://docs.telerik.com/devtools/winforms/gridview/editors/using-custom-editors
https://docs.telerik.com/devtools/winforms/gridview/editors/how-to/change-the-active-editor-depending-on-the-cell-value-type.
I hope this information helps.
Regards,
Dess
Progress Telerik
Is there a way to populate different rows drop down lists from the database? For example...I have a field for Item Category that has text values and then a Freight Class category that has integers.
Here is my code where I'm querying the database for the drop down list options (FldValue - Descr), if it's null (I want to make it a text box), else (populate the drop down list options for that specific row, then show that row, then clear the items for the next iteration).
Instead, I'm left with all of the items as empty drop down lists. FYI - not all of the rows with dataType 'A' have drop down list options... that's where the additional query is looking.
Hashtable itemGrpName =
new
Hashtable();
Hashtable dataType =
new
Hashtable();
foreach
(DataRow dr
in
itemGroupName.Rows)
{
//here we add the value of the field to a hash as the value, with the row index (count) as the key
itemGrpName.Add(count, dr[
"Descr"
]);
dataType.Add(count, dr[
"TypeID"
]);
count++;
}
//loop through all the row indexes, find the data type, and set the elements visibility accordingly
for
(
int
i=0; i<itemGrpName.Count; i++)
{
object
val = dataType[i];
string
data = val.ToString();
//our data type, 'a', 'n', or 'd'
//indices are consistent between the two hashtables...
//now we do our data control setup...
switch
(data)
{
//alphanumeric -- check for drop down options and populate where appropriate
case
"A"
:
string
getDDLoptionsQry =
"select t0.FldValue, t0.Descr from prod.dbo.UFD1 t0 "
+
" join prod.dbo.CUFD t1 on t1.FieldID = t0.FieldID "
+
" where t0.TableID = 'OITM' and t1.TableID = 'OITM' "
+
" and t1.Descr = '"
;
getDDLoptionsQry += itemGrpName[i] +
"'"
;
//check if results are null...
dropDownListTable = SQLDataAccess.DTFromQuery(
"Komodo"
, getDDLoptionsQry);
//if (null): no drop down options, so just populate text box
if
(dropDownListTable.Rows.Count == 0)
{
//show empty text box here
}
//else: drop down options, set them up and show the drop down element
else
{
//List<string> ddlOptionsList = new List<string>();
int
j = 0;
this
.radDropDownListElement.Items.Clear();
foreach
(DataRow dr
in
dropDownListTable.Rows)
{
RadListDataItem ddlDataItem =
new
RadListDataItem();
ddlDataItem.Text = dr[
"FldValue"
].ToString() +
" - "
+ dr[
"Descr"
].ToString();
this
.radDropDownListElement.Items.Insert(j, ddlDataItem);
j++;
//ddlOptionsList.Add(dr["FldValue"].ToString() + " - " + dr["Descr"].ToString());
}
this
.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
this
.radDropDownListElement.Text =
this
.Value +
""
;
}
Let me know if you have any questions/need clarification of the problem! Thanks
Here's what my data looks like (Item Category and then Freight class -- just to give you a better idea of what I'm trying to do)
I tried to clear the items because what was happening originally was that every single row had a drop down list with every single option - which is not what I wanted
Here is what I was referring to (see image) and here is the corresponding code! Another problem is that both the text box and the drop down list are visible...when I only want one or the other depending on what the datatype for that row is:
switch
(data)
{
//alphanumeric -- check for drop down options and populate where appropriate
case
"A"
:
string
getDDLoptionsQry =
"select t0.FldValue, t0.Descr from prod.dbo.UFD1 t0 "
+
" join prod.dbo.CUFD t1 on t1.FieldID = t0.FieldID "
+
" where t0.TableID = 'OITM' and t1.TableID = 'OITM' "
+
" and t1.Descr = '"
;
getDDLoptionsQry += itemGrpName[i] +
"'"
;
//check if results are null...
dropDownListTable = SQLDataAccess.DTFromQuery(
"Komodo"
, getDDLoptionsQry);
//if (null): no drop down options, so just populate text box
if
(dropDownListTable.Rows.Count == 0)
{
//show empty text box here
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
this
.radTextBoxElement.Text =
this
.Value +
""
;
//this.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
}
//else: drop down options, set them up and show the drop down element
else
{
//List<string> ddlOptionsList = new List<string>();
int
j = 0;
//this.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
//this.radDropDownListElement.Items.Clear();
foreach
(DataRow dr
in
dropDownListTable.Rows)
{
RadListDataItem ddlDataItem =
new
RadListDataItem();
ddlDataItem.Text = dr[
"FldValue"
].ToString() +
" - "
+ dr[
"Descr"
].ToString();
this
.radDropDownListElement.Items.Insert(j, ddlDataItem);
j++;
//ddlOptionsList.Add(dr["FldValue"].ToString() + " - " + dr["Descr"].ToString());
}
this
.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
this
.radDropDownListElement.Text =
this
.Value +
""
;
}
Any and all help is greatly appreciated :) Thanks so much
In order to see only the drop down in the custom cell, make sure that the Visibility property is set to Collapsed for the text box in the SetContentCore method. This is the appropriate place to synchronize the displayed data considering the data row of the cell element. As to the items in the drop down, you can also set the DataSource property to a subset of the list that is originally assigned to the drop down in the SetContentCore method. Thus, you can control which items to be visible for the different rows.
I hope this information helps. If you need any further assistance please don't hesitate to contact me.
Regards,
Dess
Progress Telerik
I really appreciate the help! I do have another question regarding the StretchHorizontally property of the RadElements...
My gridview looks like the image below, but obviously I'd like the input fields to stretch and take up the whole column length. Any idea why this is happening?
Also - do you have any example code of setting the DataSource property to be a subset of a drop down list? That would be a great help because I'm just not quite sure how to do that properly.
Thanks! I sincerely appreciate all of your help.
I am also seeing a few other issues:
1) The drop down list selections are getting added multiple times. Here's my code for that part:
See attached image for a visual representation. The Freight Class options should only have numbers - no Yes/No or other options that you can see from the picture.
01.
//maybe we can do a comparison of the RowIndex and the hashtable datatype to figure out what to display...
02.
//set visibility of data column cells depending on the data type of the corresponding ItemGrpName cell
03.
foreach
(
int
index
in
dataType.Keys)
04.
{
05.
if
(index.Equals(
this
.RowIndex))
06.
{
07.
switch
(dataType[index].ToString())
08.
{
09.
case
"A"
:
10.
this
.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
11.
this
.radDropDownListElement.Text =
this
.Value +
""
;
12.
13.
string
getDDLoptionsQry =
"select t0.FldValue, t0.Descr from prod.dbo.UFD1 t0 "
+
14.
" join prod.dbo.CUFD t1 on t1.FieldID = t0.FieldID "
+
15.
" where t0.TableID = 'OITM' and t1.TableID = 'OITM' "
+
16.
" and t1.Descr = '"
;
17.
18.
getDDLoptionsQry += itemGrpName[index] +
"'"
;
19.
20.
//check if results are null...
21.
22.
dropDownListTable = SQLDataAccess.DTFromQuery(
"Komodo"
, getDDLoptionsQry);
23.
24.
//if (null): no drop down options, so just populate text box
25.
26.
if
(dropDownListTable.Rows.Count == 0)
27.
{
28.
//show empty text box here
29.
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
30.
this
.radTextBoxElement.Text =
this
.Value +
""
;
31.
this
.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
32.
}
33.
34.
//else: drop down options, set them up and show the drop down element
35.
else
36.
{
37.
//List<string> ddlOptionsList = new List<string>();
38.
int
j = 0;
39.
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
40.
//this.radDropDownListElement.Items.Clear();
41.
foreach
(DataRow dr
in
dropDownListTable.Rows)
42.
{
43.
44.
RadListDataItem ddlDataItem =
new
RadListDataItem();
45.
ddlDataItem.Text = dr[
"FldValue"
].ToString() +
" - "
+ dr[
"Descr"
].ToString();
46.
this
.radDropDownListElement.Items.Insert(j, ddlDataItem);
47.
j++;
48.
//ddlOptionsList.Add(dr["FldValue"].ToString() + " - " + dr["Descr"].ToString());
49.
}
50.
51.
//this.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
52.
//this.radDropDownListElement.Text = this.Value + "";
53.
54.
}
55.
56.
break
;
57.
case
"B"
:
58.
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
59.
this
.radTextBoxElement.Text =
this
.Value +
""
;
60.
break
;
61.
case
"N"
:
62.
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
63.
this
.radTextBoxElement.Text =
this
.Value +
""
;
64.
break
;
65.
case
"D"
:
66.
this
.radDateTimeEditorElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
67.
break
;
68.
69.
70.
}
71.
}
72.
}
2) I'm also seeing an additional vertical scrollbar in the gridview... I'll demonstrate what I mean in some images. Once I scroll around a bit it appears over the "normal" scrollbar and only moves the gridview up and down instead of the values inside the gridview (hard to explain without showing in real time)
Again, I really appreciate your help through this! It's not easy that's for sure haha.
Regarding your question about having different data displayed in the drop-down list editors, please check the following KB resource discussing a similar setup and suggesting a possible solution rebinding the editor: https://www.telerik.com/support/kb/winforms/gridview/details/cascading-comboboxes-in-radgridview. As for the image with the editors, not filling up the entire width, it appears that they have been arranged in such a way. I am assuming that you might be hiding some of the other elements in the custom cell, in this case instead of hiding set their Visibility property to ElementVisibility.Collapsed. This way the collapsed elements will not be measured and arranged while updating the layout. In the custom cell, it is also possible to override its MeasureOverride and ArrangeOverride methods where you can specify the exact bounds and position of the elements.
As for the grey scrollbar, it might be related to the hierarchy of the custom element. Please note, however, that without actually having your implementation it is hard to make a correct assumption. If it is possible, you can share a code snippet with your implementation and details how it can be tested.
Regards,
Hristo
Progress Telerik
Here is a code snippet of my custom cell class now -- as you can see I am setting the visibility to Collapsed but I am still not seeing the results I have intended. Maybe I will try overriding the Measure/Arrange Override methods and see if I can have success that way.
Let me know if you have any suggestions/ideas for how to implement this! Thanks.
using
Legacymfg.Komodo.Data;
using
System;
using
System.Collections;
using
System.Collections.Generic;
using
System.Data;
using
System.Linq;
using
System.Text;
using
System.Threading.Tasks;
using
System.Windows.Forms;
using
Telerik.WinControls.UI;
namespace
Legacymfg.Komodo.PN
{
public
class
PNUDFCellElement : GridDataCellElement
{
public
PNUDFCellElement(GridViewColumn column, GridRowElement row) :
base
(column, row)
{
}
private
StackLayoutElement stack;
private
RadDropDownListElement radDropDownListElement;
private
RadDateTimeEditorElement radDateTimeEditorElement;
private
RadTextBoxControlElement radTextBoxElement;
DataTable itemGroupName;
DataTable dropDownListTable;
protected
override
void
CreateChildElements()
{
base
.CreateChildElements();
stack =
new
StackLayoutElement();
stack.StretchHorizontally =
true
;
stack.Orientation = Orientation.Horizontal;
radDropDownListElement =
new
RadDropDownListElement();
radDropDownListElement.DropDownStyle = Telerik.WinControls.RadDropDownStyle.DropDownList;
radDropDownListElement.StretchHorizontally =
true
;
radDateTimeEditorElement =
new
RadDateTimeEditorElement();
radDateTimeEditorElement.StretchHorizontally =
true
;
radTextBoxElement =
new
RadTextBoxControlElement();
radTextBoxElement.StretchHorizontally =
true
;
stack.Children.Add(radDropDownListElement);
stack.Children.Add(radDateTimeEditorElement);
stack.Children.Add(radTextBoxElement);
this
.Children.Add(stack);
}
protected
override
void
SetContentCore(
object
value)
{
this
.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
this
.radDateTimeEditorElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
this
.DrawText =
false
;
//here we need to check the corresponding row index (maybe create an array?)
//to determine which data type we want to show for that row
int
count = 0;
Hashtable itemGrpName =
new
Hashtable();
Hashtable dataType =
new
Hashtable();
itemGroupName = MasterDataCache.Instance.UDFDT;
foreach
(DataRow dr
in
itemGroupName.Rows)
{
//here we add the value of the field to a hash as the value, with the row index (count) as the key
itemGrpName.Add(count, dr[
"Descr"
]);
dataType.Add(count, dr[
"TypeID"
]);
count++;
}
/*
//now here we need to check the row index against the hash values and verify we are showing the right data field(s)
//if it's a drop down list that should also be handled (options)
//first, get the data field type from the database, add that to another hash? or?
//key the item group name and data type on the same index...or try to
//then, check row index against the hash and display the right data control
// A = alphanumeric
// N = numeric
// D = datetime
*/
//maybe we can do a comparison of the RowIndex and the hashtable datatype to figure out what to display...
//set visibility of data column cells depending on the data type of the corresponding ItemGrpName cell
foreach
(
int
index
in
dataType.Keys)
{
if
(index.Equals(
this
.RowIndex))
{
switch
(dataType[index].ToString())
{
case
"A"
:
string
getDDLoptionsQry =
"select t0.FldValue, t0.Descr from prod.dbo.UFD1 t0 "
+
" join prod.dbo.CUFD t1 on t1.FieldID = t0.FieldID "
+
" where t0.TableID = 'OITM' and t1.TableID = 'OITM' "
+
" and t1.Descr = '"
;
getDDLoptionsQry += itemGrpName[index] +
"'"
;
//check if results are null...
dropDownListTable = SQLDataAccess.DTFromQuery(
"Komodo"
, getDDLoptionsQry);
//if (null): no drop down options, so just populate text box
if
(dropDownListTable.Rows.Count == 0)
{
//show empty text box here
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
this
.radTextBoxElement.Text =
this
.Value +
""
;
this
.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
}
//else: drop down options, set them up and show the drop down element
else
{
//List<string> ddlOptionsList = new List<string>();
int
j = 0;
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
this
.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
this
.radDropDownListElement.Text =
this
.Value +
""
;
//this.radDropDownListElement.Items.Clear();
foreach
(DataRow dr
in
dropDownListTable.Rows)
{
RadListDataItem ddlDataItem =
new
RadListDataItem();
ddlDataItem.Text = dr[
"FldValue"
].ToString() +
" - "
+ dr[
"Descr"
].ToString();
this
.radDropDownListElement.Items.Insert(j, ddlDataItem);
j++;
//ddlOptionsList.Add(dr["FldValue"].ToString() + " - " + dr["Descr"].ToString());
}
//this.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
//this.radDropDownListElement.Text = this.Value + "";
}
break
;
case
"B"
:
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
this
.radTextBoxElement.Text =
this
.Value +
""
;
break
;
case
"N"
:
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
this
.radTextBoxElement.Text =
this
.Value +
""
;
break
;
case
"D"
:
this
.radDateTimeEditorElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
this
.radDateTimeEditorElement.Text =
""
;
break
;
}
}
}
base
.SetContentCore(value);
}
public
class
CustomDataColumn : GridViewDataColumn
{
public
CustomDataColumn(
string
fieldName) :
base
(fieldName)
{
}
public
override
Type GetCellType(GridViewRowInfo row)
{
if
(row
is
GridViewDataRowInfo)
{
return
typeof
(PNUDFCellElement);
}
return
base
.GetCellType(row);
}
}
}
}
Also, here is my code in the Form to generate the columns and row data :
See the attached picture to see how it looks in my application. Thanks!
private
void
PopulateUDFGridViewRows()
{
//clear it first
UserDefinedFieldsGridView.Rows.Clear();
udfTable = MasterDataCache.Instance.UDFDT;
foreach
(DataRow dr
in
udfTable.Rows)
{
GridViewDataRowInfo rowInfo =
new
GridViewDataRowInfo(
this
.UserDefinedFieldsGridView.MasterView);
rowInfo.Cells[0].Value = dr[
"Descr"
];
//figure out what type of control we need...
//i.e. text field, drop down list (combobox), or date (datetime)
UserDefinedFieldsGridView.Rows.Add(rowInfo);
}
}
private
void
PopulateUDFGridViewColumns()
{
UserDefinedFieldsGridView.Columns.Clear();
UserDefinedFieldsGridView.AutoGenerateColumns =
false
;
GridViewTextBoxColumn Name =
new
GridViewTextBoxColumn();
Name.Name =
"Name_Column"
;
Name.HeaderText =
"Name"
;
Name.DataType =
typeof
(
string
);
Name.MinWidth = 250;
UserDefinedFieldsGridView.MasterTemplate.Columns.Add(Name);
CustomDataColumn customDataColumn =
new
CustomDataColumn(
"Data Column"
);
customDataColumn.HeaderText =
"Data"
;
customDataColumn.Name =
"Data_Column"
;
customDataColumn.DataType =
typeof
(PNUDFCellElement);
customDataColumn.ReadOnly =
true
;
customDataColumn.Width = 500;
UserDefinedFieldsGridView.MasterTemplate.Columns.Add(customDataColumn);
}
As for testing, I'm not really sure how you would go about this since a lot of these forms/databases have underlying requirements you would need...but I'm thinking the idea should be the same. You can probably bind some test data to this (although I am binding it programmatically and not using any data binding code (just querying/getting results/assigning to variables etc).
If you have any further questions don't hesitate to ask! Thanks again
I have figured out the multiple(s) in the drop down list being added as I scroll (just needed to clear it before I added items in).
I still need help figuring out the collapsed spacing (they are not being hidden properly and I am using the Collapse property), and the additional gray scroll bar! Please assist me if you can.
Thanks,
Braden
I looked further into the layout of the custom cell and it appears that there is an issue with the StackLayoutElement object. The issue is that the stack layout will also arrange the elements which are with a collapsed visibility. The item is logged on our feedback portal, here: FIX. TPF - the StackLayoutElement should respect the Visibility of the elements when arranging them. I have also updated your Telerik points. The issue is already being investigated and we will try to include a fix for it in the upcoming service pack release scheduled for later this month.
A possible workaround is to use a custom StackLayoutElement as in the code snippet below:
public
class
CustomStackLayoutElement : StackLayoutElement
{
protected
override
void
ArrangeHorizontally(SizeF finalSize)
{
RectangleF clientRect =
this
.GetClientRectangle(finalSize);
float
stretchableWidth = 0;
int
stretchableCount = 0;
int
nonStretchableItems = 0;
foreach
(RadElement element
in
this
.Children)
{
if
(element.Visibility == ElementVisibility.Collapsed)
{
continue
;
}
if
(element.StretchHorizontally)
{
stretchableCount++;
}
else
{
stretchableWidth += element.DesiredSize.Width;
nonStretchableItems++;
}
}
if
(nonStretchableItems > 0)
{
stretchableWidth += ElementSpacing * (nonStretchableItems - 1);
}
int
spacing =
this
.ElementSpacing;
if
(stretchableCount > 0)
{
stretchableWidth = (clientRect.Width - stretchableWidth) / stretchableCount;
stretchableWidth -= spacing * stretchableCount;
}
ArrangeItemsHorizontaly(clientRect, finalSize, stretchableWidth, spacing);
}
protected
override
void
ArrangeItemsHorizontaly(RectangleF clientRect, SizeF finalSize,
float
stretchableWidth,
float
spacing)
{
float
x = clientRect.X;
float
y = clientRect.Y;
List<RadElement> children =
new
List<RadElement>(
this
.Children);
if
(
this
.Comparer !=
null
)
{
children.Sort(
this
.Comparer);
}
for
(
int
i = 0; i < children.Count; i++)
{
RadElement element =
null
;
if
(
this
.RightToLeft &&
this
.RightToLeftMode == RightToLeftModes.ReverseItems)
{
element = children[children.Count - i - 1];
}
else
{
element = children[i];
}
if
(element.Visibility == ElementVisibility.Collapsed)
{
continue
;
}
RectangleF proposedRect =
new
RectangleF(x, y, stretchableWidth, clientRect.Height);
RectangleF finalRect = AlignRect(element, proposedRect);
if
(
this
.RightToLeft &&
this
.RightToLeftMode == RightToLeftModes.ReverseOffset)
{
finalRect.X = finalSize.Width - x - finalRect.Width;
}
this
.ArrangeElement(element, clientRect, finalRect, finalSize);
x += finalRect.Width + spacing;
}
}
}
public
class
PNUDFCellElement : GridDataCellElement
{
public
PNUDFCellElement(GridViewColumn column, GridRowElement row) :
base
(column, row)
{
}
private CustomStackLayoutElement stack;
private
RadDropDownListElement radDropDownListElement;
private
RadDateTimeEditorElement radDateTimeEditorElement;
private
RadTextBoxControlElement radTextBoxElement;
protected
override
void
CreateChildElements()
{
base
.CreateChildElements();
stack =
new CustomStackLayoutElement();
stack.StretchHorizontally =
true
;
stack.Orientation = Orientation.Horizontal;
radDropDownListElement =
new
RadDropDownListElement();
radDropDownListElement.DropDownStyle = Telerik.WinControls.RadDropDownStyle.DropDownList;
radDropDownListElement.StretchHorizontally =
true
;
radDateTimeEditorElement =
new
RadDateTimeEditorElement();
radDateTimeEditorElement.StretchHorizontally =
true
;
radTextBoxElement =
new
RadTextBoxControlElement();
radTextBoxElement.StretchHorizontally =
true
;
stack.Children.Add(radDropDownListElement);
stack.Children.Add(radDateTimeEditorElement);
stack.Children.Add(radTextBoxElement);
this
.Children.Add(stack);
}
protected
override
void
SetContentCore(
object
value)
{
this
.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
this
.radDateTimeEditorElement.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
this
.DrawText =
false
;
if
(
this
.RowIndex % 3 == 0)
{
this
.radDropDownListElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
this
.radDropDownListElement.Text =
this
.Value +
""
;
}
else
if
(
this
.RowIndex % 3 == 1)
{
this
.radTextBoxElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
this
.radTextBoxElement.Text =
this
.Value +
""
;
}
else
{
this
.radDateTimeEditorElement.Visibility = Telerik.WinControls.ElementVisibility.Visible;
}
base
.SetContentCore(value);
}
}
public
class
CustomDataColumn : GridViewDataColumn
{
public
CustomDataColumn(
string
fieldName) :
base
(fieldName)
{
}
public
override
Type GetCellType(GridViewRowInfo row)
{
if
(row
is
GridViewDataRowInfo)
{
return
typeof
(PNUDFCellElement);
}
return
base
.GetCellType(row);
}
}
I hope this will help. Let me know if you have other questions.
Regards,
Hristo
Progress Telerik
Thank you Hristo!
I greatly appreciate your feedback on this issue. If you have any feedback related to the additional grey scrollbar (or maybe that is also related to the custom element hierarchy?)
I will try and implement the workaround in the meantime.
Appreciatively,
Braden
I am not able to observe the grey scrollbar in my test project using the custom column and cell from my previous snippet. I have attached a screenshot for reference. In case the scrollbar issue persists, please try and isolate it in a runnable sample and post your code snippet here.
Regards,
Hristo
Progress Telerik
I will try and implement the CustomStackLayoutElement implementation and see if that eliminates the additional scrollbar.
Thanks again,
Braden
When I am trying to create the CustomStackLayoutElement class, I am getting some errors on the methods I am trying to override.
Here is the error: 'CustomStackLayoutElement.ArrangeItemsHorizontaly(RectangleF, SizeF, float, float)': no suitable method found to override.
This same error is happening for ArrangeHorizontally method.
Here is my current code, please let me know what I am doing wrong! Thanks
using
System;
using
System.Collections.Generic;
using
System.Drawing;
using
System.Linq;
using
System.Text;
using
System.Threading.Tasks;
using
Telerik.WinControls;
using
Telerik.WinControls.UI;
using
Telerik.WinForms.Documents.Model;
namespace
Legacymfg.Komodo.PN
{
public
class
CustomStackLayoutElement : StackLayoutElement
{
protected
override
void
ArrangeHorizontally(SizeF finalSize)
{
Telerik.WinForms.Documents.Model.RectangleF clientRect =
this
.GetClientRectangle(finalSize);
float
stretchableWidth = 0;
int
stretchableCount = 0;
int
nonStretchableItems = 0;
foreach
(RadElement element
in
this
.Children)
{
if
(element.Visibility == ElementVisibility.Collapsed)
{
continue
;
}
if
(element.StretchHorizontally)
{
stretchableCount++;
}
else
{
stretchableWidth += element.DesiredSize.Width;
nonStretchableItems++;
}
}
if
(nonStretchableItems > 0)
{
stretchableWidth += ElementSpacing * (nonStretchableItems - 1);
}
int
spacing =
this
.ElementSpacing;
if
(stretchableCount > 0)
{
stretchableWidth = (clientRect.Width - stretchableWidth) / stretchableCount;
stretchableWidth -= spacing * stretchableCount;
}
ArrangeItemsHorizontaly(clientRect, finalSize, stretchableWidth, spacing);
}
protected
override
void
ArrangeItemsHorizontaly(Telerik.WinForms.Documents.Model.RectangleF clientRect, Telerik.WinForms.Documents.Model.SizeF finalSize,
float
stretchableWidth,
float
spacing)
{
float
x = clientRect.X;
float
y = clientRect.Y;
List<RadElement> children =
new
List<RadElement>(
this
.Children);
if
(
this
.Comparer !=
null
)
{
children.Sort(
this
.Comparer);
}
for
(
int
i = 0; i < children.Count; i++)
{
RadElement element =
null
;
if
(
this
.RightToLeft &&
this
.RightToLeftMode == RightToLeftModes.ReverseItems)
{
element = children[children.Count - i - 1];
}
else
{
element = children[i];
}
if
(element.Visibility == ElementVisibility.Collapsed)
{
continue
;
}
Telerik.WinForms.Documents.Model.RectangleF proposedRect =
new
RectangleF(x, y, stretchableWidth, clientRect.Height);
RectangleF finalRect = AlignRect(element, proposedRect);
if
(
this
.RightToLeft &&
this
.RightToLeftMode == RightToLeftModes.ReverseOffset)
{
finalRect.X = finalSize.Width - x - finalRect.Width;
}
this
.ArrangeElement(element, clientRect, finalRect, finalSize);
x += finalRect.Width + spacing;
}
}
}
}
I was using the telerik SizeF and RectangleF not the System.Drawing.Class that I needed to be. Will let you know if I have any other problems.
Thanks
I have fixed the data column so it looks like I want it! I am still having trouble getting rid of this gray scroll bar though....
Here is a picture of my form now. Let me know if you can provide any additional insight as I need to figure this issue out!
Thanks,
Braden
Can you show me what properties are set in your RadGridView? Maybe it's something I have set that you don't which is causing this. Otherwise I'm not quite sure how to isolate this code in a runnable sample so you can see what I am seeing...
If you have any suggestions let me know!
Thanks
I just had to set the AutoScroll property to False. That fixed it.
Thanks,
Braden
Indeed, the grey scrollbar appeared as the default one affected by the AutoScroll property. I am glad that you managed to resolve the issue.
Regards,
Hristo
Progress Telerik
I still have one more question, and I hope you can answer it...
What I need now is to set the data in the cell based off of the item I am looking at.
Here's how the data looks visually:
PN Item Master Form (holds the UDF Gridview)
UDF Gridview (holds a "Name" column with the user defined field category, and then the "data" column -- custom column holding custom cell element -- with the date picker, drop down menu, etc)
So...my question is this: Is there a way to pass the item code to the PNUDF cell element class so I can set the text of the element to equal what I am seeing in the database? Right now I am populating the drop down menu from another table which I'm not sure how to join (that's obviously a database issue that you can't see...) but I need to get this value from the database somehow keyed off the item code (that is a parameter of the parent PN Item Master class -- the form shows an instance of this class, if that makes sense)
Here's an example of how I want the UDF fields to look (look at the table on the right and notice how those fields are pre-populated with data corresponding to what's in the database field)
Thanks!
You can use the Tag property of the row to store some special data and use it in the custom cell. A suitable place to access this value is the SetContentCore method of the cell:
protected
override
void
SetContentCore(
object
value)
{
string
customValue = (
string
)
this
.RowInfo.Tag;
//...
base
.SetContentCore(value);
}
Regards,
Hristo
Progress Telerik
So I am trying to set a "default" drop down list/textbox text that shows what is currently assigned in the database. Here's my test code where I'm just trying to see if I can get the RowInfo.Tag to show up...maybe I am not doing this correctly.
Please let me know as soon as possible.
Again, I really appreciate all of your help through this!
this
.RowInfo.Tag =
"Brady was here"
;
Here is a little bit better explanation of what I am trying to accomplish.
I have an Item Object (myItem) that has a property of type PNUDF (user defined fields object). This contains all of the UDFs from the database (see attached picture -- itemUDF)
Then what I want to do is pass this object into the PNUDFCellElement class (custom cell) and use the item object and UDF property to pre-populate the data inside my Gridview... if that makes sense.
Is something like this possible? I'm just not sure how to code that up... or how to pass the item object from the form into the gridview custom cell class!
Any help is greatly appreciated -- and I'd be happy to share my code (but I've already shown most of it previously).
Thanks!
Braden
It is possible to store all of the information in the MyUDF object in the Tag property of the row. You can access each of the rows in the grid and set the custom object, e.g. like this:
this
.radGridView1.Rows[10].Tag =
"YourCustomObject"
;
Then similar to my previous code snippet, you can access the Tag property in the custom cell and set the fields of the different elements.
I hope this will help.
Regards,
Hristo
Progress Telerik
Thanks! This makes more sense now. I will attempt to implement this today and let you know if I have success.
I appreciate all the help.
Braden
Awesome! That worked great. The only issue I'm running into is that the RadDateTimeEditorElement is not getting set properly. The only thing I can think of is that the date/time strings have different formats... for example:
In the database (and on my UDF object) the datetime string looks like this: MM/DD/YYYY HH:MM:SS AM/PM
ex: 11/7/2006 12:00:00 AM
And the text in the RadDateTimeEditorElement looks like this: Thursday, October 11, 2018
Here's how I'm doing it in my code:
uAlias =
"U_"
+ aliasID[index].ToString();
//loop through all the properties on our UDF Object (every UDF field) until we find the right one
foreach
(PropertyInfo prop
in
customUDFObj.GetType().GetProperties())
{
//compare alias at our index to the property name...
if
(uAlias.ToString().Equals(prop.Name.ToString()))
{
//if they are equal,
//set the text value equal to what we have in the udf object for that aliasID
PropertyInfo property =
typeof
(PNUDF).GetProperty(uAlias);
object
obj = property.GetValue(customUDFObj);
this
.radDateTimeEditorElement.Text = obj.ToString();
}
}
Any and all help is appreciated as always! I'm so close to what result I want haha I couldn't have done it without you!
I am glad that the Tag property would work for your scenario. As for the DateTime editor element, you can set the format this way:
this
.radDateTimeEditorElement.Format = DateTimePickerFormat.Custom;
this
.radDateTimeEditorElement.CustomFormat =
"MM/dd/yyyy hh:mm:ss tt"
;
Regards,
Hristo
Progress Telerik
That is still not working, as I'm seeing the current date/time stamp in my data cell...
See the attached picture for what I'm seeing in debug mode. It's showing me that the code is setting the datetimeeditorelement text to be "11/7/2006 12:00:00 AM" but when the gridview loads it shows "10/12/2018 11:27:00 AM" (current time here when I'm writing this).
Any help would be greatly appreciated as I'm not sure what other property I would need to set for this to show correctly!
Thanks,
Braden
Please set the Value of the date time editor element and not its text. If you are having the value stored in your object as a string you can use the DateTime.Parse method to receive a DateTime object: https://docs.microsoft.com/en-us/dotnet/standard/base-types/parsing-datetime.
Regards,
Hristo
Progress Telerik
Awesome! Thanks so much Hristo. I really appreciate all your help through this process.
I've attached an updated picture of what it looks like! Finally got it working as expected.
Thanks again,
Braden
Thank you for the update. I am glad that I managed to help and that you have achieved the desired behavior in your actual project. Let me know if you will be needing further assistance.
Regards,
Hristo
Progress Telerik