2016-01-20 85 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(...)) 
相關問題