2016-11-22 57 views
0

我创建了一个例子来说明我的问题时避免闪烁。如何使用异步绑定

视图模型:

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

我发现了一种避免闪烁的方法,只是从文本框继承并覆盖它的textproperty元数据。

定制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> 

有文字结合没有一个fallbackvalue是很重要的。因此,在更新过程中,文本被设置为文本属性defalut值 - 因此在这种情况下为null

CoerceChanged处理程序检查新值是否为空。如果是这样,他会返回旧值,以便在更新过程中仍显示旧值。

+0

一个有趣的解决方案..虽然我不认为这是正确的说你在这里重写..它更像是注册你的派生类型(配置概念)与处理程序..你也可以把一个解析器模式。如果你在调用'TextProperty.OverrideMetadata'的时候输入了'typeof(TextBox)',它会不会调用处理程序并提供相同的结果?如果你同时指定了'typeof(CustomTextBox)'和'typeof(TextBox)处理程序会触发两次吗? –

+0

@BrettCaswell,不可能使用'typeof(TextBox)' - 你会得到一个异常。因为已经为textbox textproperty注册了元数据。 – ManDani

0

有时绑定会失败,失败是重要的考虑因素。如果发生错误,则回退值选项向用户显示消息,而不是什么都没有发生。如果你想你的fallbackvalue显示包含于前值,我能想到的尝试几种方法:在参考字符串值可能保存和/或其他控件,然后绑定到控制

但是,如果你不希望显示fallbackvalue,你需要做一个代码检查,看看你的绑定失败或缓慢,并将其包含在你的代码中

+0

他的绑定不​​失败。它只是显示回退值,直到属性获取器返回。 –

+0

@Peter,这就是我如何了解后备值是什么,但我编辑了我的答案,其中包括响应缓慢 – JohnChris

+0

@ManDani,我会去找Peters解决方案,但是如果您想坚持自己的方式并尝试,请尝试绑定将Fallback值保存到隐藏控件中,保存显示的前一个值的字符串 – JohnChris

1

这对我来说似乎很正常,因为你是在你的绑定中使用IsAsync=True。从the documentation

在等待值到达,结合报告FallbackValue,如果可用

PropertyChanged事件引发,WPF启动更新的目标的过程捆绑。通常这会同步发生,立即调用属性getter来更新值。

但是您使用的是IsAysnc=True,所以WPF使用回退值填充目标,然后启动异步请求以稍后检索实际属性值。在该请求完成之前,会显示故障预置值。

有没有人知道在更新过程中显示FallbackValue的目的或有什么好处?

根据文档,IsAsync=True设置背后的意图是当属性获取器的速度慢或可能慢时使用。您的代码告诉WPF该属性值已更改,因此它知道旧值不再有效。你的代码也告诉(通过XAML中的IsAsync)属性获取器可能需要一些时间来提供新值,所以它推迟检索该值直到以后。

同时,WPF应该展示什么?这就是后备价值所在。

有没有办法在异步更新过程中显示旧值?

如果您不希望为WPF中的此功能设计的行为,您应该自己异步检索新数据,并在您拥有它时通过setter更新属性。无论如何,一个属性获取者的速度并不是一个好主意,所以无论如何这都是一个更好的设计。

+0

我同意这一点。虽然在我的情况下,我没有一个缓慢的吸气。正如你所看到的,显示的值变化非常快。在我的真实应用程序中有几个文本框 - 所以视图需要很多时间。通过设置IsAsnyc = True,我试图避免冻结的视图。所以在我的情况下,显示FallbackValue是没有意义的 - 这只会导致闪烁。 – ManDani

+1

_“在我的情况下,我没有缓慢的吸气剂”_ - 那么你使用IsAsync = True的动机是什么?什么“冻结的看法”发生,为什么? WPF可以轻松显示任何合理数量的文本框和其他控件,而不会有明显的滞后;当你有足够的屏幕控制来减慢速度时,用户无论如何都无法理解。这对我来说听起来像是你真正的问题不应该是关于'IsAsync'(你可能不应该使用它),而应该是关于改善你的真实世界场景的用户体验。 –