Jacob Stanley
Jacob Stanley

Reputation: 4824

How to stop a WPF binding from ignoring the PropertyChanged event that it caused?

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).

Upvotes: 3

Views: 5913

Answers (4)

Robert
Robert

Reputation: 545

Apparently this is fixed in WPF 4.0 in .NET Framework 4.0 released in 2010: Karl Shifflett's blog

Upvotes: 2

Daniel Rose
Daniel Rose

Reputation: 17648

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).

Upvotes: 0

Matt Hamilton
Matt Hamilton

Reputation: 204239

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.

Upvotes: 0

Bubblewrap
Bubblewrap

Reputation: 7526

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");

Upvotes: 2

Related Questions