我已经创建了一个例子来说明我的问题。
视图模型:
public class VM : INotifyPropertyChanged
{
private double _value = 1;
public double Value
{
get { return _value; }
set
{
_value = value;
OnPropertyChanged();
}
}
public VM()
{
var timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromTicks(1);
timer.Tick += (s, e) => { Value += 1; };
timer.Start();
}
// OnPropertyChanged stuff ...
}
}
查看:
<Window.DataContext>
<namespace:VM/>
</Window.DataContext>
<Grid>
<TextBox Text="{Binding Value, IsAsync=True, FallbackValue=Test}"/>
</Grid>
运行我的应用程序时,文本框中的文字会闪烁。在更新过程中,会显示FallbackValue,这对我来说毫无意义。
有谁知道更新过程中显示FallbackValue的目的或有什么好处?有没有办法在异步更新过程中显示旧值?
答案 0 :(得分:2)
鉴于您在绑定中使用IsAsync=True
,这对我来说似乎很正常。来自the documentation:
在等待值到达时,绑定会报告FallbackValue(如果有的话)
当引发PropertyChanged
事件时,WPF会启动更新绑定目标的过程。通常这会同步发生,并立即调用属性getter来更新值。
但是您使用的是IsAysnc=True
,因此WPF会使用回退值填充目标,并启动异步请求以便稍后检索实际的属性值。在该请求完成之前,将显示后备值。
有谁知道更新过程中显示FallbackValue的目的或有什么好处?
根据文档,IsAsync=True
设置背后的意图是当属性getter是或可能很慢时使用它。您的代码告诉WPF属性值已更改,因此它知道旧值不再有效。您的代码还告诉(通过XAML中的IsAsync
)属性获取器可能需要一些时间来提供新值,因此它会延迟检索该值直到以后。
与此同时,WPF应该展示什么?这就是后备价值所在。
有没有办法在异步更新过程中显示旧值?
如果您不想要在WPF中为此功能设计的行为,您应该自己异步检索新数据,并在拥有它时通过setter更新属性。对于物业吸气者而言,无论如何都不是一个好主意,所以无论如何这将是一个更好的设计。
答案 1 :(得分:1)
我遇到了同样的问题,但有图像源。我已经删除了绑定上的 IsAsync
并且我已经让我的 getter 异步了:
// This field hold a copy of the thumbnail.
BitmapImage thumbnail;
// Boolean to avoid loading the image multiple times.
bool loadThumbnailInProgress;
// I'm using object as the type of the property in order to be able to return
// UnsetValue.
public object Thumbnail
{
get {
if (thumbnail != null) return thumbnail;
if (!loadThumbnailInProgress) {
// Using BeginInvoke() allow to load the image asynchronously.
dispatcher.BeginInvoke(new Action(() => {
thumbnail = LoadThumbnail();
RaisePropertyChanged(nameof(Thumbnail));
}));
loadThumbnailInProgress = true;
}
// Returning UnsetValue tells WPF to use the fallback value.
return DependencyProperty.UnsetValue;
}
}
答案 2 :(得分:0)
有时绑定会失败,失败很重要。如果发生错误,后备值选项会向用户显示消息,而不是发生任何事情。如果您希望您的fallbackvalue显示包含的先前值,我可以考虑一些尝试方法:可能将值保存在引用字符串和/或另一个控件中,然后绑定到该控件
但是如果您根本不想显示回退值,则需要进行代码检查,以查看绑定失败的方式/或是否很慢,并将其包含在您的代码中
答案 3 :(得分:0)
我找到了一种避免闪烁的方法,只需继承文本框并覆盖它的textproperty-metadata。
自定义TextBoxControl
public class CustomTextBox : TextBox
{
static CustomTextBox()
{
TextProperty.OverrideMetadata(typeof(CustomTextBox), new FrameworkPropertyMetadata(null, null, CoerceChanged));
}
private static object CoerceChanged(DependencyObject d, object basevalue)
{
var tb = d as TextBox;
if (basevalue == null)
{
return tb.Text;
}
return basevalue;
}
}
查看强>
<Window.DataContext>
<namespace:VM/>
</Window.DataContext>
<Grid>
<namespace:CustomTextBox Text="{Binding Value, IsAsync=True}"/>
</Grid>
让文本绑定没有后备值非常重要。因此,在更新过程中,文本设置为textproperty defalut值 - 因此在本例中为 null 。
CoerceChanged处理程序检查新值是否为null。如果是这样,他返回旧值,以便在更新过程中仍然显示旧值。