4

I have two textboxes on a Winform. The idea is to enter Fahrenheit in one box and have it present Celcius in the other as the user types, and vice versa.

I have it working fine using the 'Leave' method of the textbox but I was trying to use the TextChanged method to avoid having to click or press a button for the result.

The problem I have now is that when the first character is processed the focus moves to the second box, which fires the TextChanged method.

I've tried using the sender to enable an if() but the sender is now the destination box.

Any thoughts, please?

       private void TB_Fahrenheit_TextChanged(object sender, EventArgs e)
    {

        float C, F;

        if (TB_Fahrenheit.Text != "")
        {
            if (float.Parse(TB_Fahrenheit.Text) < 1.0F)
            {
                TB_Fahrenheit.Text = "0" + TB_Fahrenheit.Text;
            }

            F = float.Parse(TB_Fahrenheit.Text);
            C = ((F - 32) * 5) / 9;
            TB_Celcius.Text = C.ToString();
        }

    }

    private void TB_Celcius_TextChanged(object sender, EventArgs e)
    {
        float C, F;
        string SentBy = ((TextBox)sender).Name;

        MessageBox.Show(SentBy);
        return;

        if(SentBy != TB_Fahrenheit.Text)
        {

        if (TB_Celcius.Text != "")
        {
            if (float.Parse(TB_Celcius.Text) < 1.0F)
            {
                TB_Celcius.Text = "0" + TB_Celcius.Text;
            }

            C = float.Parse(TB_Celcius.Text);
            F = ((C * 9) / 5) + 32;
            TB_Fahrenheit.Text = F.ToString();
        }
        }

    }

    private void TB_Celcius_Enter(object sender, EventArgs e)
    {
        TB_Celcius.Clear();
        TB_Fahrenheit.Clear();
    }

    private void TB_Fahrenheit_Enter(object sender, EventArgs e)
    {
        TB_Celcius.Clear();
        TB_Fahrenheit.Clear();
    }
Cimbian
  • 173
  • 2
  • 3
  • 12

4 Answers4

3

I would use a Boolean checker.You are changing the text of a text box that has a text changed event. You need to make sure it does nothing if the other box is currently being edited. My example

private void setSliderValue(int currentAudioSecond)
{
    valueFromTimer = true;
    //Do Stuff
    valueFromTimer = false;
}

Then when the value is changed on my slider control:

private void sliderAudio_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    if (!valueFromTimer)
    {
        //Do stuff  
    }
}

I have to do this often when loading up a window, or form, I fill a combo box. To avoid the selected value/index changed to fire, I have to implement a flag like this.

Andrew Grinder
  • 585
  • 5
  • 21
  • 2
    Great idea. I use a similar method anytime I have a project with a DataGrid or other UI element where I may be programatically changing an element. This way I can avoid firing an event if I am programatically changing an element that the user may also be able to edit. – AdamMc331 Aug 05 '14 at 18:42
  • 1
    Andrew, I found something similar and this is now working for me. Thanks. Steve. – Cimbian Aug 05 '14 at 19:05
2

I would simply subscribe and unsubscribe to the event on both Control.Enter Event and Control.Leave Event.

When you Enter the fahrenheitTextBox, it would deactivate the TextChanged Event of your celsiusTextBox. The same will happen when the celsiusTextBox is entered, your fahrenheitTextBox.TextChanged event would be unsubscribed, allowing you to take advantage of the proper event, the TextChanged Event, to achieve your goal.

In addition to it, I would discourage the use of mathematic formulas within your GUI, as you may have it wrong, and it is hard to test. It would be better to have a static Convert class with proper methods for the conversion you need.

public static class Convert {
    public float ToFahrenheit(float celsius) {
        float f = celsius * 9 / 5 + 32;
        return f;
    }

    public float ToCelsius(float fahrenheit) {
        float c = (fahrenheit - 32) * 5 / 9;
        return c;
    }
}

Then you could write your unit tests.

[TestMethod]
public void ZeroCelsiusShouldConvertTo32Fahrenheit() {
    // Given
    float expected 32.0;
    float celsius = 0.0;        


    // When
    var actual = Convert.ToFahrenheit(celsius);

    // Then
    Assert.AreEqual(typeof(float), actual);
    Assert.AreEqual(expected, actual);
}
Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162
  • Will, Thanks. I did some more hunting around and I am basically doing this now but setting a bool as a flag on the Enter event. I will detect the flag in the TextChanged method. Appreciate the help. Steve. – Cimbian Aug 05 '14 at 19:04
1

I think you must use the Leave event instead of TextChanged.Because it is raised when

  1. you change the focus by using the keyboard (TAB, SHIFT+TAB, and so on), by calling the Select or SelectNextControl methods, or by setting the ContainerControl.ActiveControl property to the current form.

  2. When you change the focus by using the mouse or by calling the Focus method.

Lamloumi Afif
  • 8,941
  • 26
  • 98
  • 191
0

I would suggest using the KeyPress event to calculate the value in the other TextBox, something like this, although you'd have to do some format checking on the float.Parse to make sure you have a numeric value.

        private void TB_Fahrenheit_KeyPress(object sender, KeyPressEventArgs e)
    {
        float C, F;

        if (TB_Fahrenheit.Text != "")
        {
            if (float.Parse(TB_Fahrenheit.Text) < 1.0F)
            {
                TB_Fahrenheit.Text = "0" + TB_Fahrenheit.Text;
            }

            F = float.Parse(TB_Fahrenheit.Text);
            C = ((F - 32) * 5) / 9;
            TB_Celcius.Text = C.ToString();
        }
    }

    private void TB_Celcius_KeyPress(object sender, KeyPressEventArgs e)
    {
        float C, F;
        string SentBy = ((TextBox)sender).Name;


        if (TB_Celcius.Text != "")
        {
            if (float.Parse(TB_Celcius.Text) < 1.0F)
            {
                TB_Celcius.Text = "0" + TB_Celcius.Text;
            }

            C = float.Parse(TB_Celcius.Text);
            F = ((C * 9) / 5) + 32;
            TB_Fahrenheit.Text = F.ToString();
        }

    }
LarzStarz
  • 96
  • 3
  • 1
    I'm using the KeyPress event to build my string and check each input for a digit, decimal or sign but the string value is not available until the focus is moved or via TextChanged (I think). – Cimbian Aug 05 '14 at 19:12