Problems implementing a custom TreeView grid editor

15 posts, 3 answers
  1. Karl
    Karl avatar
    35 posts
    Member since:
    Dec 2013

    Posted 08 Oct 2014 Link to this post

    I'm trying to implement a custom TreeView editor on the GridView and I'm experiencing two problems.
    1. My editor is confined to the size of the cell and it needs to be much larger than that
    2. When I attempt to data bind the control nothing is displayed.

    Sample code:
    public class TreeEditor : BaseGridEditor
          {
           
          protected override RadElement CreateEditorElement ()
              {
              RadTreeViewElement treeViewElement = new RadTreeViewElement ();           
              //BindData (treeViewElement); // This doesn't work
              LoadData (treeViewElement); // This displays data
              return treeViewElement;
              }
     
          private static void BindData(RadTreeViewElement treeViewElement)
          {
              List<NodeData> Nodes = new List<NodeData>();
              NodeData root = new NodeData() { ID = 0 };
              root.Children.Add(new NodeData() { ID = 1 });
              root.Children.Add(new NodeData() { ID = 2 });
              Nodes.Add(root);
              treeViewElement.DataSource = Nodes;
              treeViewElement.DisplayMember = "ID\\ID";
              treeViewElement.ChildMember = "Nodes\\Children";
          }
     
          private static void LoadData (RadTreeViewElement treeViewElement)
              {
              RadTreeNode root = treeViewElement.Nodes.Add ("Root");
              root.Nodes.Add ("First", 1);
              root.Nodes.Add ("Second", 1);
              }
     
          public override object Value
              {
              get
                  {
                  RadTreeViewElement editor = (RadTreeViewElement) this.EditorElement;
                  if (editor.SelectedNode == null)
                      return string.Empty;
     
                  return editor.SelectedNode.ToString ();
                  }
              set
                  {
                  //TODO: ?
                  }
              }
          }
  2. Answer
    Dess
    Admin
    Dess avatar
    1609 posts

    Posted 13 Oct 2014 Link to this post

    Hello Karl,

    Thank you for writing.

    I have prepared a sample code snippet demonstrating an approach how to implement custom editor with RadTreeView. In order avoid difference in rows height when the editor is active, the custom tree view editor is placed in a popup:
    public Form1()
    {
        InitializeComponent();
        this.radGridView1.EditorRequired += radGridView1_EditorRequired;
        this.radGridView1.CellEditorInitialized += radGridView1_CellEditorInitialized;
     
        GridViewComboBoxColumn comboColumn = new GridViewComboBoxColumn("Description");
        comboColumn.FieldName = "Description";
        comboColumn.DisplayMember = "Description";
        comboColumn.ValueMember = "Description";
        comboColumn.DataSource = accounts1.Concat(accounts2).ToList();
        this.radGridView1.Columns.Add(comboColumn);
     
        this.radGridView1.AutoGenerateColumns = false;
        List<Account> items = new List<Account>();
        foreach (Account a in accounts1.Concat(accounts2).ToList())
        {
            items.Add(new Account(a.AccountID, a.Description));
        }
        this.radGridView1.DataSource = items;
    }
     
    private void radGridView1_CellEditorInitialized(object sender, GridViewCellEventArgs e)
    {
        TreeEditor editor = e.ActiveEditor as TreeEditor;
        if (editor != null)
        {
            TreeEditorElement treeElement = editor.EditorElement as TreeEditorElement;
            treeElement.TreeView.BindingContext = this.radGridView1.BindingContext;
            treeElement.TreeView.DataSource = accountTypes;
     
            treeElement.TreeView.DisplayMember = "Title\\Description";
            treeElement.TreeView.ChildMember = "AccountTypes\\Accounts";
            treeElement.TreeView.FullRowSelect = true;
        
            treeElement.TreeView.SelectedNodes.Clear();
     
            string text = this.radGridView1.CurrentCell.Value + "";
           
            foreach (RadTreeNode n in treeElement.TreeView.Nodes)
            {
                RadTreeNode selected = GetNodeByName(n, text);
                if (selected != null)
                {
                    selected.Current = true;
                    selected.Selected = true;
                    
                    selected.Expanded = true;
                    if (selected.Level > 0)
                    {
                        selected.Parent.Expanded = true;
                    }
                }
            }
        }
    }
     
    private static RadTreeNode GetNodeByName(RadTreeNode n, string t)
    {
        RadTreeNode foundNode = null;
        if (n.Text == t)
        {
            foundNode = n;
        }
        else
        {
            foreach (RadTreeNode node in n.Nodes)
            {
                foundNode = GetNodeByName(node, t);
                if (foundNode != null)
                {
                    break;
                }
            }
        }
        return foundNode;
    }
     
    void radGridView1_EditorRequired(object sender, EditorRequiredEventArgs e)
    {
        if (this.radGridView1.CurrentColumn.Name == "Description")
        {
            e.EditorType = typeof(TreeEditor);
        }
    }
     
    public class TreeEditor: BaseGridEditor
    {
        public override object Value
     
        {
            get
     
            {
                TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
     
                SelectedTreeNodeCollection treeNodes = treeElement.TreeView.SelectedNodes;
                StringBuilder sb = new StringBuilder();
                foreach (RadTreeNode node in treeNodes)
                {
                    sb.AppendFormat("{0}", node.Text);
                }
                return sb.ToString(); 
            }
     
            set
     
            {
                string text = ((GridComboBoxCellElement)this.OwnerElement).Value + "";
             
                TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
     
                foreach (RadTreeNode n in treeElement.TreeView.Nodes)
                {
                    RadTreeNode selected = GetNodeByName(n, text);
                    if (selected != null)
                    {
                        selected.Selected = true;
                    }
                }
            }
        }
     
        public override void BeginEdit()
        {
            base.BeginEdit();
     
            TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
            treeElement.Button.DropDownButtonElement.DropDownMenu.PopupElement.MinSize = new Size(300, 300);
            treeElement.Button.ShowDropDown();
        }
     
        protected override RadElement CreateEditorElement()
        {
            return new TreeEditorElement();
        }
     
        private RadTreeNode FindTreeNode(RadTreeNode node, string value)
        {
            if (node.Text == value)
            {
                return node;
            }
     
            foreach (RadTreeNode subNode in node.Nodes)
            {
                RadTreeNode found = FindTreeNode(subNode, value);
     
                if (found != null)
                {
                    return found;
                }
            }
     
            return null;
        }
    }
     
    public class TreeEditorElement: RadHostItem
    {
        public TreeEditorElement() : base(new RadDropDownButton())
     
        {
            this.Button.Items.Add(new TreeMenuItem());
            this.TreeView.MultiSelect = true;
            TreeView.Nodes.Add(new RadTreeNode("Root"));
            TreeView.Nodes[0].Nodes.Add(new RadTreeNode("Item 1"));
            TreeView.Nodes[0].Nodes.Add(new RadTreeNode("Item 2"));
            TreeView.ExpandAll();
        }
     
        public RadDropDownButton Button
     
        {
            get
            {
                return (RadDropDownButton)this.HostedControl;
            }
        }
     
        public RadTreeView TreeView
     
        {
            get
            {
                return (RadTreeView)((RadMenuHostItem)this.Button.Items[0]).HostedControl;
            }
        }
    }
     
    public class TreeMenuItem: RadMenuHostItem
    {
        public TreeMenuItem() : base(new RadTreeView())
        {
        }
     
        protected override SizeF MeasureOverride(SizeF availableSize)
        {
            base.MeasureOverride(availableSize);
     
            return new SizeF(100, 300);
        }
    }
     
    public class Account
    {
        public int AccountID { get; set; }
     
        public string Description { get; set; }
     
        public Account()
        {
        }
     
        public Account(int accountID, string description)
        {
            this.AccountID = accountID;
            this.Description = description;
        }
    }
     
    public class AccountType
    {
        public int AccountTypeID { get; set; }
     
        public string Title { get; set; }
     
        public List<Account> Accounts { get; set; }
     
        public AccountType(int accountTypeID, string title, List<Account> accounts)
        {
            this.AccountTypeID = accountTypeID;
            this.Title = title;
            this.Accounts = accounts;
        }
    }
     
    static List<Account> accounts1 = new List<Account>()
    {
        new Account(1,"Rent Expence description 1"),
        new Account(2, "Rent Expence description 2")
    };
     
    static List<Account> accounts2 = new List<Account>()
    {
        new Account(1,"Investment Income description 1"),
        new Account(2, "Investment Income description 2")
    };
     
    List<AccountType> accountTypes = new List<AccountType>()
    {
        new AccountType(1,"Expence",accounts1),
        new AccountType(2,"Income ",accounts2),
    };

    I hope this information helps. Should you have further questions, I would be glad to help.
     
    Regards,
    Desislava
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  3. UI for WinForms is Visual Studio 2017 Ready
  4. Karl
    Karl avatar
    35 posts
    Member since:
    Dec 2013

    Posted 15 Oct 2014 in reply to Dess Link to this post

    That's great thanks. I noticed that when I hit enter it closes the popup but still shows the dropdown button. Any suggestions on how I can hide this button without causing an event leak in this scenario?
  5. Answer
    Dess
    Admin
    Dess avatar
    1609 posts

    Posted 20 Oct 2014 Link to this post

    Hello Karl,

    Thank you for writing back.

    The drop down is displayed as the RadTreeView is placed in a RadMenuHostItem inside a RadHostItem. You can deal with the undesired behavior that when pressing Enter key the popup is closed, but the editor is still active. Here is the modified code snippet for the TreeEditor class:
    public class TreeEditor: BaseGridEditor
    {
        //some other code
        public override void BeginEdit()
        {
            base.BeginEdit();
     
            TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
            treeElement.Button.DropDownButtonElement.DropDownMenu.PopupElement.MinSize = new Size(300, 300);
            treeElement.Button.ShowDropDown();
            treeElement.Button.DropDownClosed += Button_DropDownClosed;
        }
     
        public override bool EndEdit()
        {
            bool result = base.EndEdit();
            TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
            treeElement.Button.DropDownClosed -= Button_DropDownClosed;
            return result;
        }
     
        private void Button_DropDownClosed(object sender, EventArgs e)
        {
            RadDropDownButton ddButton = sender as RadDropDownButton;
            if (ddButton != null)
            {
                RadGridView grid = ddButton.Parent as RadGridView;
                if (grid != null)
                {
                    grid.EndEdit();
                }
            }
        }
        //some other code
    }

    I hope this information helps. If you have any additional questions, please let me know.

    Regards,
    Desislava
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  6. Karl
    Karl avatar
    35 posts
    Member since:
    Dec 2013

    Posted 20 Oct 2014 in reply to Dess Link to this post

    Thank you so much for your hard work.
  7. Karl
    Karl avatar
    35 posts
    Member since:
    Dec 2013

    Posted 05 Jun 2015 Link to this post

    How can this be modified so that the tree captures the mouse wheel to scroll the treeview? Currently the mouse wheel will close the editor.
  8. Dess
    Admin
    Dess avatar
    1609 posts

    Posted 08 Jun 2015 Link to this post

    Hello Karl,

    Thank you for writing back.

    In order to force the RadTreeView to accept MouseWheel messages for scrolling, you need to focus the TreeEditorElement.TreeView in the TreeEditor.BeginEdit event. Afterwards, you should cancel the TreeEditorElement.Button.DropDownButtonElement.DropDownMenu.DropDownClosing event in order to keep the popup opened while scrolling. You can use a flag to indicate whether the drop-down should be closed. Here is just a an example demonstrating how to close the popup when selecting a node:
    public override void BeginEdit()
    {
        base.BeginEdit();
         
        TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
     
        treeElement.TreeView.Focus();
        isSelected = false;
        treeElement.Button.DropDownButtonElement.DropDownMenu.DropDownClosing -= DropDownMenu_DropDownClosing;
        treeElement.Button.DropDownButtonElement.DropDownMenu.DropDownClosing += DropDownMenu_DropDownClosing;
        treeElement.TreeView.SelectedNodeChanged -= TreeView_SelectedNodeChanged;
        treeElement.TreeView.SelectedNodeChanged += TreeView_SelectedNodeChanged;
    }
     
    bool isSelected = false;
     
    private void TreeView_SelectedNodeChanged(object sender, RadTreeViewEventArgs e)
    {
        isSelected = true;
        TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
        treeElement.Button.DropDownButtonElement.DropDownMenu.ClosePopup(RadPopupCloseReason.Mouse);
    }
     
    private void DropDownMenu_DropDownClosing(object sender, RadPopupClosingEventArgs args)
    {
        RadDropDownButtonPopup popup = sender as RadDropDownButtonPopup;
        if (popup != null && !isSelected)
        {
            args.Cancel = true;
        }
    }

    I hope this information helps. If you have any additional questions, please let me know.

    Regards,
    Dess
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  9. Karl
    Karl avatar
    35 posts
    Member since:
    Dec 2013

    Posted 17 Aug 2015 in reply to Dess Link to this post

    In the last example how can I force an EndEdit on the grid after the popup has closed? Thanks.
  10. Hristo
    Admin
    Hristo avatar
    716 posts

    Posted 18 Aug 2015 Link to this post

    Hi Karl,

    Thank you for writing back.

    In order to accomplish this task, you would need to handle the DropDownClosed event of the Button element and in the handler call the EndEdit method of the grid. Please see my code snippet below: 
    public override void BeginEdit()
    {
        base.BeginEdit();
     
        TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
         
        //more code
        treeElement.Button.DropDownClosed += Button_DropDownClosed;
    }
     
    private void Button_DropDownClosed(object sender, EventArgs e)
    {
        RadDropDownButton ddButton = sender as RadDropDownButton;
        if (ddButton != null)
        {
            RadGridView grid = ddButton.Parent as RadGridView;
            if (grid != null)
            {
                grid.EndEdit();
            }
        }
    }

    I hope this helps. Should you have further questions please do not hesitate to write back.

    Regards,
    Hristo Merdjanov
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  11. Karl
    Karl avatar
    35 posts
    Member since:
    Dec 2013

    Posted 18 Aug 2015 in reply to Hristo Link to this post

    I can't get this to work with the mouse wheel changes. Using the code below blanks out the cell when I select an item on the tree

    public class TreeEditor : BaseGridEditor
        {
        public override object Value
            {
            get
                {
                TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
                SelectedTreeNodeCollection treeNodes = treeElement.TreeView.SelectedNodes;
                StringBuilder sb = new StringBuilder();
     
                foreach (RadTreeNode node in treeNodes)
                    {
                    sb.AppendFormat("{0}", node.Text);
                    }
     
                return sb.ToString();
                }
            set
                {
                string text = ((GridComboBoxCellElement)this.OwnerElement).Value + "";
                TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
                }
            }      
     
        public override void BeginEdit()
            {
            base.BeginEdit();
     
            TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
            treeElement.Button.DropDownButtonElement.DropDownMenu.PopupElement.MinSize = new Size(300, 300);
            treeElement.Button.ShowDropDown();
     
            //mouse wheel changes-
            treeElement.TreeView.Focus();
            isSelected = false;
            treeElement.Button.DropDownButtonElement.DropDownMenu.DropDownClosing -= DropDownMenu_DropDownClosing;
            treeElement.Button.DropDownButtonElement.DropDownMenu.DropDownClosing += DropDownMenu_DropDownClosing;
            treeElement.TreeView.SelectedNodeChanged -= TreeView_SelectedNodeChanged;
            treeElement.TreeView.SelectedNodeChanged += TreeView_SelectedNodeChanged;
            // end mouse wheel
     
            treeElement.Button.DropDownClosed += Button_DropDownClosed;
            }
     
        private bool isSelected;
        private void TreeView_SelectedNodeChanged(object sender, RadTreeViewEventArgs e)
            {
            isSelected = true;
            TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
            treeElement.Button.DropDownButtonElement.DropDownMenu.ClosePopup(RadPopupCloseReason.Mouse);
     
     
            RadGridView grid = e.TreeView.Parent as RadGridView;
            if (grid != null)
                {
                grid.EndEdit();
                }
            }
     
        private void DropDownMenu_DropDownClosing(object sender, RadPopupClosingEventArgs args)
            {
            RadDropDownButtonPopup popup = sender as RadDropDownButtonPopup;
            if (popup != null && !isSelected)
                {
                args.Cancel = true;
                }
            }
     
        private void Button_DropDownClosed(object sender, EventArgs e)
            {
            RadDropDownButton ddButton = sender as RadDropDownButton;
            if (ddButton != null)
                {
                RadGridView grid = ddButton.Parent as RadGridView;
                if (grid != null)
                    {
                    grid.EndEdit();
                    }
                }
            }
     
        protected override RadElement CreateEditorElement()
            {
            return new TreeEditorElement();
            }
        }

  12. Hristo
    Admin
    Hristo avatar
    716 posts

    Posted 21 Aug 2015 Link to this post

    Hi Karl,

    Thank you for writing back.

    Closing the dropdown before editing the cell does not pass properly the selected value. I am sending you attached my modified project, allowing scrolling inside the tree and node selection.

    I hope that it would fit your scenario. Should you have further questions please do not hesitate to write back.

    Regards,
    Hristo Merdjanov
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  13. Karl
    Karl avatar
    35 posts
    Member since:
    Dec 2013

    Posted 27 Aug 2015 in reply to Hristo Link to this post

    Thanks for your continued help. When I run your project the popup tree closes when I use my scroll wheel. 

    This has been going on for a while so to review I need a combination of all these behaviors.

    1. Click on cell -> tree pops up on first click
    2. Scroll mouse wheel ->  scrolls pop up tree
    3. Click on tree item -> tree is closed and cell is filled. No drop down button displayed

    I believe all of issues have been addressed in this thread but I can't figure out how to make them all work at the same time.

     

    Note- In order to run the solution I had to remove the "Source" directory from the project and in VS right clicked on the project and chose Telerik UI For Winforms/Convert To Telerik Windows Form Application.

     Also I added extra data to make the mouse scrolling more obvious-

    static List<Account> accounts1 = new List<Account>()
    {
        new Account(1,"Rent Expence description 1"),
        new Account(2,"Rent Expence description 1"),
        new Account(3,"Rent Expence description 1"),
        new Account(4,"Rent Expence description 1"),
        new Account(5,"Rent Expence description 1"),
        new Account(6,"Rent Expence description 1"),
        new Account(7,"Rent Expence description 1"),
        new Account(8,"Rent Expence description 1"),
    };
     
    static List<Account> accounts2 = new List<Account>()
     
    {
        new Account(1,"Investment Income description 1"),
        new Account(2, "Investment Income description 2"),
        new Account(3,"Investment Income description 1"),
        new Account(4,"Investment Income description 1"),
        new Account(5,"Investment Income description 1"),
        new Account(6,"Investment Income description 1"),
        new Account(7,"Investment Income description 1"),
        new Account(8,"Investment Income description 1"),
        new Account(9,"Investment Income description 1")
    };

  14. Hristo
    Admin
    Hristo avatar
    716 posts

    Posted 01 Sep 2015 Link to this post

    Hi Karl,

    Thank you for writing back.

    I am sending you attached the sample project which I believe addresses all of the features you would like to implement. 

    Besides the project, I am also sending you a gif file showing the result on my end.

    I hope this helps. Should you have further questions please do not hesitate to write back.

    Regards,
    Hristo Merdjanov
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  15. Karl
    Karl avatar
    35 posts
    Member since:
    Dec 2013

    Posted 02 Sep 2015 in reply to Hristo Link to this post

    Sorry but this is not doing everything correctly. It does not scroll with the mouse wheel. In your gif I see you are clicking and dragging the scroll bars.
    If I apply Dess's solution from June 08 to your latest project (link and new code shown below), scrolling with the mousewheel works but I need the window to close when clicking outside the popup or when the escape button is pressed as it did before adding these changes. Now it will only close when clicking on the tree.

     

    http://www.telerik.com/forums/problems-implementing-a-custom-treeview-grid-editor#HcsEPKPbXUmdDY6CPANs-Q

     

    public override void BeginEdit()
    {
        base.BeginEdit();
     
        TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
        treeElement.Button.Visible = false;
     
        treeElement.TreeView.Focus();
        treeElement.TreeView.SelectedNodeChanged -= TreeView_SelectedNodeChanged;
        treeElement.TreeView.SelectedNodeChanged += TreeView_SelectedNodeChanged;
     
    // begin mouse wheel changes
        isSelected = false;
        treeElement.Button.DropDownButtonElement.DropDownMenu.DropDownClosing -= DropDownMenu_DropDownClosing;
        treeElement.Button.DropDownButtonElement.DropDownMenu.DropDownClosing += DropDownMenu_DropDownClosing;
    }
    bool isSelected = false;
    private void DropDownMenu_DropDownClosing(object sender, RadPopupClosingEventArgs args)
        {
        RadDropDownButtonPopup popup = sender as RadDropDownButtonPopup;
        if (popup != null && !isSelected)
            {
            args.Cancel = true;
            }
        }
     
    private void TreeView_SelectedNodeChanged(object sender, RadTreeViewEventArgs e)
        {
        isSelected = true;
    // end mouse wheel changes
        TreeEditorElement treeElement = this.EditorElement as TreeEditorElement;
        ((RadDropDownButton)treeElement.HostedControl).DropDownButtonElement.PerformClick();
        treeElement.Button.DropDownButtonElement.DropDownMenu.ClosePopup(RadPopupCloseReason.Mouse);
    }


  16. Answer
    Hristo
    Admin
    Hristo avatar
    716 posts

    Posted 07 Sep 2015 Link to this post

    Hi Karl,

    Thank you for writing back.

    I extended the sample project to include the custom solution regarding the scrolling behavior. The popup now closes when the Esc key is pressed and also if you click somewhere outside of the editor.

    Besides the project I am also sending you a gif file showing the result on my end.

    I hope this helps. Should you have further questions please do not hesitate to write back.

    Regards,
    Hristo Merdjanov
    Telerik
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Back to Top
UI for WinForms is Visual Studio 2017 Ready