This is a migrated thread and some comments may be shown as answers.

Issue with rendering page after drag and drop

1 Answer 119 Views
Treeview
This is a migrated thread and some comments may be shown as answers.
Ralf
Top achievements
Rank 1
Ralf asked on 18 Jan 2013, 07:15 AM

Hello,

I have an application were I include a Treeview.

I have some issues with my screen,
when I manipulate this treeview with drag and drop functionality.

The treeview get's rendered and is only showing a part.
It's like the scrollbar is not on the correct position.
When I scroll with the mouse up and down it will be rendered correct again.

This issue appear's when I reorder the treeview with the mouse, aswell in code.
It's not predictable when it occurs.

Has anyone an idea how to fix this ?

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Windows.Forms;
using Telerik.WinControls;
using Telerik.WinControls.Data;
using Telerik.WinControls.UI;
 
namespace SortAccountsSpike
{
    public partial class SortAccountsForm : Form
    {
        private Object _currentTargetDataBoundItem;
  
        public SortAccountsForm()
        {
            InitializeComponent();
          //  _dataList = new ObservableCollection<AccountGroup>();
        }
 
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            AutoScroll = false;
 
            radTreeView1.TreeViewElement.NodeFormatting += TreeViewElement_NodeFormatting;
            radTreeView1.DragStarting += RadTreeView1DragStarting;
            radTreeView1.DragOverNode += RadTreeView1DragOverNode;
            radTreeView1.DragEnding += RadTreeView1DragEnding;
            radTreeView1.TreeViewElement.AutoSizeItems = true;
            radTreeView1.ShowLines = true;
            radTreeView1.ShowRootLines = true;
            radTreeView1.ShowExpandCollapse = true;
            radTreeView1.FullRowSelect = true;
            radTreeView1.LineStyle = TreeLineStyle.Dot;
            radTreeView1.MultiSelect = true;
            radTreeView1.ShowNodeToolTips = true;
            radTreeView1.TreeViewElement.Comparer = new AccounNodeComparer(radTreeView1.TreeViewElement);
            radTreeView1.NodeExpandedChanging += radTreeView1_NodeExpandedChanging;
 
            FillTreeView();
        }
 
        private void FillTreeView()
        {
            radTreeView1.ChildMember = @"AccountGroup\Accounts";
          //  radTreeView1.DisplayMember = @"GroupName\AccountNumber";
            radTreeView1.SortOrder = SortOrder.Ascending;
            radTreeView1.DataSource = AccountModel.AccountGroups;
        }
 
        void TreeViewElement_NodeFormatting(object sender, TreeNodeFormattingEventArgs e)
        {
            var treeNodeContentElement = e.NodeElement.ContentElement;
 
            //General styling
            /////////////
  
            //  treeNodeContentElement.StretchHorizontally = true;
            treeNodeContentElement.Padding = new Padding(5);
            treeNodeContentElement.Margin = new Padding(0, 2, 0, 2);
            treeNodeContentElement.SmoothingMode = SmoothingMode.AntiAlias;
            treeNodeContentElement.DrawBorder = true;
            treeNodeContentElement.BorderColor = Color.FromArgb(110, 153, 210);
            treeNodeContentElement.DrawFill = true;
            treeNodeContentElement.GradientStyle = GradientStyles.Linear;
            treeNodeContentElement.NumberOfColors = 2;
 
            //AccountGroupFormatting
            var accountGroup = e.Node.DataBoundItem as AccountGroup;
            if (accountGroup != null)
            {
                treeNodeContentElement.Text = accountGroup.ToDisplayHtml();
                e.Node.Expanded = accountGroup.Expanded;
 
                //fill
                treeNodeContentElement.BackColor = Color.FromArgb(248, 248, 248);
                treeNodeContentElement.BackColor2 = Color.FromArgb(233, 233, 233);
            }
 
            //Account formatting
            var accountInfo = e.Node.DataBoundItem as AccountInfo; 
            if (accountInfo != null)
            {
                treeNodeContentElement.Text = accountInfo.ToDisplayHtml();
 
                if (accountInfo.IsVisible)
                {
                    e.Node.ToolTipText = string.Empty;
                    treeNodeContentElement.BackColor = Color.FromArgb(174, 190, 217);
                    treeNodeContentElement.BackColor2 = Color.FromArgb(168, 183, 210);
                    treeNodeContentElement.ForeColor = Color.Black;
                }
                else
                {
                    e.Node.ToolTipText = "This account is not visible in drop down lists.";
                    treeNodeContentElement.BackColor = Color.FromArgb(227, 233, 242);
                    treeNodeContentElement.BackColor2 = Color.FromArgb(235, 238, 245);
                    treeNodeContentElement.ForeColor = Color.FromArgb(153, 153, 153);
                }
 
                  
            }
        }
 
        void radTreeView1_NodeExpandedChanging(object sender, RadTreeViewCancelEventArgs e)
        {
            var group = e.Node.DataBoundItem as AccountGroup;
            if (group != null)
            {
                group.Expanded = !e.Node.Expanded;
            }
        }
 
        void RadTreeView1DragStarting(object sender, RadTreeViewDragCancelEventArgs e)
        {
            //don't allow the first group to be moved
            if (e.Node.Level == 0 && e.Node.Index == 0)
            {
                e.Cancel = true;
            }
     
            _currentTargetDataBoundItem = null;
        }
 
        void RadTreeView1DragOverNode(object sender, RadTreeViewDragCancelEventArgs e)
        {
            //determine if the dragged node can be dropped on the current hovered node
            if (e.Node != null)
            {
                e.Cancel = !CanBeDroppedOnTarget(e.Node.DataBoundItem, e.TargetNode.DataBoundItem);
            }
            else
            {
                e.Cancel = true;
            }
        }
 
        void RadTreeView1DragEnding(object sender, RadTreeViewDragCancelEventArgs e)
        {
            //recheck if it is correct to drop the dragged node on the target node (this event is fired multiple times when multiple nodes are dragged at once)
            if (CanBeDroppedOnTarget(e.Node.DataBoundItem, e.TargetNode.DataBoundItem))
            {
                if (_currentTargetDataBoundItem == null)
                    _currentTargetDataBoundItem = e.TargetNode.DataBoundItem;
                //execute drag operation      
                MoveNode(e.Node.DataBoundItem);             
            }
        
            e.Cancel = true; //cancel event and make the treeview refresh to reflect the changed observable datasource
            radTreeView1.Nodes.Refresh();
            radTreeView1.SelectedNodes.Clear();
        }
 
        private bool CanBeDroppedOnTarget(Object draggedDataBoundItem, Object targetDataBoundItem)
        {
            var draggedGroup = draggedDataBoundItem as AccountGroup;
            var targetGroup = targetDataBoundItem as AccountGroup;
            if (draggedGroup != null)
            {
                //dragged node is a group -> target must also be a group
                return (targetGroup != null);
            }
            else
            {
                //dragged node is an account
                var draggedAccount = (AccountInfo)draggedDataBoundItem;
 
                //-> if parent is also being dragged, the node cannot be dropped
                var parentGroupIsAlsoDragged = radTreeView1.SelectedNodes.Select(n => n.DataBoundItem)
                                                           .OfType<AccountGroup>()
                                                           .Any(
                                                               group =>
                                                               group.Accounts.Any(
                                                                   account => account.Id == draggedAccount.Id));
 
                return !parentGroupIsAlsoDragged;
            }
        }
 
        private void MoveNode(Object draggedDataBoundItem)
        {
            var draggedGroup = draggedDataBoundItem as AccountGroup;
            var targetGroup = _currentTargetDataBoundItem as AccountGroup;
            var draggedAccount = draggedDataBoundItem as AccountInfo;
            var targetAccount = _currentTargetDataBoundItem as AccountInfo;
            if (draggedGroup != null)
            {
                if (targetGroup == null)
                {
                    throw new InvalidOperationException(
                        "Dropping an account group on a node that does not represent an account group is not possible.");
                }
 
                MoveAccountGroup(draggedGroup, targetGroup);
            }
            else
            {
                //move account
                MoveAccount(draggedAccount, targetAccount, targetGroup);
            }
        }
 
        private void MoveAccount(AccountInfo draggedAccount, AccountInfo targetAccount, AccountGroup targetGroup)
        {
            Debug.Assert(draggedAccount != null);
 
            AccountGroup draggedGroup = AccountModel.AccountGroups.First(group => @group.Accounts.Contains(draggedAccount));
 
            if (targetAccount != null)
            {
                targetGroup = AccountModel.AccountGroups.First(group => @group.Accounts.Contains(targetAccount));
            }
            Debug.Assert(targetGroup != null);
 
            //move down items
            var targetSequence = (targetAccount != null) ? targetAccount.Sequence : 0;
            var accountInfosToMove = targetGroup.Accounts.Where(accInfo => accInfo.Sequence > targetSequence);
            foreach (var accInfo in accountInfosToMove)
            {
                accInfo.Sequence += 1;
            }
 
            //move item
            draggedAccount.Sequence = targetSequence + 1;
 
            if (draggedGroup.Id != targetGroup.Id)
            {
                draggedGroup.Accounts.Remove(draggedAccount);
                targetGroup.Accounts.Add(draggedAccount);
                NormalizeAccountSequences(draggedGroup.Accounts);
            }
 
            NormalizeAccountSequences(targetGroup.Accounts);
 
            if (_currentTargetDataBoundItem is AccountInfo)
            {
                _currentTargetDataBoundItem = draggedAccount;
            }
        }
 
        private void MoveAccountGroup(AccountGroup draggedGroup, AccountGroup targetGroup)
        {
            //move down items
            var groupsToMove = AccountModel.AccountGroups.Where(group => @group.Sequence > targetGroup.Sequence);
            foreach (var group in groupsToMove)
            {
                @group.Sequence += 1;
            }
 
            //move group
            draggedGroup.Sequence = targetGroup.Sequence + 1;
 
            //normalize
            NormalizeGroupSequences(AccountModel.AccountGroups);
        }
 
        private void NormalizeAccountSequences(IEnumerable<AccountInfo> accountInfosToNormalize)
        {
            var index = 0;
 
            foreach (var accInfo in accountInfosToNormalize.OrderBy(account => account.Sequence))
            {
                accInfo.Sequence = ++index;
            }
        }
 
        private void NormalizeGroupSequences(IEnumerable<AccountGroup> accountGroupsToNormalize)
        {
            var index = 0;
 
            foreach (var group in accountGroupsToNormalize.OrderBy(group => group.Sequence))
            {
                group.Sequence = ++index;
            }
        }
 
 
        private void MakeVisibleButtonClick(object sender, EventArgs e)
        {
            ChangVisibilityOfSelectedNodes(true);
        }
 
        private void MakeInvisibleButtonClick(object sender, EventArgs e)
        {
            ChangVisibilityOfSelectedNodes(false);
        }
 
        private void ChangVisibilityOfSelectedNodes(bool isvisible)
        {
            var accountsToChange = radTreeView1.SelectedNodes.Select(n => n.DataBoundItem).OfType<AccountInfo>().ToList();
 
            foreach (var account in accountsToChange)
            {
                account.IsVisible = isvisible;
            }
 
            radTreeView1.Nodes.Refresh();
        }
 
        private void ChangeAliasButtonClick(object sender, EventArgs e)
        {
            string filledInAlias = string.Empty;
 
            var uniquePreferedNames =
                (from account in radTreeView1.SelectedNodes.Select(n => n.DataBoundItem).OfType<AccountInfo>()
                 group account by account.PreferedName
                 into accountGroup
                 select accountGroup.Key).ToList();
 
            if (uniquePreferedNames.Count == 1)
            {
                filledInAlias = uniquePreferedNames.First();
            }
 
            var result = InputDialog.ShowInputBox("Edit alias", "Please fill in an alias for the selected account(s)", out filledInAlias, this, filledInAlias);
 
            if (result == DialogResult.OK)
            {
                var accountsToChange = radTreeView1.SelectedNodes.Select(n => n.DataBoundItem).OfType<AccountInfo>().ToList();
 
                foreach (var account in accountsToChange)
                {
                    account.PreferedName = filledInAlias;
                }
 
                radTreeView1.Nodes.Refresh();
            }     
        }
 
        private static class AccountModel
        {
            private static ObservableCollection<AccountGroup> _accountGroups;
            public static ObservableCollection<AccountGroup> AccountGroups
            {
                get { return _accountGroups ?? (_accountGroups = LoadInitialDataList()); }
            }
 
            private static ObservableCollection<AccountGroup> LoadInitialDataList()
            {
                var dataCollection = new ObservableCollection<AccountGroup>();
                var groupNone = new AccountGroup
                    {
                    Id = Guid.NewGuid(),
                    GroupName = "No group",
                    Sequence = 1,
                    Expanded = true
                };
                dataCollection.Add(groupNone);
 
                var groupTest = new AccountGroup
                {
                    Id = Guid.NewGuid(),
                    GroupName = "Some other group",
                    Sequence = 2
                };
                dataCollection.Add(groupTest);
 
                var anotherGroup = new AccountGroup
                {
                    Id = Guid.NewGuid(),
                    GroupName = "Yet another group",
                    Sequence = 3
                };
                dataCollection.Add(anotherGroup);
 
                var item1 = new AccountInfo
                {
                    Id = Guid.NewGuid(),
                    AccountNumber = "1",
                    Balance = 154000,
                    Currency = "EUR",
                    Product = "Alba VZW, Mullens Kris",
                    Sequence = 1,
                    IsVisible = true
                };
                groupNone.Accounts.Add(item1);
 
                var item2 = new AccountInfo
                {
                    Id = Guid.NewGuid(),
                    AccountNumber = "2",
                    Balance = 500,
                    Currency = "EUR",
                    Product = "John Doe",
                    PreferedName = "The unknown account",
                    Sequence = 3,
                    IsVisible = true
                };
                groupNone.Accounts.Add(item2);
 
                var item3 = new AccountInfo
                {
                    Id = Guid.NewGuid(),
                    AccountNumber = "3",
                    Balance = -600,
                    Currency = "EUR",
                    Product = "Jane Doe",
                    Sequence = 4
                };
                groupTest.Accounts.Add(item3);
 
                var item4 = new AccountInfo
                {
                    Id = Guid.NewGuid(),
                    AccountNumber = "4",
                    Balance = -600,
                    Currency = "EUR",
                    Product = "John Denver",
                    Sequence = 5
                };
                groupTest.Accounts.Add(item4);
 
                var item5 = new AccountInfo
                {
                    Id = Guid.NewGuid(),
                    AccountNumber = "5",
                    Balance = 600897,
                    Currency = "EUR",
                    Product = "Richie Vallens",
                    Sequence = 6,
                    IsVisible = true
                };
                groupTest.Accounts.Add(item5);
 
                for (int i = 0; i < 10; i++)
                {
                    var item6 = new AccountInfo
                    {
                        Id = Guid.NewGuid(),
                        AccountNumber = "BE11 2222 3333 4444",
                        Balance = -150,
                        Currency = "EUR",
                        Product = "Donna Summer",
                        Sequence = i + 1
                    };
                    anotherGroup.Accounts.Add(item6);
                }
 
                
 
                return dataCollection;
            }
        }
    }
 
    public class AccounNodeComparer : TreeNodeComparer
    {
        public AccounNodeComparer(RadTreeViewElement treeViewElement)
            : base(treeViewElement)
        {
 
        }
 
        public override int Compare(RadTreeNode x, RadTreeNode y)
        {
            //compare 2 account groups
            var accountGroup1 = x.DataBoundItem as AccountGroup;
            var accountGroup2 = y.DataBoundItem as AccountGroup;
 
            if (accountGroup1 != null && accountGroup2 != null)
            {
                return accountGroup1.CompareTo(accountGroup2);
            }
 
            //compare 2 accounts
            var accountInfo1 = x.DataBoundItem as AccountInfo;
            var accountInfo2 = y.DataBoundItem as AccountInfo;
 
            if (accountInfo1 != null && accountInfo2 != null)
            {
                return accountInfo1.CompareTo(accountInfo2);
            }
 
            return 0;
        }
    }
}

Kind regards.

Ralf

1 Answer, 1 is accepted

Sort by
0
Svett
Telerik team
answered on 22 Jan 2013, 02:23 PM
Hello Ralf,

Thank you for writing.

I applied the sample code snippet in a project on my side. Nevertheless, I did not manage to reproduce the issue. I am enclosing a sample video that demonstrates my approach. Could you tell me the exact steps that I should follow? What did I miss?  Note that you need a web browser and installed flash plugin to watch the video.

Regards,
Svett
the Telerik team
Q3'12 SP1 of RadControls for WinForms is out now. See what's new.
Tags
Treeview
Asked by
Ralf
Top achievements
Rank 1
Answers by
Svett
Telerik team
Share this question
or