2011-12-30 32 views
7

結合考慮以下視圖模型屬性:延遲的從源

private string _slowProperty; 
public string SlowProperty 
{ 
    get { return _slowProperty; } 
    set 
    { 
     _slowProperty = value; 
     RaisePropertyChanged("SlowProperty"); 
    } 
} 

這是綁定到一個文本框,如下所示:

<TextBox Text="{Binding SlowProperty}" /> 

現在,這裏的問題是,每次的價值SlowProperty的變化很常見,文本框會去嘗試獲取它的值,這很慢。我可以使用異步綁定來緩解這種情況,但是,這仍然會浪費CPU週期。

相反,我想擁有的是一樣的東西:

<TextBlock Text="{z:DelayedSourceBinding SlowProperty}" /> 

這將嘗試獲得一定的延時後綁定。例如,如果SlowProperty在短時間內連續更改了5次,則只有最後一個文本在文本框中可見。

我發現,執行類似的東西following project,所以我的例子,我可以使用它,像這樣:

<TextBox Text="{z:DelayBinding Path=SearchText}" /> 

它的問題是,它僅更新結合目標後延遲。但是,源路徑會被評估,並且每次更改源時都會執行其獲取器。其中,在SlowProperty的情況下仍然會浪費CPU週期。

我試過讓自己的延遲綁定類,但got stuck。有沒有其他的活頁夾可以做到這些?

爲了完整起見,這裏有2個執行類似任務的其他項目,到目前爲止,還沒有解決這個問題我遇到:

DeferredBinding - 類似的解決方案,以DelayBinding。但是,使用起來要複雜一點。

DelayedBindingTextBox - 使用自定義文本框控件實現延遲綁定。

謝謝!

回答

3

爲什麼不在視圖模型中解決這個問題?如果你的財產迅速變化,但速度很慢,那麼你的視圖模型可能會暴露第二個「延遲」財產。您可以使用定時器定期更新這個「延遲」屬性。

或者,更清晰的實現可以使用被動擴展框架提供的Throttle函數。

+0

科林,優秀。所有CS問題都可以通過添加另一個間接層來解決! :) – 2011-12-30 22:32:30

+0

你可能是對的,這確實是一個應該在VM級別解決的問題。儘管如此,我仍然想知道是否可以進行自定義綁定,就像我所描述的那樣。 – VitalyB 2011-12-30 22:43:55

1

對我來說似乎是什麼,當你調用RaisePropertyChanged()時,你真正想要的是延遲點。
所以我嘗試過了,這裏是一個解決方案:

的XAML:

<StackPanel> 
    <TextBox Text="{Binding DelayedText, UpdateSourceTrigger=PropertyChanged}" /> 
    <TextBlock Text="{Binding DelayedText}" /> 
</StackPanel> 

的C#:

public partial class MainWindow : Window, INotifyPropertyChanged 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
      this.DataContext = this; 
     } 

     private String m_DelayedText; 
     public String DelayedText 
     { 
      get 
      { 
       return m_DelayedText; 
      } 
      set 
      { 
       if (m_DelayedText != value) 
       { 
        String delayedText; 
        m_DelayedText = delayedText = value; 
        Task.Factory.StartNew(() => 
         { 
          Thread.Sleep(2000); 
          if (delayedText == m_DelayedText) 
          { 
           RaisePropertyChanged("DelayedText"); 
          } 
         }); 
       } 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
     private void RaisePropertyChanged(String _Prop) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(_Prop)); 
      } 
     } 
    } 

您可以檢查它的工作原理是在RaisePropertyChanged("DelayedText")設置斷點

我明白,它可以看起來像很多「只是」一個屬性的代碼。
但是,您可以使用代碼片段,或者在運行時使用Resharper等注入樣板代碼。
無論如何,你可能不會經常需要它。另外,如果您要使用其他方法(例如,通過調整文本框),則必須處理綁定到屬性的每個位置。
通過這樣做,在屬性的setter中,您確保訪問此屬性的每個人都受到所收到更新的限制。

HTH,

Bab。

+0

有趣的解決方案,謝謝!結果代碼確實有點沉重,但這是一個有趣的閱讀。 – VitalyB 2011-12-30 22:44:50

2

我有一個類似的需求,我需要能夠延遲源和目標,所以我創建了兩個標記擴展名爲DelayBindingDelayMultiBinding。要延遲的更新源指定UpdateSourceDelay

<TextBox Text="{db:DelayBinding SlowProperty, 
           UpdateSourceDelay='00:00:01'}" /> 

的源代碼和示例使用情況DelayBindingDelayMultiBinding可以downloaded here
如果你感興趣的實現細節,你可以在這裏看看我的博客文章吧:
DelayBinding and DelayMultiBinding with Source and Target delay

1

值得注意的是,作爲.NET 4.5的,一個delay property已被添加到框架,它可以讓您將綁定延遲的數量設置爲毫秒。在Microsoft示例中,強調twoway模式,但綁定延遲在任何綁定模式下均可用。

例如,我在一個數據網格中使用這個選項,必須從自定義的usercontrol文本框中改變選定的項目/值,顯然從數據網格中改變。由於我在這裏不提及的原因,文本框必須綁定到與視圖模型不同的屬性,但這兩個屬性在一天結束時必須具有相同的值,並且其中一個屬性的任何更改都必須是反映在另一個。當在數據網格中選定的值發生變化時,文本框也必須更新,並且我檢查了SelectedValue綁定屬性的setter中的實際值更改,以防止無限循環。當更改速度太快時,在由SelectedValue設置器更改的文本框內的文本發生更改時,將數據保存回源代碼時出錯。兩週的延遲解決了這一問題,沒有任何複雜的解決方案並沒有UI感覺太laggy:

SelectedValue="{Binding SampleNumberSelect, Mode=OneWayToSource, Delay=33}" 

這是非常方便,並節省您實現在視圖模型中的任何這樣的變化帶來的麻煩,這將不必要地弄亂代碼,包括必須處理窗口關閉時的任何計時器。當然,它甚至不必在像我這樣的相對複雜的場景中使用,但它可能有助於防止CPU /資源繁重的代碼在用戶界面中發生的每次小改動時不必要地運行。