2010-01-28 242 views
7

好了一直與WPF工作了一段時間,但我需要一些幫助。WPF組合框SelectedItem

我有一個ComboBox象下面這樣:

<TabControl> 
    <TabItem Header="1"> 
     <ComboBox ItemsSource="{Binding MyList}" SelectedItem="{Binding MyListSelection}"/> 
    </TabItem> 
    <TabItem Header="2"/> 
</TabControl> 

每當我從標籤1移開,然後回來給它的選擇被刪除。我認爲這樣做的原因是控件在超出範圍之後會被銷燬,但是在SelectedItem變爲null的過程中,這實際上並不是用戶想要的,這是由於UI生命週期。

所以我想知道什麼是最好的路線?我正在用MVVM構建這個應用程序,所以我可以忽略ViewModel中MyListSelection屬性上的set調用,但我有遍佈整個地方的ComboBoxes,並且不喜歡修改我認爲是WPF錯誤的ViewModel。

我可以繼承的WPF組合框,但沒有SelectedItemChanging事件時的SelectedItem改變我只能添加一個處理程序。

任何想法?

UPDATE:

好了,打我的頭靠在我發現爲什麼我的問題沒能再現的後牆上。如果由於某種原因,列表項類型是一個類,SelectedItem被WPF設置爲null,但如果它是一個值類型,則它不會。

這裏是我的測試類(VMBase僅僅是一個抽象類,實現INotifyPropertyChanged):

public class TestListViewModel : VMBase 
{ 
    public TestListViewModel() 
    { 
     TestList = new List<TestViewModel>(); 
     for (int i = 0; i < 10; i++) 
     { 
      TestList.Add(new TestViewModel(i.ToString())); 
     } 
    } 

    public List<TestViewModel> TestList { get; set; } 

    TestViewModel _SelectedTest; 
    public TestViewModel SelectedTest 
    { 
     get { return _SelectedTest; } 
     set 
     { 
      _SelectedTest = value; 
      OnPropertyChanged("SelectedTest"); 
     } 
    } 
} 

public class TestViewModel : VMBase 
{ 
    public string Name {get;set;} 
} 

所以,當我改變TestList爲int類型,並來回標籤之間的SelectedItem保持不變。但是,如果它的類型爲TestViewModel當Tabitem離焦時SelectedTest設置爲null。

發生了什麼事?

回答

10

我有完全相同的問題,並且到現在爲止我想不出是什麼問題。我在4個不同的機器上測試了相同的操作系統,.Net版本和硬件規格,並且可以在其中兩個中重現問題,其他人工作得很好。 我可以找到適用於我的解決方法是在ItemsSource之前定義SelectedItem綁定。奇怪的是,如果我遵循這種模式,一切都按預期工作。 這就是說,你就必須做到以下幾點:

<Window x:Class="ComboBoxInTabItemSpike.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300"> 
    <StackPanel> 
     <TabControl> 
      <TabItem Header="1"> 
       <ComboBox SelectedItem="{Binding MySelect}" ItemsSource="{Binding MyList}"/> 
      </TabItem> 
      <TabItem Header="2"/> 
     </TabControl> 
     <TextBlock Text="{Binding MySelect}"/> 
    </StackPanel> 
</Window> 
0

在OP更改後編輯。 嗨,何塞,我無法重現你提到的錯誤。所以你關於控制被破壞的假設是錯誤的。即使它現在使用引用類型,Combobox的行爲也與預期的一樣,其代碼如下。當您更改TabItems時,您的代碼的其他部分必須啓動。

<Window x:Class="ComboBoxInTabItemSpike.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300"> 
    <StackPanel> 
     <TabControl> 
      <TabItem Header="1"> 
       <ComboBox ItemsSource="{Binding MyList}" 
          SelectedItem="{Binding MySelect}"/> 
      </TabItem> 
      <TabItem Header="2"/> 
     </TabControl> 
     <TextBlock Text="{Binding MySelect}"/> 
    </StackPanel> 
</Window> 

using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Windows; 

namespace ComboBoxInTabItemSpike 
{ 
    public partial class Window1 : Window, INotifyPropertyChanged 
    { 
     public Window1() 
     { 
      InitializeComponent(); 
      MyList=new ObservableCollection<TestObject>(
       new[]{new TestObject("1"),new TestObject("2"),new TestObject("3") }); 
      DataContext = this; 
     } 

     public ObservableCollection<TestObject> MyList { get; set; } 

     private TestObject mySelect; 
     public TestObject MySelect 
     { 
      get { return mySelect; } 
      set{ mySelect = value; 
      if(PropertyChanged!=null) 
       PropertyChanged(this,new PropertyChangedEventArgs("MySelect"));} 
     } 

     public TestObject MySelectedItem 
     { 
      get { return (TestObject)GetValue(MySelectedItemProperty); } 
      set { SetValue(MySelectedItemProperty, value); } 
     } 

     public static readonly DependencyProperty MySelectedItemProperty = 
      DependencyProperty.Register("MySelectedItem", 
           typeof(TestObject), 
           typeof(Window1), 
           new UIPropertyMetadata(null)); 

     public event PropertyChangedEventHandler PropertyChanged; 
    } 

    public class TestObject 
    { 
     public string Name { get; set; } 

     public TestObject(string name) 
     { 
      Name = name; 
     } 

     public override string ToString() 
     { 
      return Name; 
     } 
    } 
} 
+1

當列表類型是引用類型它不具有相同的行爲。查看我更新的帖子 – Jose 2010-01-28 21:09:54

0

我建議檢查綁定。如果您應用中的其他內容正在更改所選項目或項目源,那麼您的綁定將會中斷。您也可以在輸出窗口中查看Visual Studio以查看是否有任何錯誤。

0

我想你可能會錯過這裏是一個TwoWay綁定SelectedItem。當綁定包含MyList(綁定ItemsSource)和MyListSelection(Bond到您的案例中的SelectedItem)的ViewModel類時,即使您訪問了不同的選項卡,也會始終獲得這些信息。所以當你回到這個選項卡時,MyListSelection會再次綁定到ComboBoc.SelectedItem,你會很好。試試這個,讓我知道。

+1

默認情況下,SelectedItem綁定是TwoWay。 – 2010-01-29 05:53:30

0

我認爲這可以通過一個簡單的空檢查來解決。

public TestViewModel SelectedTest 
{ 
    get { return _SelectedTest; } 
    set 
    { 
     if(value != null) 
      _SelectedTest = value; 
     OnPropertyChanged("SelectedTest"); 
    } 
} 

這是因爲ComboBox在回收時有重置其SelectedIndex的傾向。這個簡單的空檢查將強制它重新綁定到最後一個有效的項目。

+0

是的,這是我多次使用的選項,但該應用程序有很多組合框和列表視圖,每次都這樣做非常煩人。 – Jose 2010-01-29 17:07:38

+0

事實上,這可能會很煩人,但是即使在每個房地產上也不得不提高房產也是令人討厭的。 WPF遠非完美。 GL – 2010-01-30 12:29:14

+1

這並不總是可接受的,因爲空值有時可能是集合中的有效值。此外,屬性實際上是依賴項屬性的情況如何?然後,你將不得不看着Coerce和Change通知事件來做類似的事情,這只是一團糟。在我看來,這通常不是一個可接受的解決方案。 – jpierson 2010-05-10 09:52:33

0

我是有我的列表中引用類型完全相同的問題。解決方案是覆蓋我的TestViewModel中的Equals(),以便WPF能夠在對象之間執行值相等性檢查(而不是參考檢查)以確定哪個是SelectedItem。我碰巧有一個ID字段,它確實是TestViewModel的識別特徵。

0

該行爲由組合框執行,應該由編譯器以比它更好的方式實現...... IE編譯器應檢查並查看ItemsSource的類型和SelectedItem屬性的類型引用值勢必將永遠返回一個值,相當於

應該警告你可能會考慮重寫的equals()和GetHashCode()方法...

浪費了大量的時間這個今天!

相關問題