TextBox.TextChanged event firing twice on Windows Phone 7 emulator

14,671

Solution 1

The reason the TextChanged event fires twice in WP7 is a side effect of how the TextBox has been templated for the Metro look.

If you edit the TextBox template in Blend you will see that it contains a secondary TextBox for the disabled/read-only state. This causes, as a side effect, the event to fire twice.

You can change the template to remove the extra TextBox (and associated states) if you don't need these states, or modify the template to achieve a different look in the disabled/read-only state, without using a secondary TextBox.

With that, the event will fire only once.

Solution 2

i'd go for the bug, mainly because if you put the KeyDown and KeyUp events in there, it shows that that they are fired only once (each of them) but the TextBoxChanged event is fired twice

Solution 3

That does sound like a bug to me. As a workaround, you could always use Rx's DistinctUntilChanged. There is an overload that allows you to specify the distinct key.

This extension method returns the observable TextChanged event but skips consecutive duplicates:

public static IObservable<IEvent<TextChangedEventArgs>> GetTextChanged(
    this TextBox tb)
{
    return Observable.FromEvent<TextChangedEventArgs>(
               h => textBox1.TextChanged += h, 
               h => textBox1.TextChanged -= h
           )
           .DistinctUntilChanged(t => t.Text);
}

Once the bug is fixed you can simply remove the DistinctUntilChanged line.

Solution 4

Nice! I found this question by searching for a related problem and also found this annoying thing in my code. Double event eats more CPU resources in my case. So, I fixed my real-time filter textbox with this solution:

private string filterText = String.Empty;

private void SearchBoxUpdated( object sender, TextChangedEventArgs e )
{
    if ( filterText != filterTextBox.Text )
    {
        // one call per change
        filterText = filterTextBox.Text;
        ...
    }

}

Solution 5

I believe this has always been a bug in the Compact Framework. It must have been carried over into WP7.

Share:
14,671
Jon Skeet
Author by

Jon Skeet

Author of C# in Depth. Currently a software engineer at Google, London. Usually a Microsoft MVP (C#, 2003-2010, 2011-) Sites: C# in Depth Coding blog C# articles Twitter updates (@jonskeet) Email: [email protected] (but please read my blog post on Stack Overflow-related emails first)

Updated on June 02, 2022

Comments

  • Jon Skeet
    Jon Skeet almost 2 years

    I have a very simple test app just to play around with Windows Phone 7. I've just added a TextBox and a TextBlock to the standard UI template. The only custom code is the following:

    public partial class MainPage : PhoneApplicationPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
    
        private int counter = 0;
    
        private void TextBoxChanged(object sender, TextChangedEventArgs e)
        {
            textBlock1.Text += "Text changed " + (counter++) + "\r\n";
        }
    }
    

    The TextBox.TextChanged event is wired up to TextBoxChanged in the XAML:

    <TextBox Height="72" HorizontalAlignment="Left" Margin="6,37,0,0"
             Name="textBox1" Text="" VerticalAlignment="Top"
             Width="460" TextChanged="TextBoxChanged" />
    

    However, every time I press a key when running in the emulator (either the on-screen keyboard or the physical one, having pressed Pause to enable the latter) it increments the counter twice, displaying two lines in the TextBlock. Everything I've tried shows that the event is genuinely firing twice, and I've no idea why. I've verified that it's only being subscribed once - if I unsubscribe in the MainPage constructor, nothing happens at all (to the text block) when the text changes.

    I've tried the equivalent code in a regular Silverlight app, and it didn't occur there. I don't have a physical phone to reproduce this with at the moment. I haven't found any record of this being a known problem in the Windows Phone 7.

    Can anyone explain what I'm doing wrong, or should I report this as a bug?

    EDIT: To reduce the possibility of this being down to having two text controls, I've tried removing the TextBlock completely, and changing the TextBoxChanged method to just increment counter. I've then run in the emulator, typed 10 letters and then put a breakpoint on the counter++; line (just to get rid of any possibility that breaking into the debugger is causing issues) - and it shows counter as 20.

    EDIT: I've now asked in the Windows Phone 7 forum... we'll see what happens.

  • Jon Skeet
    Jon Skeet almost 14 years
    I'm not sure that that will work around it - the problem isn't the event handler firing because of textBlock1.Text changing - I'll give it a try though. (The workaround I was going to try was to make my eventhandler stateful, remembering the previous text. If it hasn't actually changed, ignore it :)
  • Jon Skeet
    Jon Skeet almost 14 years
    @undertakeror: Thanks for checking out that bit. I'll ask the same question on the WP7-specific forum and see what the response is...
  • MordechayS
    MordechayS almost 14 years
    What does TextInput do? These seems like quite a big bug to slip through the unit tests of the WP7, but then it is SL
  • Jon Skeet
    Jon Skeet almost 14 years
    @Chris S: What do you mean by "What does TextInput do?" I'm not familiar with TextInput...
  • Jon Skeet
    Jon Skeet almost 14 years
    I'm not the one passing any event args - I'm implementing an event handler. But I've verified that adding the event handler purely in C# makes no difference... it still gets fired twice.
  • Pimp Juice McJones
    Pimp Juice McJones almost 14 years
    OK, hmmm. Yeah, if it's pure c# then it sounds more like a bug. About by first suggestion- I'm sorry my verbage was horrible, how I should have stated is- I'd try [in your implementation/TextBoxChanged handler method] change the args parameter type to just plain eventargs. Probably won't work... but hey... it was just my first thought.
  • Pimp Juice McJones
    Pimp Juice McJones almost 14 years
    In other words, it probably won't work but I'd try method signature = private void TextBoxChanged(object sender, EventArgs e) just to say that I tried it =)
  • MordechayS
    MordechayS almost 14 years
    @Jon ` OnTextInput(TextCompositionEventArgs e)` is the SL way of handling text input instead of KeyDown, as obviously the device may not have a keyboard: "Occurs when a UI element gets text in a device-independent manner" msdn.microsoft.com/en-us/library/…
  • MordechayS
    MordechayS almost 14 years
    I was just curious if that fired twice as well
  • Jon Skeet
    Jon Skeet almost 14 years
    Right. I don't think that will have any effective, I'm afraid.
  • Jon Skeet
    Jon Skeet over 13 years
    @Chris: I'll give it a try if I have time :)
  • Jon Skeet
    Jon Skeet over 13 years
    I thought it was fixed in a more recent version of the CF... and it would be weird to get in despite the move to Silverlight. On the other hand, it's a pretty weird bug to see anyway...
  • Jerod Houghtelling
    Jerod Houghtelling over 13 years
    I agree that it is strange. I reran into it yesterday in a CF 2.0 application.
  • Jon Skeet
    Jon Skeet over 13 years
    From the question: "I've just added a TextBox and a TextBlock to the standard UI template" - they're not the same thing. I've got one TextBox which the user can type into, and one TextBlock which displays the count.