2009-09-27 41 views
3

我有以下XAML標記:WPF組合框綁定行爲

<TextBox x:Name="MyTextBox" Text="{Binding Path=SelectedCustomer.FavouriteProduct.ProductNumber, UpdateSourceTrigger=PropertyChanged}" /> 
<ComboBox x:Name="MyComboBox" ItemsSource="{Binding Products}" DisplayMemberPath="ProductName" 
    SelectedValue="{Binding Path=SelectedCustomer.FavouriteProduct.ProductNumber}" 
    SelectedValuePath="ProductNumber" /> 

我的視圖的DataContext的必然包含名爲SelectedCustomer公共屬性視圖模型。 Customer對象包含Product類型的FavouriteProduct屬性,Product對象包含公共屬性ProductNumber和ProductName。

我正在尋找的行爲是讓組合框的SelectedItem更新文本框中的文本,反之亦然。 ComboBox到TextBox工作得很好。選擇ComboBox中的任何產品都會使用該產品的產品編號更新文本框。但是,當我嘗試以另一種方式時,我會得到一些奇怪的行爲。它僅適用於所選項目之前的項目。我會盡量解釋:

考慮產品下面的列表([產品型號],[產品名稱]):

  1. 芬達
  2. 百事可樂
  3. 可口可樂
  4. 雪碧

現在讓我們來說說SelectedCustomer的favouri te產品是可口可樂(必須是開發商)。所以當窗口打開時,TextBox讀取3,ComboBox讀取可口可樂。可愛。現在讓我們將TextBox中的產品編號更改爲2.ComboBox將其更新爲百事可樂的價值。現在嘗試將文本框中的產品編號更改爲高於可口可樂(Coca Cola)(3)的編號。不太可愛。選擇4(Sprite)或5(Water)使ComboBox恢復到可口可樂。因此,行爲似乎是從ItemSource中的列表中打開窗口寬度的項目下面的任何內容都不起作用。將其設置爲1(芬達),其他人均無效。設置爲5(水),他們都工作。這可能與ComboBox的一些初始化有關嗎?潛在的錯誤?好奇是否有其他人看到過這種行爲。

UPDATE:爲SelectedProduct和SelectedProductNumber

閱讀邁克·布朗的迴應後,我已經創建的屬性。我遇到的問題是,只要從ComboBox中選擇了一些東西,就會在無限循環中結束更新對象。我是否錯誤地實現了OnPropertyChanged處理程序,或者是否存在缺少的內容?下面是代碼從我的ViewModel一個片段:

private int _SelectedProductNumber = -1; 
     public int SelectedProductNumber 
     { 
      get 
      { 
       if (_SelectedProductNumber == -1 && SelectedCustomer.Product != null) 
        _SelectedProductNumber = SelectedCustomer.Product.ProductNumber; 
       return _SelectedProductNumber; 
      } 
      set 
      { 
       _SelectedProductNumber = value; 
       OnPropertyChanged("SelectedProductNumber"); 
       _SelectedProduct = ProductList.FirstOrDefault(s => s.ProductNumber == value); 
      } 
     } 

     private Product _SelectedProduct; 
     public Product SelectedProduct 
     { 
      get 
      { 
       if (_SelectedProduct == null) 
        _SelectedProduct = SelectedCustomer.Product; 
       return _SelectedProduct; 
      } 
      set 
      { 
       _SelectedProduct = value; 
       OnPropertyChanged("SelectedProduct"); 
       _SelectedProductNumber = value.ProductNumber; 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 

     protected virtual void OnPropertyChanged(string property) 
     { 
      if (PropertyChanged != null) 
       PropertyChanged(this, new PropertyChangedEventArgs(property)); 
     } 

更新2

我已經從兩個屬性更新SelectedCustomer.FavouriteProduct,然後使用該閱讀他們的價值觀發生變化時,執行稍現在。這現在可行,但我不確定這是'正確的方式'。

private int _SelectedProductNumber = 0; 
public int SelectedProductNumber 
{ 
    get 
    { 
     if (SelectedCustomer.Product != null) 
      _SelectedProductNumber = SelectedCustomer.Product.ProductNumber; 
     return _SelectedProductNumber; 
    } 
    set 
    { 
     _SelectedProductNumber = value; 
     SelectedCustomer.FavouriteProduct = ProductList.FirstOrDefault(s => s.ProductNumber == value); 
     OnPropertyChanged("SelectedProductNumber"); 
     OnPropertyChanged("SelectedProduct"); 
    } 
} 

private Product _SelectedProduct; 
public Product SelectedProduct 
{ 
    get 
    { 
     if (SelectedCustomer.Product != null) 
      _SelectedProduct = SelectedCustomer.Product; 
     return _SelectedProduct; 
    } 
    set 
    { 
     _SelectedProduct = value; 
     SelectedCustomer.FavouriteProduct = value; 
     OnPropertyChanged("SelectedProduct"); 
     OnPropertyChanged("SelectedProductNumber"); 
    } 
} 
+0

錯誤在我身上...我用正確的代碼更新了我的答案。 – 2009-10-07 12:37:50

+0

爲了確保當屬性沒有真正改變時不會觸發已更改的事件,請使用'if(_selectedProduct!= value){/*...*/}'塊。 – 2009-10-08 23:31:31

+0

您的新解決方案是完全有效的(實際上它避免重複的信息很棒)。然而,我感到奇怪的是你仍然收到堆棧溢出。我把代碼放入VS,對我來說運行得很好。不知道你身邊出了什麼問題。您對選定的顧客進行的更改是否也促使更新其他兩個屬性?無論哪種方式,我已更新我的示例代碼與在我的機器(TM) – 2009-10-09 20:36:24

回答

0

嘗試: 的SelectedItem = 「{綁定路徑= YourPath,模式=雙向」} 而不是設置的SelectedValue和SelectedValuePath。

也可以使用SelectedValue,不要忘記Mode = TwoWay,因爲這不是默認值。

一個不錯的應用程序會使用主細節模式 - 使用主細節(項目視圖,例如組合框)將數據源集合和細節視圖(例如文本框)綁定到源集合中的選定項目,一個綁定轉換器來讀/寫適當的屬性。

下面是一個例子: http://blogs.microsoft.co.il/blogs/tomershamam/archive/2008/03/28/63397.aspx

通知主結合的形式{結合}或{綁定SourceCollection}和細節結合是{結合}形式的或{結合SourceCollection}的。

爲了得到這個工作,你需要用一個保存選定項目的對象來包裝你的集合。 WPF有一個內置的ObjectDataProvider。

例子: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/068977c9-95a8-4b4a-9d38-b0cc36d06446

+0

作品的版本我看不到我可以使用SelectedItem設置選定的產品根據ProductNumber – 2009-10-05 23:55:11

+0

編輯答案解決該問題。 – 2009-10-07 23:16:57

1

所以我寫了這麼folloiwng要麼支持我的選項可以看到你的目標是不是太清楚。

保持同步綁定到一個項目兩個元素,你可以設置你的組合框的IsSynchronizedWithCurrentItem="True",如下圖所示:

<TextBox x:Name="MyTextBox" Text="{Binding Path=SelectedCustomer.FavouriteProduct.ProductNumber, UpdateSourceTrigger=PropertyChanged}" /> 
<ComboBox x:Name="MyComboBox" ItemsSource="{Binding Products}" DisplayMemberPath="ProductName" 
    SelectedValue="{Binding Path=SelectedCustomer.FavouriteProduct.ProductNumber}" 
    IsSynchronizedWithCurrentItem="True" 
    SelectedValuePath="ProductNumber" /> 

這將意味着在綁定到相同的背景對象的當前窗口將保持一切同步並不會給你看到的奇怪行爲。

此報價表此不再MSDN article描述的效果:

的IsSynchronizedWithCurrentItem 屬性的重要性在於,當 選擇的變化,這就是 改變「當前項目」至於 的窗口有關。這告訴 WPF引擎該對象是 將用於更改當前 項目。如果沒有此屬性,DataContext中的當前項目 將不會更改 ,因此您的文本框 將假定它仍在 列表中的第一項。

然後設置Mode=TwoWay由其他答案的建議只會確保雙方在更新文本框的基礎對象將被更新,在更新文本框被更新的對象。

這使得文本編輯所選項目的文本,而不是與匹配文本combolist選擇項目(這是替代認爲你可能是想達到什麼目的?)

爲了實現同步選擇效應可能需要在組合框上設置IsEditable="True"以允許用戶輸入項目並放置文本框。或者,如果您需要兩個盒子,請使用IsSynchronizedWithCurrentItem="True"IsEditable="True"之間的第二個組合框替換文本框,然後使用它作爲文本框。

+0

這看起來很有希望,但不幸的是我仍然得到相同的行爲。 TextBox在我從ComboBox中選擇某些東西時得到更新,但另一種方式工作不正常。我認爲我可能會全力以赴。 – 2009-10-05 23:59:31

+0

您是否在尋找文本框中的文本來更改選擇或更改/編輯所選項目的文本?我已經用兩種解決方案更新了答案。 – John 2009-10-06 11:54:52

+0

我致力於爲用戶提供兩種選擇產品的選擇。通過從組合框中選擇產品或輸入產品編號。我可以使ComboBox可編輯,但不會讓我輸入產品編號。我還沒有研究過使用帶有IsSynchronizedWithCurrentItem選項的單獨組合框。 – 2009-10-06 21:34:26

1

您要做的就是在ViewModel上顯示當前選定產品和當前選定產品編號的單獨屬性。選定的產品更改後,請更新產品編號,反之亦然。因此,您的視圖模型應該是這個樣子

public class MyViewModel:INotifyPropertyChanged 
{ 
    private Product _SelectedProduct; 
    public Product SelectedProduct 
    { 
     get { return _SelectedProduct; } 
     set 
     { 
      _SelectedProduct = value; 
      PropertyChanged(this, new PropertyChangedEventArgs("SelectedProduct")); 
      _SelectedProductID = _SelectedProduct.ID; 
      PropertyChanged(this, new PropertyChangedEventArgs("SelectedProductID")); 
     } 
    } 
    private int _SelectedProductID; 
    public int SelectedProductID 
    { 
     get { return _SelectedProductID; } 
     set 
     { 
      _SelectedProductID = value; 
      PropertyChanged(this, new PropertyChangedEventArgs("SelectedProductID")); 
      _SelectedProduct = _AvailableProducts.FirstOrDefault(p => p.ID == value); 
      PropertyChanged(this,new PropertyChangedEventArgs("SelectedProduct")); 
     } 
    } 
    private IEnumerable<Product> _AvailableProducts = GetAvailableProducts(); 

    private static IEnumerable<Product> GetAvailableProducts() 
    { 
     return new List<Product> 
        { 
         new Product{ID=1, ProductName = "Coke"}, 
         new Product{ID = 2, ProductName="Sprite"}, 
         new Product{ID = 3, ProductName = "Vault"}, 
         new Product{ID=4, ProductName = "Barq's"} 
        }; 
    } 

    public IEnumerable<Product> AvailableProducts 
    { 
     get { return _AvailableProducts; } 
    } 
    private Customer _SelectedCustomer; 
    public Customer SelectedCustomer 
    { 
     get { return _SelectedCustomer; } 
     set 
     { 
      _SelectedCustomer = value; 
      PropertyChanged(this, new PropertyChangedEventArgs("SelectedCustomer")); 
      SelectedProduct = value.FavoriteProduct; 
     } 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 
} 

所以,現在你的XAML綁定到相應的屬性和視圖模型負責syncrhronization

<TextBox 
    x:Name="MyTextBox" 
    Text="{Binding Path=SelectedProductID, UpdateSourceTrigger=PropertyChanged}" /> 
<ComboBox 
    x:Name="MyComboBox" 
    ItemsSource="{Binding AvailableProducts}" 
    DisplayMemberPath="ProductName" 
    SelectedItem="{Binding SelectedProduct}" /> 

不要忘了執行INotifyPropertyChanged和其餘的GetAvailableProducts函數。也可能有一些錯誤。我在這裏輸入這個而不是使用VS,但你應該得到一般的想法。

+0

我想我可能不得不這樣做。我已經添加了相應的屬性,但是我在ProductId和Product屬性之間存在問題。只要你改變其中任何一個,你進入一個無限循環,並最終得到一個StackOverflow異常;)可能是因爲我如何實現處理程序,雖然(我對WPF相當新)。我將用代碼更新問題。 – 2009-10-06 22:11:52

+0

對不起,這是我頭腦...而不是更新相反的屬性只是更新後臺字段和調用屬性更改...我會更新代碼與正確的實現。 – 2009-10-07 12:32:57

+1

好了...現在應該爲你工作...他們應該添加一個特殊的徽章,導致堆棧溢出的答案;) – 2009-10-07 12:35:40