Declined
Last Updated: 08 Aug 2016 10:33 by ADMIN
ADMIN
Dess | Tech Support Engineer, Principal
Created on: 16 May 2014 13:24
Category: Editors
Type: Bug Report
0
FIX. RadTextBoxControl - StackOverflowException when using RadTextBoxControlElement inside TreeNodeContentElement
To reproduce: add a RadTreeView and a timer. Use the following code:

BindingList<Item> list = new BindingList<Item>();

public Form1()
{
    InitializeComponent();
    this.radTreeView1.TreeViewElement.CreateNodeElement += TreeViewElement_CreateNodeElement;
   
    for (int i = 0; i < 10; i++)
    {
        list.Add(new Item(Guid.NewGuid().ToString(), "Node" + i));
    }

    this.radTreeView1.DataSource = list;
    this.radTreeView1.DisplayMember = "Title";
    this.radTreeView1.ValueMember = "UniqueIdentifier";

    this.radTreeView1.TreeViewElement.AutoSizeItems = true;
    this.timer1.Start();
}

void TreeViewElement_CreateNodeElement(object sender, Telerik.WinControls.UI.CreateTreeNodeElementEventArgs e)
{
    e.NodeElement = new CustomTreeNodeElement();
}

public class Item: System.ComponentModel.INotifyPropertyChanged
{
    public Item(string uniqueIdentifier, string title)
            {
                this._uniqueIdentifier = uniqueIdentifier;
                this._title = title;
            }

    public string UniqueIdentifier
            {
                get
                {
                    return this._uniqueIdentifier;
                }
                set
                {
                    this._uniqueIdentifier = value;
                    OnPropertyChanged("UniqueIdentifier");
                }
            }

    public string Title
            {
                get
                {
                    return this._title;
                }
                set
                {
                    this._title = value;
                    OnPropertyChanged("Title");
                }
            }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
            }

    private string _uniqueIdentifier;
    private string _title;
}

public class CustomContentElement : TreeNodeContentElement
{
    StackLayoutElement nodeContentContainer;
    LinePrimitive lineElement;
    LightVisualElement idElement;
    RadTextBoxControlElement textBoxElement;

    protected override Type ThemeEffectiveType
            {
                get
                {
                    return typeof(TreeNodeContentElement);
                }
            }

    protected override void InitializeFields()
            {
                base.InitializeFields();
                this.Margin = new Padding(5, 5, 5, 5);

                this.StretchHorizontally = true;
            }

    public override void Synchronize()
    {
        this.DrawFill = true;

        TreeNodeElement treeNodeElement = this.NodeElement;
        RadTreeNode node = treeNodeElement.Data;
        Item dataItem = (Item)node.DataBoundItem;
        if (dataItem != null)
        {
            this.idElement.Text = string.Empty + dataItem.UniqueIdentifier;

            this.textBoxElement.Text = string.Empty + dataItem.Title;
        }
    }

    protected override void CreateChildElements()
            {
                nodeContentContainer = new StackLayoutElement();
                nodeContentContainer.Orientation = Orientation.Vertical;
                nodeContentContainer.StretchHorizontally = true;
                nodeContentContainer.StretchVertically = false;

                idElement = new LightVisualElement();
                idElement.ShouldHandleMouseInput = false;
                idElement.NotifyParentOnMouseInput = true;
                idElement.StretchVertically = false;
                this.nodeContentContainer.Children.Add(idElement);

                lineElement = new LinePrimitive();
                lineElement.BackColor = Color.Black;
                lineElement.Margin = new Padding(10, 0, 10, 0);
                lineElement.StretchVertically = false;
                this.nodeContentContainer.Children.Add(lineElement);

                textBoxElement = new RadTextBoxControlElement();
                textBoxElement.TextChanged += textBoxElement_TextChanged;
                textBoxElement.Margin = new Padding(20, 3, 20, 3);
                textBoxElement.StretchVertically = false;
                this.nodeContentContainer.Children.Add(textBoxElement);

                this.Children.Add(nodeContentContainer);
            }

    private void textBoxElement_TextChanged(object sender, EventArgs e)
    {
        RadTextBoxControlElement tb = sender as RadTextBoxControlElement;
        CustomContentElement contentElement = tb.Parent.Parent as CustomContentElement;
        Item item = contentElement.NodeElement.Data.DataBoundItem as Item;
        if (item.Title != tb.Text)
        {
            item.Title = tb.Text;
        }
    }
}

public class CustomTreeNodeElement : TreeNodeElement
{
    protected override TreeNodeContentElement CreateContentElement()
    {
        return new CustomContentElement();
    }

    protected override Type ThemeEffectiveType
    {
        get
        {
            return typeof(TreeNodeElement);
        }
    }
}

private void timer1_Tick(object sender, EventArgs e)
{
    foreach (Item item in list)
    {
        item.Title = "Node " + DateTime.Now.ToLongTimeString();
    }
}
1 comment
ADMIN
Todor
Posted on: 28 Jun 2016 08:17
This is not an issue in the controls, rather in the client code when the Title of Item is changed, it notifies the CurrencyManager of RadTreeView to force visual item's Synchronize method, where the text of TextBoxElement is changed. This fires the TextChanged event of TextBoxElement, where the Title of Item is changed. This cycle forms an endless loop.
To prevent this use the following code:
public override void Synchronize()
{
    this.DrawFill = true;

    TreeNodeElement treeNodeElement = this.NodeElement;
    RadTreeNode node = treeNodeElement.Data;
    Item dataItem = (Item)node.DataBoundItem;
    if (dataItem != null)
    {
        this.idElement.Text = string.Empty + dataItem.UniqueIdentifier;

        this.textBoxElement.TextChanged -= textBoxElement_TextChanged;
        this.textBoxElement.Text = string.Empty + dataItem.Title;
        this.textBoxElement.TextChanged += textBoxElement_TextChanged;
    }
}