WPF 延迟绑定无法正常工作
WPF Binding with Delay does not work properly
我正在尝试将 Delay-属性 用于 WPF 绑定。在以下示例中,两个文本框绑定到同一个 属性。第一个使用 Delay-属性,第二个不使用。
延迟效果很好。但意外的行为是,更改 TextBox1 中的值不会立即启用 Button,但 TextBox2 会。单击鼠标、回车键或使用 Tab 键离开文本框可启用该按钮。
有人知道我该如何解决这个问题或原因是什么吗?
查看:
<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>
代码隐藏:
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));
}
}
我建议你的RelayCommand是微软的默认实现。所以 x => Value1 != InitialValue
是 Func<bool> _canExecute
条件。
您可能需要在 _canExecute 条件更改后引发 RelayCommand
的 RaiseCanExecuteChanged
事件。它不酷,但我认为应该可以。
问题是 WPF 命令系统 "CanExecute" 检查是由 Control
事件触发的,而不是由 ViewModel 中的更改触发的。
所以发生的事情是你输入一个数字,触发一个事件。绑定触发响应,但由于延迟,它不会立即更新 ViewModel 属性。
不幸的是,命令的 "CanExecute" 检查(RelayCommand
构造函数的第二个参数中的委托)也会响应您输入的数字而发生,并且 Value1
没有' 尚未更改,因此按钮保持灰色,因为 Value1
仍等于初始值。一旦延迟过去并且 Value1
发生变化,将不会重新检查 "CanExecute"。
您可以将 CommandManager.InvalidateRequerySuggested();
添加到您的 Value1
setter 并且它应该有效:
set
{
_value1 = value;
OnPropertyChanged();
CommandManager.InvalidateRequerySuggested();
}
我正在尝试将 Delay-属性 用于 WPF 绑定。在以下示例中,两个文本框绑定到同一个 属性。第一个使用 Delay-属性,第二个不使用。
延迟效果很好。但意外的行为是,更改 TextBox1 中的值不会立即启用 Button,但 TextBox2 会。单击鼠标、回车键或使用 Tab 键离开文本框可启用该按钮。
有人知道我该如何解决这个问题或原因是什么吗?
查看:
<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>
代码隐藏:
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));
}
}
我建议你的RelayCommand是微软的默认实现。所以 x => Value1 != InitialValue
是 Func<bool> _canExecute
条件。
您可能需要在 _canExecute 条件更改后引发 RelayCommand
的 RaiseCanExecuteChanged
事件。它不酷,但我认为应该可以。
问题是 WPF 命令系统 "CanExecute" 检查是由 Control
事件触发的,而不是由 ViewModel 中的更改触发的。
所以发生的事情是你输入一个数字,触发一个事件。绑定触发响应,但由于延迟,它不会立即更新 ViewModel 属性。
不幸的是,命令的 "CanExecute" 检查(RelayCommand
构造函数的第二个参数中的委托)也会响应您输入的数字而发生,并且 Value1
没有' 尚未更改,因此按钮保持灰色,因为 Value1
仍等于初始值。一旦延迟过去并且 Value1
发生变化,将不会重新检查 "CanExecute"。
您可以将 CommandManager.InvalidateRequerySuggested();
添加到您的 Value1
setter 并且它应该有效:
set
{
_value1 = value;
OnPropertyChanged();
CommandManager.InvalidateRequerySuggested();
}