TextBox.TextChanged event

Hi everyone,

I am in trouble with TextBox.TextChanged event. When I tried to change value in TextBox in order to manipulate geometry, it doesn’t wait me complete what I want to type in TextBox. For example, When I want to type 284 in to TextBox, TextBox.TextChanged event firing immediately after 2…

Lets look it in example.

using Eto.Forms;
using Rhino.Geometry;
using Rhino.UI;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows.Input;

namespace TestObject
{
    // This class is inherited from EtoCollapsibleSection
    public class TestObjectCollapsibleSection : Section 
    {
        #region Fields - Eto.Forms Controls

        private readonly LocalizeStringPair caption;
        private Label testLabel;
        private TextBox testTextBox;

        #endregion Fields - Eto.Forms Controls


        #region Properties

        public TestObjectController TestObjectController { get; set; }

        /// <summary>
        /// This property overriden from Section class to define unique caption of related section
        /// </summary>
        public override LocalizeStringPair Caption
        {
            get { return caption; }
        }

        ///<summary>
        /// The Heigth of the section, it is calculated from height of content that
        /// defined InitializeLayout() method
        ///</summary>
        public override int SectionHeight
        {
            get
            {
                return this.Content.Height;
            }
        }

        #endregion Properties

        #region Constructor

        public TestObjectCollapsibleSection (TestObjectController testObjectController)
        {
             caption = new LocalizeStringPair("Test Section", "Test Section");
             TestObjectController = testObjectController;
             InitializeComponents();
             InitializeLayout();
             RegisterControlEvents();
        }

        #endregion Constructor

        #region Initialization methods

        private void InitializeComponents()
        {
            testLabel = new Label()
            {
                Text = "Test Value:",
                VerticalAlignment = VerticalAlignment.Center,
                TextAlignment = TextAlignment.Right,
                Width = 100
            };

            testTextBox = new TextBox()
            {
                Text = "0",
                Enabled = false 
            };
        }

        private void InitializeLayout()
        {
            TableLayout layout = new TableLayout()
            {
                // Padding around the table
                Padding = 5,
                // Spacing between table cells
                Spacing = new Eto.Drawing.Size(15, 15),
                Rows =
                {
                    new TableRow(testLabel, testTextBox),
                }
            };
            Content = layout;
        }

        /// <summary>
        /// Struggling with this event,
        /// It's not wait to complete what I want to type
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TestTextBox_TextChanged(object sender, EventArgs e)
        {
            UnregisterControlEvents();

            double newValue = double.Parse(testTextBox.Text);
            TestObjectController.ChangeSelectedTestObjectParameter<Height, double>(newValue);

            RegisterControlEvents();
        }

        private void TestObjectController_TestObjectSelected()
        {
            UnregisterControlEvents();
            // Fill textBox here according to geometry has selected, for example
            // Height of the box

            // Let's assume that this guid object's guid
            Guid guid = Guid.Empty;
            testTextBox.Text = TestObjectController.SelectedTestObjects[guid].Height.ToString();
            testTextBox.Enabled = true;

            RegisterControlEvents();
        }

        private void TestObjectController_TestObjectDeselected()
        {
            UnregisterControlEvents();
            // Fill textBox here according to geometry has selected, for example
            // Height of the box

            testTextBox.Text = "0";
            testTextBox.Enabled = false;

            RegisterControlEvents();
        }

        private void RegisterControlEvents()
        {
             TestObjectController.TestObjectSelected += TestObjectController_TestObjectSelected;
             TestObjectController.TestObjectDeselected += TestObjectController_TestObjectDeselected;
             testTextBox.TextChanged += TestTextBox_TextChanged;
        }
        private void UnregisterControlEvents()
        {
            TestObjectController.TestObjectSelected -= TestObjectController_TestObjectSelected;
            TestObjectController.TestObjectDeselected -= TestObjectController_TestObjectDeselected;
            testTextBox.TextChanged -= TestTextBox_TextChanged;
        }

        #endregion Initialization methods
    }

    public class TestObject
    {
        // let's assume that TestObject simply Box object as brep

        public double Height { get; set; }

        public Curve BorderCurve { get; set; }

        public TestObject(Curve curve, double height)
        {
            // There is a method which is creates Brep using with curve and height
        }
    }

    public class TestObjectController
    {
        public Dictionary<Guid, TestObject> TestObjects { get; set; }
        public Dictionary<Guid, TestObject> SelectedTestObjects { get; set; }

        public TestObjectController()
        {
            TestObjects = new Dictionary<Guid, TestObject>();
            SelectedTestObjects = new Dictionary<Guid, TestObject>();
        }

        public event TestObjectEvents.TestObjectSelectionEvents TestObjectSelected;
        public event TestObjectEvents.TestObjectSelectionEvents TestObjectDeselected;

        internal void ChangeSelectedTestObjectParameter<T1, T2>(T2 newValue)
        {
            // this method recreates this object and handle dictionaries
        }
    }

    public class TestObjectEvents
    {
        public delegate void TestObjectSelectionEvents();
    }
}

Has anyone suggestion for best practice for TextBoxes?
Thanks in advance

-Oğuzhan

Instead of OnTextChanged you could check OnKeyUp so that when you find that user released Enter you’d do whatever you need to do. The event LostFocus might work too, if you want tab key or clicking outside of the textbox to work too as confirmation.

1 Like

Hi @nathanletwory,

I found main problem, it was problematic because of OnRhinoIdle. When I use below structure the problem solved.

private void TestTextBox_GotFocus(object sender, EventArgs e)
{
    TestObjectController.UnhookRhinoIdle();
}

private void TestTextBox_LostFocus(object sender, EventArgs e)
{
    TestObjectController.HookRhinoIdle();
}

private void TestTextBox_KeyUp(object sender, KeyEventArgs e)
{
    if (e.Key == Keys.Enter)
    {
        UnregisterControlEvents();
        UnregisterSelectionEvents();
        double newValue = double.Parse(TestTextBox.Text);
        TestObjectController.ChangeSelectedTestObjectParameter<T1, double>(newValue);
        RegisterControlEvents();
        RegisterSelectionEvents();
        EnableRhinoIdle();
    }
}

Thanks for your advice.
-Oğuzhan

@nathanletwory,

I have extra question. I am working as cross-platform, in Windows everything working as desired with above event structure. But in Mac, nothing change when I type new value in order to manipulate geometry. TextBox keeps value same as before.

Do you dave any idea about what can cause this difference between Windows and Mac?