To reprodice:
for (int i = 0; i < 20; i++)
{
RadTreeNode node = new RadTreeNode("Node " + i);
node.ToolTipText = "hello " + i;
radTreeView1.Nodes.Add(node);
}
Start dragging a node and scroll using the mouse wheel. While scrolling, drop the node.
To reproduce: Add nodes to RadTreeView with at least 3 levels hierarchy. Set some of the last level nodes Visible property to false. Start the application. Expand some nodes and scroll. You will notice that the last item will change sometimes. Workaround: Set this.radTreeView1.TreeViewElement.AllowArbitraryItemHeight = true; Use ItemHeight = 1, instead of Visible = false
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