2

I'm trying to use the Delay-Property for a WPF Binding. In the following sample are two textboxes binded to the same Property. First one use the Delay-Property, the second one doesn't.

The delay works well. But the unexpected behavior is, that changing the value in TextBox1 does not enable the Button immediately but TextBox2 does. A mouse click, enter key or leaving the textbox with tab key enables the button.

Anybody an idea how I can solve this problem or what the reason is?

View:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<StackPanel>
    <TextBox x:Name="TextBox1" Text="{Binding Value1, UpdateSourceTrigger=PropertyChanged, Delay=1000}"/>
    <TextBox x:Name="TextBox2" Text="{Binding Value1, UpdateSourceTrigger=PropertyChanged}"/>
        <Button Command="{Binding ButtonCommand}" Content="GO!"></Button>
</StackPanel>

CodeBehind:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private const decimal InitialValue = 400;

    private decimal _value1;
    public decimal Value1
    {
        get { return _value1; }
        set
        {
            _value1 = value; 
            OnPropertyChanged();                
        }
    }

    public ICommand ButtonCommand { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        Value1 = InitialValue;
        ButtonCommand = new RelayCommand(x => { /*Do something*/ }, x => Value1 != InitialValue);
        DataContext = this;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}
rhe1980
  • 1,557
  • 1
  • 15
  • 36

2 Answers2

1

The problem is that the WPF commanding system "CanExecute" checks are triggered by Control events, not by changes in the ViewModel.

So what happens is that you enter a number, triggering an event. The binding triggers in response, but due to the delay, it doesn't update the ViewModel property immediately.

Unfortunately, the "CanExecute" check (the delegate in the second parameter of your RelayCommand constructor) for the command also happens in response to you entering a number, and Value1 hasn't changed yet, so the button stays grey as Value1 is still equal to the initial value. Once the delay passes and Value1 changes, "CanExecute" is not rechecked.

You can add CommandManager.InvalidateRequerySuggested(); to your Value1 setter and it should work:

    set
    {
        _value1 = value; 
         OnPropertyChanged();                              
         CommandManager.InvalidateRequerySuggested();           
    }
svinja
  • 5,495
  • 5
  • 25
  • 43
0

I suggest that your RelayCommand is the default implementation of microsoft. So the x => Value1 != InitialValue is the Func<bool> _canExecute condition.

You may need to raise the RaiseCanExecuteChanged event of the RelayCommand after the _canExecute-condition has changed. its not cool but should work i think.

ich2211
  • 275
  • 4
  • 7