2009-11-06 64 views
3

有什麼辦法可以告訴如何在WPF中引發ComboBox_SelectionChanged事件。WPF - 如何知道引發了什麼ComboBox_SelectionChanged事件

也就是說,是由於用戶交互引起的事件,還是作爲其綁定屬性更改的結果?

+0

對誰只是刪除了他的答案的傢伙註釋:你可能想通了,發送者是*始終*組合框,但我想你想知道你的方法體可以簡化爲IF(發件人是ComboBox)then {blah} else {blah} – 2009-11-06 21:25:42

回答

4

在ComboBox.SelectionChanged事件中,發件人爲總是組合框,並且在SelectionChangedEventArgs中沒有任何內容可以幫助您。

對此我有兩種解決方案。您可以在綁定上使用轉換器,或者您可以檢查堆棧跟蹤以查看System.Windows.Controls.Primitives.Selector.OnSelectedItemsCollectionChanged(object,NotifyCollectionChangedArgs)是否在堆棧中。堆棧檢查非常難看,是一種不好的做法,並且不適用於部分信任環境。所以我只會描述另一個。

使用對結合的轉換器,以檢測改變源

該解決方案是比較乾淨,但需要改變的結合。當事情沒有改變時,它有時也會通知你。

第1步:創建一個轉換器,則不進行轉換,但有一個「轉換」事件和「ConvertedBack」事件:

public EventingConverter : IValueConverter 
{ 
    public event EventHandler Converted; 
    public event EventHandler ConvertedBack; 

    public object Convert(object value, ...) 
    { 
    if(Converted!=null) Converted(this, EventArgs.Empty); 
    return value; 
    } 
    public object ConvertBack(object value, ...) 
    { 
    if(ConvertedBack!=null) ConvertedBack(this, EventArgs.Empty); 
    return value; 
    } 
} 

第2步:設置您的結合使用這個轉換器的一個新實例(不要使用共享資源字典或靜態財產通常做)轉換器實例

<ComboBox ...> 
    <ComboBox.SelectedValue> 
    <Binding Path="..." ...> 
     <Binding.Converter> 
     <local:EventingConverter 
      Converted="ComboBoxSelectedValue_Converted" 
      ConvertedBack="ComboBoxSelectedValue_ConvertedBack" /> 
     </Binding.Converter> 
    </Binding> 
    </ComboBox.SelectedValue> 
</ComboBox> 

現在你ComboBoxSelectedValue_Converted和ComboBoxSelectedValue_ConvertedBack方法將從綁定過程中調用。

警告:如果您在這些事件中拋出異常,您將破壞綁定。

如果不能修改的XAML,它結合

如果你有超過創建的結合(例如您正在使用附加屬性)的XAML無法控制你仍然可以進來,並添加事實之後的轉換器。在這種情況下,你的轉換器類將需要鏈接到之前聲明的轉換器,你必須克隆綁定並安裝新的(一旦它們被使用後它們是不可變的),並且你還必須處理MultiBindings (如果你想支持他們)。

最後說明

需要確定是否改變是由用戶作出或財產可能實際上是貧窮的UI設計症狀,通常是從誰不真正瞭解自己的用戶產生要求。

我已經有過幾個項目,我最終用戶指定了這樣的事情發生時「當我改變這個組合框」。在幾乎所有情況下,事實證明,應用程序在某些使用情況下會表現出意外,我們找到了更好的方法來實現目標。在許多情況下,用戶真正想要的是「當此值首先與數據庫中的值不同」或「此值不再默認時」或「此值爲5時」。

+0

精美的回答。非常感謝你花時間把這些放在一起。 – mattdlong 2009-11-06 22:22:36

+0

很好的答案:) – slugster 2009-11-06 23:54:46

2

簡答:沒有。不應該有任何區別,在這兩種情況下,選擇都發生了變化,這是重要的。 要確定它是否是用戶交互,您必須監視其他事件的組合,如DropDownOpened/Closed和KeyDown/Up以及Stylus *。

+0

發件人始終是ComboBox,因爲它是觸發事件的邏輯控件。 – 2009-11-06 22:09:41

+0

+1不知道爲什麼有人低估了這個答案。這是正確的,幷包含有用的信息,儘管它沒有解決原始問題。德魯是正確的,發件人總是選擇被改變的組合框。 – 2009-11-06 22:17:31

1

我也遇到過這樣的問題,並用布爾型bInternalChange變量解決了這個問題。

想象一下將接口從°C轉換成°F並將接口轉換爲兩個ComboBox。在第一個中選擇一個值將更新第二個的選擇,並在第二個中選擇一個值更新第一個值。如果您不區分UI更改和內部更改,它會創建一個無限循環。

bool bInternalChange = false; 
private void ComboBoxF_SelectionChanged(...) 
{ 
    if (!bInternalChange) 
    { 
     bInternalChange = true; 
     ComboBoxC.SelectedValue = ConvertFtoC(...); 
     bInternalChange = false; 
    } 
} 
private void ComboBoxC_SelectionChanged(...) 
{ 
    if (!bInternalChange) 
    { 
     bInternalChange = true; 
     ComboBoxF.SelectedValue = ConvertCtoF(...); 
     bInternalChange = false; 
    } 
} 
+0

我也使用過這個解決方案。如果您對bInternalChange使用try..finally,則更可靠,否則轉換代碼或值更新中的任何地方的異常都會導致您的同步停止工作。我經常把它封裝在一個對象中,例如:using(var change = ChangeTracker.StartChange())if(change)ComboBoxC.SelectedValue = ...; StartChange()返回一個可隱式轉換爲bool的IDisposable。 – 2009-11-07 00:10:55

相關問題