2016-01-20 92 views
3

我有一个文本框用结合:WPF图形用户界面没有更新,虽然主线程运行

<TextBox Text="{Binding TestString, UpdateSourceTrigger=PropertyChanged}" /> 

这里将TestString实现:

private string testString; 
    public string TestString 
    { 
     get { return testString; } 
     set 
     { 
      if (testString != value) 
      { 
       testString = value; 
       PropChanged(); // INotifyPropertyChanged Implementation .. 
       System.Threading.Thread.Sleep(100); 
      } 
     } 
    } 

将TestString属性的set方法需要几毫秒(例如,您可以用100ms的睡眠时间进行测试),然后如果按住一个字母键,则首先用两个字母看到编辑的更新,然后GUI会一直停止更新/刷新字母键。如果密钥被释放,gui会继续更新。我知道长时间运行的动作我应该使用异步编程机制,但令人讨厌的是,我不完全知道当WPF开始不再更新时的阈值是多少。 我个人不希望为持续5或10或100ms的短操作实现异步开销,因为UI仍然足够响应(如果WPF会更新...)。

有谁知道为什么会发生这种情况,或者我可以如何解决这个问题而不使用异步编程?

在Borland VCL中(我猜在WinForms中),这根本不是问题,因为GUI在每个关键事件之后都会更新。

顺便说一句,如果您使用滑块,那么比鼠标键有更多的UI mousemove事件,并且如果使用滑块更新GUI,WPF也没有问题,即使ui线程中的操作持续很长时间(唯一的一点是ui反应更慢)。

+1

请TestString'财产 – StepUp

回答

1

不要在您的setter中放置任何同步逻辑。通常我不会推荐把逻辑放在你的setter中,但是当你这样做时 - 这是异步执行的。否则,您的用户界面将会像您所描述的那样被阻止

private string _testString; 

public string TestString 
{ 
    get { return _testString; } 
    set 
    { 
     // Custom Method, returns true if property has changed 
     if (SetProperty(ref _testString, value)) 
     { 
      DoSomeStuff(); 
     } 
    } 
} 

private async void DoSomeStuff() 
{ 
    // Do long lasting calls here 
    await Task.Delay(3000); 
} 
+0

。当然'显示的实施,我可以......但我想知道为什么会这样。 我怎么知道这个动作对于二传手来说太长了? 无论如何您的答案! – Lumo

+0

你将什么样的逻辑放入setter中会很有趣。在主线程(UI线程)上执行的每个“持久”操作都会冻结您的用户界面。你如何定义“持久的任务”是你的定义。通常服务电话,计算,数据库访问等 –

0

wpf中的主线程(UI线程)基本上是无限循环的其他东西。循环基本上这样做:

  1. 处理所有事件; 2.提供用户界面; 1.处理所有事件; 2.渲染UI等

所以当你按下键时,它会触发一个事件并在复选框中改变文本。然后wpf数据绑定更改TestStrin g属性,并且毕竟完成后,UI将呈现为

现在,循环重复。第一步是处理所有事件。但是由于上一个周期需要更长的时间,因此需要处理很多事件(事件缓存在某处)。在UI呈现之前,多个事件会多次更改TestString属性。所以这个循环比第一个事件的事件更多,下一个事件必须处理更多的事件,并且你的UI线程被事件处理程序充斥。

那么你在一个循环中有多少时间?错误的问题。除此之外,这取决于客户的个人电脑设置以及他的键盘速度有多快(按住按键的次数是多少次)。

你应该这样编写代码,即使事件被多次触发,也不会在事件处理中泛滥UI线程。

编辑: 你可能感兴趣Binding.Delay属性。例如,延迟100ms告诉WPF更新绑定源(本例中为TestString),每秒至多10x更新事件,如果TextBox.Text已更改25x次。

另一个解决方案是Reactive Extensions库。它基本上可以帮助你使用类似运算符的linq处理事件。例如:

Observable.FromEvent<PropertyChangedEventArs)(this, nameof(PropertyChanged)) 
    .Where(e => e.PropertyName == nameof(TestString)) 
    .Sample(TimeSpan.FromMiliseconds(100)) 
    .Subscribe(() => Thread.Sleep(...)) 
相关问题