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.Value0I 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 editor09. {10.//here I try to create PopupEditor11. var pEditor = new RadPopupEditor();12.//PickPopupContainer inherits PopupContainer with only adding all needed controls13. 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 rounding18. }19. else //fix double values being rounded20. {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 enum31.//ExTag is simply Dictionary<string, object> to extend Tag functionality32. 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 creation36. 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 full39. 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 = true08. };09. var checkCol = new GridViewCheckBoxColumn("State")10. {11. Width = 50,12. ReadOnly = false,13. EditMode = EditMode.OnValueChange,14. EnableHeaderCheckBox = true15. };16. var valueCol = new GridViewTextBoxColumn17. {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 RadPopupContainer41.{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 RadGridView53.{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.AlwaysHide69.};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
