Start dragging a node and scroll using the mouse wheel. While scrolling, drop the node.
To reproduce:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
radTreeView1 = new RadTreeView();
radTreeView1.Parent = this;
for (int i = 0; i < 5; i++)
{
RadTreeNode n1 = new RadTreeNode("Node" + i);
this.radTreeView1.Nodes.Add(n1);
if (i % 2 == 0)
{
for (int j = 0; j < 2; j++)
{
RadTreeNode n2 = new RadTreeNode("Node" + i + "." + j);
n1.Nodes.Add(n2);
if (j % 2 == 0)
{
for (int k = 0; k < 2; k++)
{
RadTreeNode n3 = new RadTreeNode("Node" + i + "." + j + "." + k);
n2.Nodes.Add(n3);
}
}
}
}
}
radTreeView1.ShowRootLines = false;
radTreeView1.ShowLines = false;
}
Workaround:
void radTreeView1_NodeFormatting(object sender, TreeNodeFormattingEventArgs e)
{
if (radTreeView1.ShowLines == false)
{
if (e.NodeElement.LinesContainerElement.Children.Count > 0)
{
TreeNodeLineElement lineElement = (TreeNodeLineElement)e.NodeElement.LinesContainerElement.Children[0];
lineElement.Visibility = ElementVisibility.Collapsed;
}
}
}
To reproduce - Add RadTreeView with some nodes to a blank form. - Set the MultiSelect property to true. - Select\Deselect a node with code. Resolution: The SelectedNodeChanged event should not be fired when selected/deselected the node programmatically. We added a new event SelectedNodesChanged which is fired when the SelectedNodes collection changes.
To reproduce: - Add treeview to a form and set its AutoScrollOnClick property to false. - click a node that is not entirely visible with the right mouse button. - You will notice that the view is auto scrolled.
To reproduce:
- Add RadTreeView to a blank form.
- Set its AllowDragDrop and AllowDefaultContextMenu properties to true.
- Clear the menu items in the ContextMenuOpening event.
- You will notice that the Copy, Cut and Paste items are not removed.
Workaround:
void radTreeView1_ContextMenuOpening(object sender, Telerik.WinControls.UI.TreeViewContextMenuOpeningEventArgs e)
{
e.Menu.DropDownOpened -= Menu_DropDownOpened;
e.Menu.DropDownOpened += Menu_DropDownOpened;
}
void Menu_DropDownOpened(object sender, EventArgs e)
{
TreeViewDefaultContextMenu Menu = sender as TreeViewDefaultContextMenu;
for (int i = Menu.Items.Count - 1; i >= 0; i--)
{
if (Menu.Items[i].Name == "Copy" || Menu.Items[i].Name == "Cut" || Menu.Items[i].Name == "Paste")
{
Menu.Items.Remove(Menu.Items[i]);
}
}
}
To reproduce: use the following code
public class Item
{
public int Id { get; set; }
public string Title { get; set; }
public string Tag { get; set; }
public Item(int id, string title, string tag)
{
this.Id = id;
this.Title = title;
this.Tag = tag;
}
}
public Form1()
{
InitializeComponent();
List<Item> items = new List<Item>();
items.Add(new Item(1,"a1","x1"));
items.Add(new Item(2,"a2","x2"));
items.Add(new Item(3,"a3","x3"));
items.Add(new Item(4,"b1","y1"));
items.Add(new Item(5,"b2","y2"));
items.Add(new Item(6,"b3","y3"));
this.radTreeView1.DataSource = items;
this.radTreeView1.DisplayMember = "Title";
this.radTreeView1.ValueMember = "Id";
radTreeView1.FilterDescriptors.Add(new FilterDescriptor("Tag", FilterOperator.Contains, "y"));
}
Workaround: use custom filtering:
public Form1()
{
InitializeComponent();
List<Item> items = new List<Item>();
items.Add(new Item(1,"a1","x1"));
items.Add(new Item(2,"a2","x2"));
items.Add(new Item(3,"a3","x3"));
items.Add(new Item(4,"b1","y1"));
items.Add(new Item(5,"b2","y2"));
items.Add(new Item(6,"b3","y3"));
this.radTreeView1.DataSource = items;
this.radTreeView1.DisplayMember = "Title";
this.radTreeView1.ValueMember = "Id";
radTreeView1.FilterDescriptors.Add(new FilterDescriptor("Tag", FilterOperator.Contains, "y"));
radTreeView1.TreeViewElement.FilterPredicate = FilterNode;
}
public class Item
{
public int Id { get; set; }
public string Title { get; set; }
public string Tag { get; set; }
public Item(int id, string title, string tag)
{
this.Id = id;
this.Title = title;
this.Tag = tag;
}
}
private bool FilterNode(RadTreeNode node)
{
Item item = node.DataBoundItem as Item;
if (item != null && radTreeView1.FilterDescriptors.Count > 0)
{
FilterDescriptor fd = radTreeView1.FilterDescriptors[0];
var propertyValue = item.GetType().GetProperty(fd.PropertyName,
BindingFlags.Public | BindingFlags.Instance).GetValue(item, null);
if (propertyValue.ToString().Contains(fd.Value.ToString()))
{
return true;
}
return false;
}
return false;
}
Workaround:
class MyTreeView : RadTreeView
{
protected override RadTreeViewElement CreateTreeViewElement()
{
return new MyTreeViewElement();
}
public override string ThemeClassName
{
get
{
return typeof(RadTreeView).FullName;
}
}
}
class MyTreeViewElement : RadTreeViewElement
{
bool IsPerformingEndEdit = false;
protected override bool EndEditCore(bool commitChanges)
{
if (!IsEditing || IsPerformingEndEdit)
{
return false;
}
TreeNodeElement nodeElement = GetElement(this.SelectedNode);
if (nodeElement == null)
{
return false;
}
this.IsPerformingEndEdit = true;
if (commitChanges && this.ActiveEditor.IsModified)
{
SaveEditorValue(nodeElement, this.ActiveEditor.Value);
}
this.ActiveEditor.EndEdit();
nodeElement.RemoveEditor(this.ActiveEditor);
this.InvalidateMeasure();
UpdateLayout();
OnEdited(new TreeNodeEditedEventArgs(nodeElement, ActiveEditor, !commitChanges));
typeof(RadTreeViewElement).GetField("activeEditor", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(this, null);
this.IsPerformingEndEdit = false;
return false;
}
protected override Type ThemeEffectiveType
{
get
{
return typeof(RadTreeViewElement);
}
}
}
To reproduce: add a RadTreeView and a RadButton to the form. Use the following code snippet:
public Form1()
{
InitializeComponent();
RadTreeNode node1 = new RadTreeNode();
node1.Text = "SameText";
RadTreeNode node2 = new RadTreeNode();
node2.Text = "SameText";
this.radTreeView1.Nodes.Add(node1);
this.radTreeView1.Nodes.Add(node2);
this.radTreeView1.SortOrder = SortOrder.Ascending;
}
private void radButton1_Click(object sender, EventArgs e)
{
for (int i = this.radTreeView1.Nodes.Count - 1; i > -1; i--)
{
this.radTreeView1.Nodes.RemoveAt(i);
}
}
Workaround: set the SortOrder property to None before removing the nodes and restore it afterwards
private void radButton1_Click(object sender, EventArgs e)
{
this.radTreeView1.SortOrder = SortOrder.None;
for (int i = this.radTreeView1.Nodes.Count - 1; i > -1; i--)
{
this.radTreeView1.Nodes.RemoveAt(i);
}
this.radTreeView1.SortOrder = SortOrder.None;
}
Please refer to the attached gif file. Workaround: set the Enabled property to false at run time.
To reproduce: use the following code snippet and perform the illustrated steps on the attached gif file:
public Form1()
{
InitializeComponent();
for (int i = 0; i < 5; i++)
{
this.radTreeView1.Nodes.Add("Node" + i);
}
this.radTreeView1.NodeRemoving += radTreeView1_NodeRemoving;
this.radTreeView1.AllowRemove = true;
this.radTreeView1.AllowDefaultContextMenu = true;
}
private void radTreeView1_NodeRemoving(object sender, Telerik.WinControls.UI.RadTreeViewCancelEventArgs e)
{
DialogResult result = RadMessageBox.Show(String.Format("Do you really want to remove the node '{0}'?", e.Node.Text),
"Question", System.Windows.Forms.MessageBoxButtons.YesNo, RadMessageIcon.Question);
if (result != System.Windows.Forms.DialogResult.Yes)
{
e.Cancel = true;
}
}
Error: "Object of type 'Telerik.WinControls.Enumerations.ToggleState' cannot be converted to type 'System.Boolean'."
To reproduce:
public Form1()
{
InitializeComponent();
List<Parent> dataItems = new List<Parent>();
Parent currentParent;
Child currentChild;
List<Child> children;
string parentId = string.Empty;
string childId = string.Empty;
for (int i = 1; i <= 5; i++)
{
parentId = Guid.NewGuid().ToString();
children = new List<Child>();
for (int j = 1; j < 5; j++)
{
childId = Guid.NewGuid().ToString();
currentChild = new Child(childId, parentId, "SubNode." + i + "." + j, j % 2 == 0);
children.Add(currentChild);
}
currentParent = new Parent(parentId, "Node." + i, i % 2 == 0,children);
dataItems.Add(currentParent);
}
radTreeView1.DataSource = dataItems;
radTreeView1.DisplayMember = "Title\\Name";
radTreeView1.ChildMember = "Parent\\Children";
radTreeView1.CheckedMember = "IsActive\\Status";
radTreeView1.CheckBoxes = true;
}
public class Parent
{
public string ParentId { get; set; }
public string Title { get; set; }
public bool IsActive { get; set; }
public List<Child> Children { get; set; }
public Parent(string parentId, string title, bool isActive, List<Child> children)
{
this.ParentId = parentId;
this.Title = title;
this.IsActive = isActive;
this.Children = children;
}
}
public class Child
{
public string ChildId { get; set; }
public string ParentId { get; set; }
public string Name { get; set; }
public bool Status { get; set; }
public Child(string childId, string parentId, string name, bool status)
{
this.ChildId = childId;
this.ParentId = parentId;
this.Name = name;
this.Status = status;
}
}
Workaround: Use a custom TypeConverter for the boolean properties:
public class ToggleStateConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
return destinationType == typeof(ToggleState);
}
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
{
if (value is bool)
{
switch ((bool)value)
{
case true:
return ToggleState.On;
case false:
return ToggleState.Off;
default :
return ToggleState.Indeterminate;
}
}
return base.ConvertTo(context, culture, value, destinationType);
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(ToggleState);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
ToggleState state = (ToggleState)value;
switch (state)
{
case ToggleState.On:
return true;
case ToggleState.Off:
return false;
case ToggleState.Indeterminate:
return false;
}
return base.ConvertFrom(context, culture, value);
}
}
To reproduce: use the following code:
public Form1()
{
InitializeComponent();
this.radTreeView1.MultiSelect = true;
for (int i = 0; i < 3; i++)
{
RadTreeNode node = new RadTreeNode();
node.Text = "Node." + i;
for (int j = 0; j < 3; j++)
{
node.Nodes.Add(new RadTreeNode("Node." + i + "." + j));
}
this.radTreeView1.Nodes.Add(node);
}
this.radTreeView1.SelectedNodeChanged += radTreeView1_SelectedNodeChanged;
}
private void radTreeView1_SelectedNodeChanged(object sender, Telerik.WinControls.UI.RadTreeViewEventArgs e)
{
Console.WriteLine(e.Node.Text + ">> Selected: " + e.Node.Selected);
}
1.Select a node
2.Press Ctrl and click over the selected node again in order to unselect it. The SelectedNodeChanged event will not fire.
Workaround:
public class MyRadTreeNode : RadTreeNode
{
public MyRadTreeNode(string text) : base(text)
{
}
private static readonly MethodInfo OnSelectedNodeChangedMethodInfo =
typeof(RadTreeViewElement).GetMethod("OnSelectedNodeChanged",
BindingFlags.NonPublic | BindingFlags.Instance, null,
new Type[] { typeof(RadTreeNode), typeof(RadTreeViewAction) }, null);
protected override void OnNotifyPropertyChanged(PropertyChangedEventArgs args)
{
base.OnNotifyPropertyChanged(args);
if (args.PropertyName == "Selected" && TreeViewElement != null)
{
OnSelectedNodeChangedMethodInfo.Invoke(TreeViewElement, new object[] { this, RadTreeViewAction.ByMouse });
}
}
}
Workaround: add RadTreeNodes at run time.
Workaround: After updating the binding source reset the data source of the tree this.radTreeView.DataSource = null; this.radTreeView.DataSource = this.MyBindingSource;
Workaround: this.radTreeView1.EnableRadAccessibilityObjects = false;
To reproduce:
private void Form1_Load(object sender, EventArgs e)
{
this.radTreeView1.Nodes.Add("Node1");
this.radTreeView1.Nodes.Add("Node2");
this.radTreeView1.Nodes.Add("Node3");
this.radTreeView1.Nodes.Add("Node4");
this.radTreeView1.Nodes.Add("Node5");
this.radTreeView1.Nodes.Add("Node6");
this.radTreeView1.Nodes["Node1"].Nodes.Add("Node11");
this.radTreeView1.Nodes["Node1"].Nodes.Add("Node12");
this.radTreeView1.Nodes["Node1"].Nodes.Add("Node13");
this.radTreeView1.Nodes["Node1"].Nodes.Add("Node14");
this.radTreeView1.Nodes["Node2"].Nodes.Add("Node21");
this.radTreeView1.Nodes["Node2"].Nodes.Add("Node22");
this.radTreeView1.Nodes["Node2"].Nodes.Add("Node23");
this.radTreeView1.Nodes["Node2"].Nodes.Add("Node24");
this.radTreeView1.Nodes["Node3"].Nodes.Add("Node31");
this.radTreeView1.Nodes["Node3"].Nodes.Add("Node32");
this.radTreeView1.Nodes["Node3"].Nodes.Add("Node33");
this.radTreeView1.Nodes["Node3"].Nodes.Add("Node34");
this.radTreeView1.Nodes["Node4"].Nodes.Add("Node41");
this.radTreeView1.Nodes["Node4"].Nodes.Add("Node42");
this.radTreeView1.Nodes["Node4"].Nodes.Add("Node43");
this.radTreeView1.Nodes["Node4"].Nodes.Add("Node44");
this.radTreeView1.Nodes["Node5"].Nodes.Add("Node51");
this.radTreeView1.Nodes["Node5"].Nodes.Add("Node52");
this.radTreeView1.Nodes["Node5"].Nodes.Add("Node53");
this.radTreeView1.Nodes["Node5"].Nodes.Add("Node54");
this.radTreeView1.Nodes["Node6"].Nodes.Add("Node61");
this.radTreeView1.Nodes["Node6"].Nodes.Add("Node62");
this.radTreeView1.Nodes["Node6"].Nodes.Add("Node63");
this.radTreeView1.Nodes["Node6"].Nodes.Add("Node64");
}
Workaround: add the nodes in the form's constructor.
Second workaround: Me.RadTreeView1.TreeViewElement.Update(Telerik.WinControls.UI.RadTreeViewElement.UpdateActions.Reset)
Workaround: raise a flag before the delete operation and cancel the SelectedNodeChanging event
To reproduce:
DataTable dt = new DataTable();
public Form1()
{
InitializeComponent();
dt.Columns.Add("Id", typeof(int));
dt.Columns.Add("ParentID", typeof(int));
dt.Columns.Add("NodeName", typeof(string));
dt.Rows.Add(1, 0, "Category1");
dt.Rows.Add(2, 1, "Category2");
dt.Rows.Add(3, 0, "Category3");
dt.Rows.Add(4, 3, "Category4");
dt.Rows.Add(5, 3, "Category5");
dt.Rows.Add(6, 3, "Category6");
dt.Rows.Add(7, 6, "Category7");
dt.Rows.Add(8, 6, "Category8");
this.radTreeView1.DataSource = dt;
this.radTreeView1.DisplayMember = "NodeName";
this.radTreeView1.ChildMember = "ID";
this.radTreeView1.ParentMember = "ParentID";
this.radTreeView1.ExpandAll();
this.radTreeView1.AllowAdd = true;
this.radTreeView1.AllowRemove = true;
this.radTreeView1.AllowDefaultContextMenu = true;
this.radLabel1.Text = "Number of rows: " + dt.Rows.Count;
this.radTreeView1.NodeRemoved += radTreeView1_NodeRemoved;
}
private void radTreeView1_NodeRemoved(object sender, Telerik.WinControls.UI.RadTreeViewEventArgs e)
{
this.radLabel1.Text = "Number of rows: " + dt.Rows.Count;
}
Workaround: perform the delete operation programmatically by modifying the default context menu:
this.radTreeView1.ContextMenuOpening += radTreeView1_ContextMenuOpening;
private void radTreeView1_ContextMenuOpening(object sender, TreeViewContextMenuOpeningEventArgs e)
{
foreach (RadMenuItem item in e.Menu.Items)
{
if (item.Text == "&Delete")
{
item.Visibility = Telerik.WinControls.ElementVisibility.Collapsed;
}
else
{
item.Visibility = Telerik.WinControls.ElementVisibility.Visible;
}
}
RadMenuItem removeItem = new RadMenuItem("Remove");
e.Menu.Items.Add(removeItem);
removeItem.Click += item_Click;
}
private void item_Click(object sender, EventArgs e)
{
DeleteSubNodes(this.radTreeView1.SelectedNode);
this.radLabel1.Text = "Number of rows: " + dt.Rows.Count;
}
private void DeleteSubNodes(Telerik.WinControls.UI.RadTreeNode node)
{
if (node.Nodes.Count == 0)
{
dt.Rows.Remove(((DataRowView)node.DataBoundItem).Row);
}
else
{
foreach (RadTreeNode n in node.Nodes)
{
DeleteSubNodes(n);
}
dt.Rows.Remove(((DataRowView)node.DataBoundItem).Row);
}
}
To reproduce: - Open the Property builder, add some nodes and disable them. - There is no way to enable them at design time. Workaround. Disable the nodes at runtime.