views:

1228

answers:

5

I have a TextBox bound to a ViewModel's Text property with the following setup:

Xaml

<TextBox Text="{Binding Text}"/>

C#

public class ViewModel : INotifyPropertyChanged
{
    public string Text
    {
        get
        {
            return m_Text;
        }
        set
        {
            if (String.Equals(m_Text, value))
            {
                return;
            }

            m_Text = value.ToLower();
            RaisePropertyChanged("Text");
        }
    }

    // Snip
}

When I type some stuff in to the TextBox it successfully sets the Text property on the ViewModel. The problem is that WPF ignores the property changed event that is raised by it's own update. This results in the user not seeing the text they typed converted to lowercase.

How can I change this behaviour so that the TextBox updates with lowercase text?

Note: this is just an example I have used to illustrate the problem of WPF ignoring events. I'm not really interested in converting strings to lowercase or any issues with String.Equals(string, string).

+2  A: 

You can achieve this by raising the event in a seperate dispatcher call using Dispatcher.BeginInvoke

Define a delegate:

private delegate void RaisePropertyChangedDelegate(string property);

Then use the following to raise the event

Dispatcher.CurrentDispatcher.BeginInvoke(
    DispatcherPriority.Normal,
    new RaisePropertyChangedDelegate(RaisePropertyChanged), 
    "Text");
Bubblewrap
I don't really like this solution as it requires the bound object to know about the Dispatcher. It does however solve the problem, so I'm marking it as the answer.
Jacob Stanley
A: 

I remember Rocky Lhotka complaining about this very behaviour on an old episode of .NET Rocks. (Searches for half an hour ...) ah, here we are. Episode 169 from March, 2006:

So if you have got a detailed Form in Windows Forms then you bind all of your properties to those different text boxes and the user is typing things into a text box and tabs off, of course that value gets put into your object but your object then might change the value, may be there is some sort of a manipulation that says all letters must be upper case. It’s a business rule so it goes in your object. If you do that it won’t show up in the UI. In other words the user can type a, b, c, type in lower case, tab off. The lower case a, b, c will stay in the text box. Then later when they change some other field, then they will keep in mind the object to upper case the value, right? So the object has an uppercase a, b, c the UI is incorrectly showing a lowercase, the user then changes some other control and tabs off that control, all of a sudden the a, b, c in uppercase shows up in the text box that they weren’t on.

Rocky doesn't actually suggest a solution to the problem, and I'd hazard that if he hasn't worked it out maybe there's no good answer. Perhaps you need to subscribe to the PropertyChanged event on your object from the code-behind and manually refresh the binding when the property in question has changed.

ps. This isn't directly answering your question, but in the example you've given you could set the CharacterCasing on the TextBox so that it only accepts lower-case characters.

Matt Hamilton
Ha ha - I started typing this answer and then went out for tea. I come back 5 hours later and see you've updated your question to pre-empt me talking about CharacterCasing. Oh well. ;-)
Matt Hamilton
+2  A: 

Apparently this is fixed in the next version of WPF: Karl Shifflett's blog

Robert
A: 

I would dearly love a good solution to this for silverlight.

I'm using 4.0.

Any ideas on an actual workaround for Silverlight?

Many thanks

Matthew Black
A: 

You need to force an update of the binding target (see this post on MSDN). However, this was changed/broken in WPF4, so you have to force an update on the source instead (see this post).

Daniel Rose