Start dragging a node and scroll using the mouse wheel. While scrolling, drop the node.
Please refer to the attached sample project and follow the steps: If you execute my code sample and try this sequence, you will see my problem: 1- start the application 2- select "test1" on the grid => you see "fonction XX of test1" in the treeview (that's correct) 3- select "test2" on the grid => you see "fonction XX of test2" in the treeview (that's correct) 4- expand all nodes in the treeview 5- uncheck "fonction 31 of test2" in the treeview 6- select "test1" on the grid => you have the error message. On the grid, we have "test1" selected and on the treeview we have "test2". Note that the problem appears only when checking a node in the treeview on a second level. If you follow this procedure, you will have no problem : 1- restart the application 2- select "test1" on the grid => you see "fonction XX of test1" in the treeview (that's correct) 3- select "test2" on the grid => you see "fonction XX of test2" in the treeview (that's correct) 4- uncheck "fonction 30 of test2" in the treeview 5- select "test1" on the grid => you will have no error. On the grid, we have "test1" selected and on the treeview we have "test1". 6- select "test2" on the grid => you will have no error. On the grid, we have "test2" selected and on the treeview we have "test2" with "fonction 30 of test2" unchecked. Workaround: in order to synchronize the current row in RadGridView is to change the RadTreeView.DataSource in the RadGridView.CurrentRowChanged event.
Please refer to the attached gif file. Workaround: set the Enabled property to false at run time.
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: select a node and click the button. Note: it may be necessary to perform this several times.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private List<DataObject> GetDataList()
{
var ret = new List<DataObject>();
ret.Add(new DataObject() { Node = "A", Parent = null });
ret.Add(new DataObject() { Node = "B", Parent = "A" });
ret.Add(new DataObject() { Node = "C", Parent = "B" });
ret.Add(new DataObject() { Node = "D", Parent = "B" });
return ret;
}
private void button1_Click(object sender, EventArgs e)
{
radTreeView1.Nodes.Clear();
radTreeView1.DisplayMember = "Node";
radTreeView1.ChildMember = "Node";
radTreeView1.ParentMember = "Parent";
radTreeView1.DataSource = GetDataList();
radTreeView1.ExpandAll();
}
}
public class DataObject
{
public string Node { get; set; }
public string Parent { get; set; }
}
Workaround: instead of clearing the nodes, set the DataSource property to null.
Use the attached project to reproduce. - Check on of the nodes and then press Alt +T (do not move the mouse away from the node) Workaround: Set transparent fill and border to the TreeNodeElement disabled state in Visual Style Builder.
Workaround: this.radTreeView1.TreeViewElement.InvalidateMeasure(); this.radTreeView1.TreeViewElement.InvalidateArrange();
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)
To reproduce:
Add a RadTreeView ,add nodes, enable TriState, disable AutoCheckChildNodes and use this code:
void cxTreeView2_NodeCheckedChanging(object sender, RadTreeViewCancelEventArgs e)
{
if (!cxTreeView2.AutoCheckChildNodes && cxTreeView2.CheckBoxes && cxTreeView2.TriStateMode)
{
cxTreeView2.TreeViewElement.NodeCheckedChanging -= cxTreeView2_NodeCheckedChanging;
if (e.Node.CheckState == ToggleState.Indeterminate)
{
e.Cancel = true;
e.Node.CheckState = ToggleState.On;
CheckAllChildren(e.Node);
}
cxTreeView2.TreeViewElement.NodeCheckedChanging += cxTreeView2_NodeCheckedChanging;
}
}
void CheckAllChildren(RadTreeNode parent)
{
foreach (var node in parent.Nodes)
{
node.CheckState = ToggleState.On;
CheckAllChildren(node);
}
}
Click a top node two times and remove the mouse from the checkbox, it is now showing as Indetermined but the data item is on.
Workaround:
void cxTreeView2_NodeCheckedChanging(object sender, RadTreeViewCancelEventArgs e)
{
if (!cxTreeView2.AutoCheckChildNodes && cxTreeView2.CheckBoxes && cxTreeView2.TriStateMode)
{
cxTreeView2.TreeViewElement.NodeCheckedChanging -= cxTreeView2_NodeCheckedChanging;
if (e.Node.CheckState == ToggleState.Indeterminate)
{
e.Cancel = true;
e.Node.CheckState = ToggleState.On;
CheckAllChildren(e.Node);
cxTreeView2.TreeViewElement.Update(RadTreeViewElement.UpdateActions.Reset);
}
cxTreeView2.TreeViewElement.NodeCheckedChanging += cxTreeView2_NodeCheckedChanging;
}
}
void CheckAllChildren(RadTreeNode parent)
{
foreach (var node in parent.Nodes)
{
node.CheckState = ToggleState.On;
CheckAllChildren(node);
}
}
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;
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);
}
}
The check boxes are squeezed when the expanded state of the child nodes is changed in NodeCheckedChanged event. Possible workaround: use Begin-End update block
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:
private void radTreeView1_NodeFormatting(object sender, Telerik.WinControls.UI.TreeNodeFormattingEventArgs e)
{
e.NodeElement.UseDefaultDisabledPaint = true;
}
In Load-On-Demand scenario when visibility of ExpanderElement is changed in NodeFormatting - drawing of lines is invalid
To reproduce:
- Open the attached project.
- Scroll to the right.
- Drag a node.
- The DropHint line is outside the window.
Workaround:
class CustomTreeView : RadTreeView
{
//Replace the default element with the custom one
protected override RadTreeViewElement CreateTreeViewElement()
{
return new CustomTreeViewElement();
}
//Enable theming for the control
public override string ThemeClassName
{
get
{
return typeof(RadTreeView).FullName;
}
}
}
class CustomTreeViewElement : RadTreeViewElement
{
//Enable themeing for the element
protected override Type ThemeEffectiveType
{
get
{
return typeof(RadTreeViewElement);
}
}
//Replace the default drag drop service with the custom one
protected override TreeViewDragDropService CreateDragDropService()
{
return new MyDragDropService(this);
}
}
class MyDragDropService : TreeViewDragDropService
{
public MyDragDropService(RadTreeViewElement owner)
: base(owner)
{ }
protected override void UpdateHintPosition(Point mousePosition)
{
base.UpdateHintPosition(mousePosition);
RadLayeredWindow dropHint =typeof(TreeViewDragDropService).GetField("dropHintWindow", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(this) as RadLayeredWindow;
if (dropHint != null)
{
TreeNodeElement nodeElement = this.DropTarget as TreeNodeElement;
dropHint.Location = new Point (nodeElement.ElementTree.Control.PointToScreen(Point.Empty).X, dropHint.Location.Y);
}
}
}
To reproduce:
1. Drag and drop RadTreeView on the form.
2. Set the Dock property to true
3. Add 3 or more nodes with long names
4. Resize the form to minimum size and you will notice that the spacing between characters is changed.
Workaround:
If FontSize of nodes is bigger than 13, you can subscribe to the NodeFormatting event and set the AutoEllipsis property to false:
Font font = new Font("Segoe UI", 13f, FontStyle.Regular);
void radTreeView1_NodeFormatting(object sender, Telerik.WinControls.UI.TreeNodeFormattingEventArgs e)
{
e.NodeElement.ContentElement.Font = font;
e.NodeElement.ContentElement.AutoEllipsis = false;
}
If font size is smaller, you need to set the MinSize property too:
Font font = new Font("Segoe UI", 12f, FontStyle.Regular);
void radTreeView1_NodeFormatting(object sender, Telerik.WinControls.UI.TreeNodeFormattingEventArgs e)
{
e.NodeElement.ContentElement.Font = font;
e.NodeElement.ContentElement.MinSize = new System.Drawing.Size(500, 18);
}
To reproduce:
Bind the tree to the following structure:
public class DeskSites
{
public string DeskSiteName { get; set; }
public Channels channels { get; set; }
}
public class Channels : List<Channel>
{
}
public class Channel
{
public string ChannelName { get; set; }
public FileSets fileSets { get; set; }
}
public class FileSets : List<FileSet>
{
}
public class FileSet
{
public string FileSetName { get; set; }
}
Workaround:
Use the the generic class instead of the inherited one:
public class DeskSites
{
public string DeskSiteName { get; set; }
public List<Channel> channels { get; set; }
}
To reproduce:
1. Add a RadTreeView with several nodes
2. Subscribe to the EditorRequired event and specify the editor to TreeViewTextBoxEditor where its Multiline property is set to true.
3. Select a node and press F2. The editor is activated. However, when you enter some text and press Ctrl+Enter, the editor is closed. The expected behavior is that a new line is inserted.
Workaround:
private void radTreeView1_EditorRequired(object sender, TreeNodeEditorRequiredEventArgs e)
{
CustomTreeViewTextBoxEditor editor = new CustomTreeViewTextBoxEditor();
editor.Multiline = true;
e.Editor = editor;
}
public class CustomTreeViewTextBoxEditor : TreeViewTextBoxEditor
{
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter &&
e.Modifiers == Keys.Control &&
this.Multiline)
{
return;
}
base.OnKeyDown(e);
}
}
Select Demo application >> "Tree View" -> "Drag & Drop". Focus on the left treeview. 1. Click on the node "Drafts"; 2. Press Shift button and click on the "Outbox" node; 3. Release shift button; 4. Press left mouse button on the "Outbox" node and start dragging; 5. Drop selected nodes after node "Large Mail". You can see that order of nodes was changed. Before: "Drafts", "Inbox" and "Outbox" After: "Outbox", "Drafts" and "Inbox" Possible workaround: http://www.telerik.com/forums/nodes-order-after-drag-drop#5bbz6cBDEUeHLyLU5zkfDQ