To reproduce: public BlankTreeView() { InitializeComponent(); RadContextMenu menu = new RadContextMenu(); RadMenuItem addItem = new RadMenuItem("Add"); addItem.Click += addItem_Click; menu.Items.Add(addItem); this.radTreeView1.RadContextMenu = menu; BindingList<ParentObject> items = new BindingList<ParentObject>(); for (int i = 0; i < 3; i++) { BindingList<ChildObject> subItems = new BindingList<ChildObject>(); for (int j = 0; j < 10; j++) { subItems.Add(new ChildObject(j,"SubNode" + i + "." + j)); } items.Add(new ParentObject(i ,"Node" + i,subItems)); } this.radTreeView1.DataSource = items; this.radTreeView1.DisplayMember = "Title\\Description"; this.radTreeView1.ChildMember = "ParentObject\\Children"; } private void addItem_Click(object sender, EventArgs e) { if (this.radTreeView1.SelectedNode != null) { if (this.radTreeView1.SelectedNode.Level == 0) { Random rand = new Random(); ParentObject dataItem = this.radTreeView1.SelectedNode.DataBoundItem as ParentObject; if (dataItem != null) { dataItem.Children.Add(new ChildObject(rand.Next(0, 100),"New Node")); } } } } public class ParentObject: INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } private int id; private string title; private BindingList<ChildObject> children; public int ID { get { return this.id; } set { this.id = value; OnPropertyChanged("ID"); } } public string Title { get { return this.title; } set { this.title = value; OnPropertyChanged("Title"); } } public BindingList<ChildObject> Children { get { return this.children; } set { this.children = value; OnPropertyChanged("Children"); } } public ParentObject(int iD, string title, BindingList<ChildObject> children) { this.ID = iD; this.Title = title; this.Children = children; } } public class ChildObject: INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private int id; private string description; public int ID { get { return this.id; } set { this.id = value; OnPropertyChanged("ID"); } } public string Description { get { return this.description; } set { this.description = value; OnPropertyChanged("Description"); } } public ChildObject(int iD, string description) { this.id = iD; this.description = description; } protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } Workaround: reset the TreeViewElement after adding the record: radTreeView1.TreeViewElement.Update(RadTreeViewElement.UpdateActions.Reset);
To reproduce: use the attached sample project and follow the steps: 1. Filter by "Jo". 2. Press the "Refresh" button. 3. Press the "Clear Filter" button. Note: if there is no applied filter when rebinding, the nodes order is correct. Please refer to the attached gif file. Workaround: clear the filter before setting the DataSource property and restore ethe filter afterwards: string filter = this.radTreeView1.Filter + ""; this.radTreeView1.Filter = ""; this.radTreeView1.DataSource = dt; this.radTreeView1.DisplayMember = "Name"; this.radTreeView1.ValueMember = "Id"; this.radTreeView1.Filter = filter;
Workaround: create a custom TreeNodeContentElement and override the Synchronize method public class MyTreeNodeContentElement : TreeNodeContentElement { protected override Type ThemeEffectiveType { get { return typeof(TreeNodeContentElement); } } public override void Synchronize() { TreeNodeElement treeNodeElement = NodeElement; if (treeNodeElement == null || treeNodeElement.Data == null || treeNodeElement.Data.TreeViewElement == null || treeNodeElement.Data.Text == null) { return; } this.Text = treeNodeElement.Data.Text; } } public class MyTreeNodeElement : TreeNodeElement { protected override TreeNodeContentElement CreateContentElement() { return new MyTreeNodeContentElement(); } protected override Type ThemeEffectiveType { get { return typeof(TreeNodeElement); } } } public partial class Form1 : Form { public Form1() { InitializeComponent(); this.radTreeView1.AllowEdit = true; this.radTreeView1.DisplayMember = "name"; this.radTreeView1.ParentMember = "pid"; this.radTreeView1.ChildMember = "id"; this.radTreeView1.DataSource = this.GetSampleData(); this.radTreeView1.CreateNodeElement += radTreeView1_CreateNodeElement; this.radTreeView1.ValueChanged += radTreeView1_ValueChanged; } private void radTreeView1_CreateNodeElement(object sender, Telerik.WinControls.UI.CreateTreeNodeElementEventArgs e) { e.NodeElement = new MyTreeNodeElement(); } private void radTreeView1_ValueChanged(object sender, Telerik.WinControls.UI.TreeNodeValueChangedEventArgs e) { this.UpdateDb(); } private void UpdateDb() { this.radTreeView1.DataSource = null; DataTable dt = this.GetSampleData(); this.radTreeView1.DataSource = dt; } private DataTable GetSampleData() { DataTable dt = new DataTable(); DataColumn dc = new DataColumn(); dc.ColumnName = "id"; dc.DataType = typeof(int); dt.Columns.Add(dc); DataColumn dc1 = new DataColumn(); dc1.ColumnName = "name"; dc1.DataType = typeof(string); dt.Columns.Add(dc1); DataColumn dc2 = new DataColumn(); dc2.ColumnName = "pid"; dc2.DataType = typeof(int); dt.Columns.Add(dc2); DataRow dr = dt.NewRow(); dr[0] = 0; dr[1] = "My Computer"; dr[2] = DBNull.Value; dt.Rows.Add(dr); dr = dt.NewRow(); dr[0] = 1; dr[1] = @"C:\"; dr[2] = 0; dt.Rows.Add(dr); dr = dt.NewRow(); dr[0] = 2; dr[1] = @"D:\"; dr[2] = 0; dt.Rows.Add(dr); dr = dt.NewRow(); dr[0] = 3; dr[1] = "Program Files"; dr[2] = 1; dt.Rows.Add(dr); dr = dt.NewRow(); dr[0] = 4; dr[1] = "Microsoft"; dr[2] = 3; dt.Rows.Add(dr); dr = dt.NewRow(); dr[0] = 5; dr[1] = "Telerik"; dr[2] = 3; dt.Rows.Add(dr); dr = dt.NewRow(); dr[0] = 6; dr[1] = "WINDOWS"; dr[2] = 1; dt.Rows.Add(dr); return dt; } }
To reproduce: private void radTreeView1_NodesNeeded(object sender, Telerik.WinControls.UI.NodesNeededEventArgs e) { for (int i = 0; i < 100; i++) { var node = new RadTreeNode("Test"+i); for (int j = 0; j < 10; j++) { node.Nodes.Add(new RadTreeNode("Sub")); } node.Expanded = true; e.Nodes.Add(node); } } Workaorund: private void radTreeView1_NodesNeeded(object sender, Telerik.WinControls.UI.NodesNeededEventArgs e) { radTreeView1.BeginUpdate(); for (int i = 0; i < 100; i++) { var node = new RadTreeNode("Test"+i); for (int j = 0; j < 10; j++) { node.Nodes.Add(new RadTreeNode("Sub")); } node.Expanded = true; e.Nodes.Add(node); } radTreeView1.EndUpdate(); }
Workaround: this.radTreeView1.EnableRadAccessibilityObjects = false;
To reproduce: - Add a lot of nodes to the tree (scrollbars must appear). - Use the following code to add nodes: public RadForm1() { InitializeComponent(); radTreeView1.AllowEdit = true; RadContextMenu menu = new RadContextMenu(); RadMenuItem add = new RadMenuItem(); add.Click += add_Click; add.Text = "add"; menu.Items.Add(add); radTreeView1.RadContextMenu = menu; } void add_Click(object sender, EventArgs e) { RadTreeNode node = radTreeView1.SelectedNode; var newNode = node.Nodes.Add("new node"); node.Expanded = true; radTreeView1.SelectedNode = newNode; radTreeView1.BeginEdit(); } - Add a node and scroll Workaround: public RadForm1() { InitializeComponent(); radTreeView1.TreeViewElement.VScrollBar.Scroll += VScrollBar_Scroll; radTreeView1.MouseWheel += TreeViewElement_MouseWheel; } void TreeViewElement_MouseWheel(object sender, MouseEventArgs e) { var radTreeView = sender as RadTreeView; if (radTreeView.IsEditing) { radTreeView.EndEdit(); } } void VScrollBar_Scroll(object sender, ScrollEventArgs e) { var radTreeView = (sender as RadScrollBarElement).ElementTree.Control as RadTreeView; if (radTreeView.IsEditing) { radTreeView.EndEdit(); } }
To reproduce: - Add items to the tree view (scrollbar must appear) - Add context menu item which adds a new node and puts it in edit mode. - Add a new node with the context menu item, scroll to the bottom, add item again. - Scroll up and add item one more time. Workaround: void treeView_EditorRequired(object sender, TreeNodeEditorRequiredEventArgs e) { e.Editor = new TreeViewTextBoxEditor(); }
To reproduce: radTreeView1.CheckBoxes = true; radTreeView1.TriStateMode = true; radTreeView1.AutoCheckChildNodes = true; RadTreeNode root = radTreeView1.Nodes.Add("Home"); root.Expanded = true; RadTreeNode node1 = new RadTreeNode("Minimal"); node1.CheckState = Telerik.WinControls.Enumerations.ToggleState.On; root.Nodes.Add(node1); Workaround: first add the node to the Nodes collection and only then set its CheckState
Workaround: After updating the binding source reset the data source of the tree this.radTreeView.DataSource = null; this.radTreeView.DataSource = this.MyBindingSource;
Workaround: add RadTreeNodes at run time.
To reproduce: public Form1() { InitializeComponent(); for (int i = 0; i < 20; i++) { this.radTreeView1.Nodes.Add("Node"+i); } this.radTreeView1.AllowEdit = true; } The attached gif file illustrates the steps. Workaround: this.radTreeView1.VScrollBar.ValueChanged+=VScrollBar_ValueChanged; private void VScrollBar_ValueChanged(object sender, EventArgs e) { this.radTreeView1.EndEdit(); }
To reproduce: public Form1() { InitializeComponent(); this.radTreeView1.AllowDragDrop = true; this.radTreeView2.AllowDragDrop = true; for (int i = 0; i < 5; i++) { this.radTreeView1.Nodes.Add("Node1." + i); this.radTreeView2.Nodes.Add("Node2." + i); } this.radTreeView1.ScreenTipNeeded += radTreeView1_ScreenTipNeeded; this.radTreeView2.ScreenTipNeeded += radTreeView1_ScreenTipNeeded; } RadOffice2007ScreenTipElement _screenTip = new RadOffice2007ScreenTipElement(); private void radTreeView1_ScreenTipNeeded(object sender, Telerik.WinControls.ScreenTipNeededEventArgs e) { _screenTip.CaptionLabel.Text = "Caption"; _screenTip.MainTextLabel.Text = "text"; _screenTip.AutoSize = true; e.Delay = 2000; e.Item.ScreenTip = _screenTip; } Steps: 1. Drag a node from the first RadTreeView to the other while the screen-tip is shown for the dragged node. 2. When the screen-tip is about to be hidden, the error occurs. Workaround: private void radTreeView1_DragStarting(object sender, RadTreeViewDragCancelEventArgs e) { if (_screenTip.IsElementVisible) { this.radTreeView1.Behavior.HideScreenTip(); } }
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 }); } } }
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); } }
Currently we do not support binding to the ToggleState.Indeterminate state automatically because it would require a change in the behavior of the Checked property. If you use the CheckedMember, the ToggleState.Indeterminate state is represent like ToggleState.On. Workaround: Subscribe to the NodeFormatting and NodeCheckedChanged events: void radTreeView1_NodeFormatting(object sender, Telerik.WinControls.UI.TreeNodeFormattingEventArgs e) { Child child = e.Node.DataBoundItem as Child; if (child != null) { e.Node.CheckState = child.Status; } } void radTreeView1_NodeCheckedChanged(object sender, Telerik.WinControls.UI.TreeNodeCheckedEventArgs e) { Child child = e.Node.DataBoundItem as Child; if (child != null) { child.Status = e.Node.CheckState; } }
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; } }
Please refer to the attached gif file. Workaround: set the Enabled property to false at run time.
Workaround: class CustomDragDropService : TreeViewDragDropService { public CustomDragDropService(RadTreeViewElement owner) : base(owner) { } protected override void SetHintWindowPosition(Point mousePt) { } } class CustomTreeViewElement : RadTreeViewElement { protected override Type ThemeEffectiveType { get { return typeof(RadTreeViewElement); } } protected override TreeViewDragDropService CreateDragDropService() { return new CustomDragDropService(this); } } class CustomTreeView : RadTreeView { protected override RadTreeViewElement CreateTreeViewElement() { return new CustomTreeViewElement(); } public override string ThemeClassName { get { return typeof(RadTreeView).FullName; } } }
To reproduce: 1. Run Demo application >> TreeView >> Drag & Drop. 2. Change the theme to Windows7 and start dragging a node. The drop hint is missing. Workaround: apply the theme in the Form.Load event after getting the TreeViewElement.ItemDropHint property coming from the ControlDefault theme. RadImageShape hint; private void Form1_Load(object sender, EventArgs e) { hint = this.radTreeView1.TreeViewElement.ItemDropHint; this.radTreeView1.ThemeName = "Windows7"; this.radTreeView1.TreeViewElement.ItemDropHint = hint; }