Hi.
I'd like to bind the DataTable (contains a single DataRow) to radPropertyGrid: each row in radPropertyGrid should represent sequental value from DataRow. As I've understood it is quite possible. But I also want to add IsReadOnly and Category attributes to each property created this way. I have arrays of appropriate length where there each value should be applied to same index's attributes of (DataRow value as Property) in radPropertyGrid.
Moreover I have plans to get changes from this radPropertyGrid to create an update statement for my database.
I'm afraid I'm not quite skilled to complete these tasks without some help as I have some problems with understanding TypeDescriptors, TypeProviders etc.
Could you please give me any tips?
17 Answers, 1 is accepted
To be more specific: I've tried to use solution of Marc Gravell from here: http://stackoverflow.com/questions/943621/c-winforms-how-to-best-bind-a-propertygrid-and-a-system-data-datarow
It works in .NET propertyGrid although I did not understand where should I place my code to apply required values for attributes as those overrides give me readonly attributes only.
Unfortunatelly the example does not work for radPropertyGrid and my head is spinning round around from all those unknown words.
Thank you for writing.
I don't think that RadPropertyGrid is the appropriate control for this case with DataTable. RadPropertyGrid for WinForms displays the properties of a given object in a user-friendly way allowing the end-user to edit these properties using our editors. You can consider using RadGridView.
However, if you need displaying the data just for a single row, I would recommend you to use a RadPropertyStore and populate it with the desired items: http://docs.telerik.com/devtools/winforms/propertygrid/radpropertystore---adding-custom-properties
I hope this information helps. Should you have further questions I would be glad to help.
Regards,
Dess
Telerik by Progress
Actually in my project there are two cases: one for single row and one for multiple rows. So I definitely going to use RadGridView for second case.
As of RadPropertyStore - it seems to be the way, I haven't seen it in demo. Thanks a lot, I'll reply again soon.
RadPropertyStore truly is the solution I've needed. You are awesome.
Two more lil questions in here:
1) how should I implement my custom typed collections (int, string) so the RadPropertyGrid would auto use comboBox, when I feed the appropriate type right in PropertyStoreItem creation (without EditorRequired event handling)? I used type-safe-enum before but I guess it can be redone into for ex. Dictionary<int, string> or whatever;
2) where could I check the list of all available Editors to apply? some of my collections should allow more than one value checked so there is some math behind and I used slightly modified .NET ListView before (with multiselect set to true).
Thank you for writing back.
Our Demo application >> PropertyGrid >> Property Store example is quite useful on this topic as well. It demonstrates how to add items specifying different categories. The Demo application is located in the installation folder which is usually located at the following path: C:\Program Files (x86)\Telerik\UI for WinForms Q2 2016\Examples\QuickStart\Bin
I hope this information helps. If you have any additional questions, please let me know.
Regards,
Dess
Telerik by Progress
Thank you for writing back.
Yes, now your message is visible.
1. As you have already found out the appropriate solution to specify the editor is handling the EditorRequired event. Additionally, you are allowed to add attributes, including EditorAttribute as well:
PropertyStoreItem stringItem =
new
PropertyStoreItem(
typeof
(
string
),
"String"
,
"telerik"
,
"Property storing a string value"
);
stringItem.Attributes.Add(
new
EditorAttribute(
typeof
(PropertyGridDropDownListEditor),
typeof
(BaseInputEditor) ));
However, in order to populate the editor with data, it would be necessary to handle the EditorInitialized event. The following forum post is quite useful on this topic: http://www.telerik.com/forums/how-to-use-standard-editors-with-runtime-added-properties
2. The available editors in RadPropertyGrid are listed in the following help article: http://docs.telerik.com/devtools/winforms/propertygrid/editors/overview
Note that if you need some other editor type, feel free to create a custom editor.
I hope this information helps. If you have any additional questions, please let me know.
Regards,
Dess
Telerik by Progress
Great. I'm completely satisfied with your answers.
It's a pleasure to deal with you. Thanks again and have a nice day!
And again I have to ask.
PropertyStoreItems are created this way:
1.
var item =
new
PropertyStoreItem(fd.EnumType ?? column.DataType, column.ColumnName, dt.Rows[0][i], column.ColumnName, fd.Categorie.ToString(), i == 0);
where enums for EnumType looks like this:
1.
public
enum
TrainerType
{
Class = 0, Mounts = 1, Tradeskills = 2, Pets = 3 }This way RadPropertyGrid uses the PropertyGridDropDownListEditor automatically.
For the first use I create all items, for the next times i reuse existing by changing item.Value to needed.
Though there is an issue: in RadPropertyGrid if I want to reset changed value to defalut I use the context menu; It works well if fd.EnumType was null. But if not (so the item should use my enum and object value from DataTable dt), the Editor uses not the first loaded value as default but the first selected value as default. This behaviour only applied to first load - I mean in case the item is reused the reset function works properly.
Am I doing it wrong?
OK, I localized the issue. The problem is I'm trying to use object value instead of custom type value:
1.
dt.Rows[0][i] instead of, say, Enum.Value0
I guess the variable is used to setup SelectedValue of comboBox. I've thought though it is possible to use direct value here.
The case was solved by using following syntax: Enum.ToObject(EnumType, dt.Rows[0][i])
I stuck at different point now: when I collect changes from RadPropertyGrid the cells' values which are binded to my enums are string values of enum, not int. I mean that for, say, enum Enum1 { Item0 = 0, Item1 = 1 } RadPropertyGridItem.Value is Item0 whilst expected is 0. The RadPropertyGrid still displays the expected "Item0".
Have to use rather ugly construction to get int enum value back:
1.
(
int
)Enum.Parse((Type) item.Tag, item.Value.ToString())
Another closed door: I cannot find a way to get current RadPropertyGrid from inside of EditorRequired/EditorInitialized events.
Thank you for writing back.
Here is demonstrated how to setup the PropertyStoreItem correctly when using an enum type. Thus, when the editor is activated, the correct value is selected:
PropertyStoreItem enumItem =
new
PropertyStoreItem(
typeof
(TrainerType),
"MyItem"
, 2);
RadPropertyStore store =
new
RadPropertyStore();
store.Add(enumItem);
this
.radPropertyGrid1.SelectedObject = store;
public
enum
TrainerType
{
Class = 0,
Mounts = 1,
Tradeskills = 2,
Pets = 3
}
An alternative approach is to specify the value by using the enum as follows:
PropertyStoreItem enumItem =
new
PropertyStoreItem(
typeof
(TrainerType),
"MyItem"
, TrainerType.Tradeskills);
Note that if the initialized editor's value is not correct, this means that that property item's value is not the expected type. It is necessary to handle the EditorInitialized event and set the BaseDropDownListEditorElement.SelectedIndex:
private
void
radPropertyGrid1_EditorInitialized(
object
sender, PropertyGridItemEditorInitializedEventArgs e)
{
PropertyGridDropDownListEditor ddl = e.Editor
as
PropertyGridDropDownListEditor;
if
(ddl !=
null
)
{
BaseDropDownListEditorElement el = ddl.EditorElement
as
BaseDropDownListEditorElement;
el.SelectedIndex = 1;
}
}
If you are experiencing any further difficulties, it would be greatly appreciated if you can provide a full code snippet which would be enough to build a runnable project. Thank you.
I hope this information helps. If you have any additional questions, please let me know.
Regards,
Dess
Telerik by Progress
Thank you for your patience and have my apologises for any misunderstanding: English is not my mother tongue so I'm doing my best.
I've overcomed the previous problems already. Currently my questions are:
1) how could I reach the current RadPropertyGrid instance from inside of EditorRequired/EditorInitialized events? I did a workaround by setting up the Tag property but I wonder if there is another way;
2) what is the right way of using RadPopupEditor inside the RadPropertyGrid? Back in days I used custom WinForm that was called on button click in the .NET PropertyGrid; now I try to inherit the RadPopupContainer in designer to make it contain everything I need; I've red the examples found on google but I am still not sure of how to apply it now.
Here is the code with all my doubts:
01.
private
void
OnEditorRequired(
object
sender, PropertyGridEditorRequiredEventArgs e)
02.
{
03.
var item = e.Item
as
PropertyGridItem;
04.
var te = sender
as
PropertyGridTableElement;
05.
06.
if
(te !=
null
&& e.EditorType ==
typeof
(PropertyGridSpinEditor))
07.
{
08.
if
(e.Item.Name ==
"InhabitType"
)
//add binary flag editor
09.
{
10.
//here I try to create PopupEditor
11.
var pEditor =
new
RadPopupEditor();
12.
//PickPopupContainer inherits PopupContainer with only adding all needed controls
13.
var container =
new
PickPopupContainer();
14.
pEditor.SetAssociatedControlRuntime(container);
15.
//here I'm stuck currently
16.
//e.Editor = (IValueEditor)pEditor; //?
17.
//here I have to use workaround you created a while ago to prevent rounding
18.
}
19.
else
//fix double values being rounded
20.
{
21.
var dtype = item.PropertyType;
22.
if
(dtype ==
typeof
(
double
) || dtype ==
typeof
(
float
))
23.
{
24.
var editor =
new
FixRoundPropertyGridSpinEditor();
25.
((BaseSpinEditorElement)editor.EditorElement).DecimalPlaces = 4;
26.
e.Editor = editor;
27.
}
28.
}
29.
}
30.
//add dropdown requirement on enum
31.
//ExTag is simply Dictionary<string, object> to extend Tag functionality
32.
var ex = te.PropertyGridElement.Tag
as
ExTag;
33.
if
(ex ==
null
)
return
;
34.
var tw = ex.Get(
"tw"
)
as
TableWrapper;
35.
//my current workaround to reach the RadPropertyGrid instance is to extend Tag and to set it at RadPropertyStore creation
36.
var prop = ex.Get(
"prop"
)
as
RadPropertyGrid;
37.
var store = prop.SelectedObject
as
RadPropertyStore;
38.
//here I have to access the store instead of RadPropertyGrid.Items to get the real item index because if RadPropertyGrid is filtered those items list is not full
39.
var index = store.TakeWhile(storeItem => storeItem.PropertyName != item.Name).Count();
40.
if
(!tw.EnumTypeIndex.ContainsKey(index))
return
;
41.
//the item index required in my case to get the appropriate enum (I have many)
42.
e.EditorType =
typeof
(PropertyGridDropDownListEditor);
43.
e.Item.Tag = tw.EnumTypeIndex[index];
44.
}
Thank you for writing.
You can find in the following code snippet how to access the RadPropertyGrid in the EditorRequired event:
private
void
radPropertyGrid1_EditorRequired(
object
sender, PropertyGridEditorRequiredEventArgs e)
{
PropertyGridTableElement tableElement = sender
as
PropertyGridTableElement;
if
(tableElement!=
null
)
{
RadPropertyGrid propertyGrid = tableElement.ElementTree.Control
as
RadPropertyGrid;
RadPropertyGrid propertyGrid2 =
this
.radPropertyGrid1;
}
}
As to the question about using a RadPopupEditor, it is appropriate to create a custom editor. A sample approach is demonstrated in the following code snippet:
private
void
radPropertyGrid1_EditorRequired(
object
sender, PropertyGridEditorRequiredEventArgs e)
{
if
(e.EditorType ==
typeof
(PropertyGridSpinEditor))
{
e.Editor =
new
CustomBaseInputEditor();
}
}
public
class
CustomBaseInputEditor : BaseInputEditor
{
RadPopupEditor popupEditor =
new
RadPopupEditor();
RadPopupContainer container =
new
RadPopupContainer();
RadGridView grid =
new
RadGridView();
public
override
object
Value
{
get
{
if
(grid.CurrentRow !=
null
)
{
return
(
int
)grid.CurrentRow.Cells[0].Value;
}
return
-1;
}
set
{
foreach
(GridViewDataRowInfo row
in
grid.Rows)
{
if
((
int
)row.Cells[0].Value==(
int
)value)
{
grid.CurrentRow = row;
break
;
}
}
}
}
protected
override
Telerik.WinControls.RadElement CreateEditorElement()
{
grid.Dock = DockStyle.Fill;
grid.DataSource = GetData();
container.Controls.Add(grid);
popupEditor.SetAssociatedControlRuntime(container);
RadHostItem host =
new
RadHostItem(popupEditor);
return
host;
}
private
object
GetData()
{
DataTable dt =
new
DataTable();
dt.Columns.Add(
"Id"
,
typeof
(
int
));
dt.Columns.Add(
"Name"
,
typeof
(
string
));
for
(
int
i = 0; i < 10; i++)
{
dt.Rows.Add(i,
"Item"
+ i);
}
return
dt;
}
public
override
Type DataType
{
get
{
return
typeof
(
int
);
}
}
}
Note that this is just a sample approach and it may not cover all possible cases. Feel free to modify it in a way which suits your requirement best.
I hope this information helps. Should you have further questions I would be glad to help.
Regards,
Dess
Telerik by Progress
Thanks again. Finally I was able to understand a bit more and make it work.
And yet this is not over: in desire to make it look smooth I found AutoSize option for both PopupEditor and the RadGridView inside. I've tried to set AutoSize in different positions (before setting dataSource, after, before adding control to Popup, after and so on), tried also to set MaxSize/MinSize but the best I could reach is proper autosizing on second click on editor: any first click autosizes the grid inside but the Popup is not autosized. I guess I understand why is it happening but I don't know the way to fix it.
First click: http://prntscr.com/c3vfm2
Second click: http://prntscr.com/c3vfra
Some datasources are less, some are wide: so I'd like to autosize both RadGridView and PopupEditor accordingly limiting by MaxSize, in which case VerticalScroll should be available in RadGridView.
01.
protected
override
RadElement CreateEditorElement()
02.
{
03.
var nameCol =
new
GridViewTextBoxColumn(
"Value"
)
04.
{
05.
FieldName =
"Name"
,
06.
Width = 100,
07.
ReadOnly =
true
08.
};
09.
var checkCol =
new
GridViewCheckBoxColumn(
"State"
)
10.
{
11.
Width = 50,
12.
ReadOnly =
false
,
13.
EditMode = EditMode.OnValueChange,
14.
EnableHeaderCheckBox =
true
15.
};
16.
var valueCol =
new
GridViewTextBoxColumn
17.
{
18.
IsVisible =
false
,
19.
FieldName =
"Code"
20.
};
21.
_grid.Columns.Add(nameCol);
22.
_grid.Columns.Add(checkCol);
23.
_grid.Columns.Add(valueCol);
24.
//_grid.DataSource = _dataSource;
25.
_grid.GridViewElement.DrawBorder =
false
;
26.
_grid.GridViewElement.GroupPanelElement.DrawBorder =
false
;
27.
//_container.AutoSize = true;
28.
_container.Controls.Add(_grid);
29.
_grid.DataSource = _dataSource;
30.
_container.AutoSize =
true
;
31.
_popupEditor.SetAssociatedControlRuntime(_container);
32.
var host =
new
RadHostItem(_popupEditor);
33.
return
host;
34.
}
35.
36.
public
override
Type DataType =>
typeof
(
int
);
37.
38.
private
readonly
RadPopupEditor _popupEditor =
new
RadPopupEditor();
39.
40.
private
readonly
RadPopupContainer _container =
new
RadPopupContainer
41.
{
42.
//Size = new Size(152, 75),
43.
MinimumSize =
new
Size(100, 50),
44.
MaximumSize =
new
Size(170, 500)
45.
46.
//AutoSize = true
47.
};
48.
49.
private
readonly
int
_limit;
50.
private
readonly
object
_dataSource;
51.
52.
private
readonly
RadGridView _grid =
new
RadGridView
53.
{
54.
//Size = new Size(100, 200),
55.
MinimumSize =
new
Size(100, 50),
56.
MaximumSize =
new
Size(165, 500),
57.
AutoSize =
true
,
58.
//AllowEditRow = false,
59.
ShowRowHeaderColumn =
false
,
60.
ShowGroupPanel =
false
,
61.
AllowColumnReorder =
false
,
62.
AllowColumnChooser =
false
,
63.
AllowColumnResize =
false
,
64.
AllowCellContextMenu =
false
,
65.
AllowColumnHeaderContextMenu =
false
,
66.
AllowAddNewRow =
false
,
67.
Dock = DockStyle.Fill,
68.
HorizontalScrollState = ScrollState.AlwaysHide
69.
};
Thank you for writing back.
In order to auto size the popup container, the dropdown should be opened at least once to calculate the necessary size. For the first opening, I can suggest you specify the RadPopupEditor.DropDownMinSize property considering the rows count and columns.
protected
override
Telerik.WinControls.RadElement CreateEditorElement()
{
grid.DataSource = GetData();
grid.ShowGroupPanel =
false
;
grid.AllowAddNewRow =
false
;
grid.BindingContext =
new
BindingContext();
grid.AutoSize =
true
;
container.Controls.Add(grid);
popupEditor.SetAssociatedControlRuntime(container);
RadHostItem host =
new
RadHostItem(popupEditor);
int
width = GetWidth(grid);
int
height = GetHeight(grid);
height = Math.Max(height, grid.Size.Height);
popupEditor.DropDownMinSize =
new
Size(width, height);
return
host;
}
private
int
GetHeight(RadGridView grid)
{
int
height = grid.Rows.Count * grid.TableElement.RowHeight + grid.TableElement.TableHeaderHeight + 60;
return
height;
}
private
int
GetWidth(RadGridView grid)
{
int
width = 0;
foreach
(GridViewColumn col
in
grid.Columns)
{
width += col.Width;
}
width += grid.TableElement.RowHeaderColumnWidth + 5;
return
width;
}
I hope this information helps. If you have any additional questions, please let me know.
Regards,
Dess
Telerik by Progress