Bind DataRow to PropertyGrid

18 posts, 4 answers
  1. Ismas
    Ismas avatar
    13 posts
    Member since:
    Aug 2016

    Posted 02 Aug Link to this post

    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?

  2. Ismas
    Ismas avatar
    13 posts
    Member since:
    Aug 2016

    Posted 02 Aug in reply to Ismas Link to this post

    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.

  3. UI for WinForms is Visual Studio 2017 Ready
  4. Answer
    Dess
    Admin
    Dess avatar
    1609 posts

    Posted 02 Aug Link to this post

    Hello Ismas,

    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
    Check out the Windows Forms project converter, which aids the conversion process from standard Windows Forms applications written in C# or VB to Telerik UI for WinForms.For more information check out this blog post and share your thoughts.
  5. Ismas
    Ismas avatar
    13 posts
    Member since:
    Aug 2016

    Posted 02 Aug in reply to Dess Link to this post

    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.

  6. Ismas
    Ismas avatar
    13 posts
    Member since:
    Aug 2016

    Posted 02 Aug Link to this post

    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).

  7. Answer
    Dess
    Admin
    Dess avatar
    1609 posts

    Posted 03 Aug Link to this post

    Hello Ismas,

    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
    Check out the Windows Forms project converter, which aids the conversion process from standard Windows Forms applications written in C# or VB to Telerik UI for WinForms.For more information check out this blog post and share your thoughts.
  8. Ismas
    Ismas avatar
    13 posts
    Member since:
    Aug 2016

    Posted 03 Aug in reply to Dess Link to this post

    Unfortunatelly my last message is still in "spam check". I hope it will appear soon.
  9. Answer
    Dess
    Admin
    Dess avatar
    1609 posts

    Posted 03 Aug Link to this post

    Hello Ismas,

    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
    Check out the Windows Forms project converter, which aids the conversion process from standard Windows Forms applications written in C# or VB to Telerik UI for WinForms.For more information check out this blog post and share your thoughts.
  10. Ismas
    Ismas avatar
    13 posts
    Member since:
    Aug 2016

    Posted 03 Aug in reply to Dess Link to this post

    Great. I'm completely satisfied with your answers.

    It's a pleasure to deal with you. Thanks again and have a nice day!

  11. Ismas
    Ismas avatar
    13 posts
    Member since:
    Aug 2016

    Posted 04 Aug Link to this post

    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 TrainerTypeClass = 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?

  12. Ismas
    Ismas avatar
    13 posts
    Member since:
    Aug 2016

    Posted 04 Aug in reply to Ismas Link to this post

    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.

  13. Ismas
    Ismas avatar
    13 posts
    Member since:
    Aug 2016

    Posted 06 Aug in reply to Ismas Link to this post

    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".

  14. Ismas
    Ismas avatar
    13 posts
    Member since:
    Aug 2016

    Posted 07 Aug in reply to Ismas Link to this post

    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.

  15. Dess
    Admin
    Dess avatar
    1609 posts

    Posted 08 Aug Link to this post

    Hello Ismas

    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 in 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;
        }
    }
    In the mentioned events you have access to the current item by the event arguments. It is necessary to cast the item to PropertyGridItem.

    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
    Check out the Windows Forms project converter, which aids the conversion process from standard Windows Forms applications written in C# or VB to Telerik UI for WinForms.For more information check out this blog post and share your thoughts.
  16. Ismas
    Ismas avatar
    13 posts
    Member since:
    Aug 2016

    Posted 08 Aug in reply to Dess Link to this post

    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.        }

     

  17. Answer
    Dess
    Admin
    Dess avatar
    1609 posts

    Posted 09 Aug Link to this post

    Hello Ismas,

    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
    Check out the Windows Forms project converter, which aids the conversion process from standard Windows Forms applications written in C# or VB to Telerik UI for WinForms.For more information check out this blog post and share your thoughts.
  18. Ismas
    Ismas avatar
    13 posts
    Member since:
    Aug 2016

    Posted 10 Aug in reply to Dess Link to this post

    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.};

  19. Dess
    Admin
    Dess avatar
    1609 posts

    Posted 15 Aug Link to this post

    Hello Ismas

    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
    Check out the Windows Forms project converter, which aids the conversion process from standard Windows Forms applications written in C# or VB to Telerik UI for WinForms.For more information check out this blog post and share your thoughts.
Back to Top
UI for WinForms is Visual Studio 2017 Ready