我有一个带有绑定的文本框:
<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的Sleep来测试它),然后如果按住一个字母键,你首先会看到带有几个字母的编辑更新然后GUI会在您按住一个字母键时停止更新/刷新。如果密钥被释放,gui会继续更新。
我知道对于长时间运行的操作,我应该使用异步编程机制,但令人讨厌的是,我不知道什么是WPF开始不再更新时的阈值。 我个人不希望为持续5或10或100ms的短动作实现异步开销,因为UI仍然足够响应(如果WPF会更新......)。
有没有人知道为什么会这样,或者我如何在不使用异步编程的情况下解决这个问题?
在Borland VCL中(我想在WinForms中)这根本不是问题,因为GUI在每次关键事件后都在更新。
顺便说一句,如果你使用滑块,那么除了持有键之外,还有更多的UI mousemove事件,如果使用滑块,WPF在更新GUI时没有问题,即使ui线程中的操作持续很长时间(唯一的问题是ui反应更慢。)
答案 0 :(得分:1)
不要在你的setter中放置任何同步逻辑。通常我不会建议在你的setter中放入逻辑,但是当你这样做时 - 异步进行。否则,您的UI将被阻止,如您所述。
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);
}
答案 1 :(得分:0)
因此,当您按下键时,它会触发一个事件并更改复选框中的文本。 wpf数据绑定然后更改TestStrin
g属性,并且在完成所有操作后,将呈现UI
现在,循环重复。第一步是处理所有事件。但由于上一个周期需要更长时间,因此需要处理很多事件(事件在某处缓冲)。在UI呈现之前,多个事件会多次更改TestString属性。因此,这个循环比第一个循环更多,下一个循环将需要处理更多事件,并且您的UI线程充满了事件处理程序。
那么你在一个循环循环中有多少时间?错误的问题。其中,它取决于客户端的PC设置以及他的键盘有多快(当你按住它时,键的重复频率是多少)。
您应该以这样的方式编写代码,即使事件多次触发,您也不会在事件处理过程中泛滥UI线程。
修改强>
您可能对Binding.Delay财产感兴趣。例如,延迟100ms告诉WPF最多每秒10次更新绑定源(在本例中为TestString),如果TextBox.Text
已更改25次,则为事件。
另一个解决方案是Reactive Extensions
库。它基本上可以帮助您使用linq like运算符处理事件。例如:
Observable.FromEvent<PropertyChangedEventArs)(this, nameof(PropertyChanged))
.Where(e => e.PropertyName == nameof(TestString))
.Sample(TimeSpan.FromMiliseconds(100))
.Subscribe(() => Thread.Sleep(...))