我在 WPF 应用程序中遇到了同样的问题,并提出了以下解决方案:
public class DelayedProperty<T> : INotifyPropertyChanged
{
#region Fields
private T actualValue;
private DispatcherTimer timer;
private T value;
#endregion
#region Properties
public T ActualValue => this.actualValue;
public int Delay { get; set; } = 800;
public bool IsPendingChanges => this.timer?.IsEnabled == true;
public T Value
{
get
{
return this.value;
}
set
{
if (this.Delay > 0)
{
this.value = value;
if (timer == null)
{
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(this.Delay);
timer.Tick += ValueChangedTimer_Tick;
}
if (timer.IsEnabled)
{
timer.Stop();
}
timer.Start();
this.RaisePropertyChanged(nameof(IsPendingChanges));
}
else
{
this.value = value;
this.SetField(ref this.actualValue, value);
}
}
}
#endregion
#region Event Handlers
private void ValueChangedTimer_Tick(object sender, EventArgs e)
{
this.FlushValue();
}
#endregion
#region Public Methods
/// <summary>
/// Force any pending changes to be written out.
/// </summary>
public void FlushValue()
{
if (this.IsPendingChanges)
{
this.timer.Stop();
this.SetField(ref this.actualValue, this.value, nameof(ActualValue));
this.RaisePropertyChanged(nameof(IsPendingChanges));
}
}
/// <summary>
/// Ignore the delay and immediately set the value.
/// </summary>
/// <param name="value">The value to set.</param>
public void SetImmediateValue(T value)
{
this.SetField(ref this.actualValue, value, nameof(ActualValue));
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetField<U>(ref U field, U valueField, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<U>.Default.Equals(field, valueField)) { return false; }
field = valueField;
this.RaisePropertyChanged(propertyName);
return true;
}
protected void RaisePropertyChanged(string propertyName)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
要使用它,您需要创建如下属性:
public DelayedProperty<string> Name { get;set; } // Your choice of DP or INPC if you desire.
并将您的文本框更改为:
<TextBox Text="{Binding Name.Value, UpdateSourceTrigger=PropertyChanged}" />
那么在处理SaveChanges命令时可以调用:
this.Name?.FlushValue();
然后,您将能够从属性访问 ActualValue。我目前订阅了 Name 属性上的 PropertyChanged 事件,但我正在考虑为此创建一个特定事件。
我希望找到一个更易于使用的解决方案,但这是我目前能想到的最好的解决方案。