2012-03-22 57 views
2

我有一個ComboBox,其ItemsSource綁定到鏈接到ObservableCollection的新(非默認)ListCollectionView。 ComboBox SelectedItem屬性綁定到公共SelectedHat屬性。ComboBox的SelectedItem在實際值之前意外地設置爲空

步驟1:在ComboBox中選擇第二項。按照預期,SelectedHat現在是列表中的第二個帽子。 步驟2 :(點擊按鈕)將列表中的第二個點設置爲新的帽子。 SelectedHat首先設置爲null,然後設置爲新的Hat。

爲什麼在新帽子之前將SelectedHat設置爲null?

欲能夠vm.Collection [索引] =新帽()和
(1)如果ComboBox該索引選擇已,保持選定的去空白
(2)只設置SelectedHat代替一旦新的帽子,而不是空,然後將新帽

C#:

public partial class MainWindow : Window 
{ 
    private readonly ViewModel vm; 

    public MainWindow() 
    { 
     InitializeComponent(); 
     vm = new ViewModel(); 
     DataContext = vm; 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     Hat item = new Hat { Name = "hat 2", Color = "Red"}; 
     vm.Collection[1] = item; 
    } 
} 

public class ViewModel : BaseNotifyPropertyChanged 
{ 
    public ObservableCollection<Hat> Collection { get; set; } 
    public ListCollectionView View { get; set; } 

    private Hat selectedHat; 
    public Hat SelectedHat 
    { 
     get { return selectedHat; } 
     set 
     { 
      selectedHat = value; 
      Console.WriteLine(string.Format("SelectedHat set to [{0}]", value)); 
      NotifyPropertyChanged("SelectedHat"); 
     } 
    } 

    public ViewModel() 
    { 
     Collection = new ObservableCollection<Hat>() 
     { 
      new Hat { Name = "hat 1", Color = "Black" }, 
      new Hat { Name = "hat 2", Color = "Black" }, 
      new Hat { Name = "hat 3", Color = "Black" }, 
     }; 

     View = new ListCollectionView(Collection); 
     View.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending)); 
    } 
} 

public class Hat 
{ 
    public string Name { get; set; } 
    public string Color { get; set; } 

    public override string ToString() 
    { 
     return string.Format("{0} ({1})", Name, Color); 
    } 
} 

public abstract class BaseNotifyPropertyChanged : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    protected virtual void NotifyPropertyChanged(String propertyName) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

XAML:

<StackPanel> 
    <TextBlock Text="{Binding Path=SelectedHat, Mode=OneWay}" /> 
    <ComboBox ItemsSource="{Binding Path=View}" SelectedItem="{Binding Path=SelectedHat, UpdateSourceTrigger=PropertyChanged}" /> 
    <Button Content="click me" Click="Button_Click" /> 
</StackPanel> 

回答

2

這是ObservableCollection.SetItem

protected override void SetItem(int index, T item) 
{ 
    this.CheckReentrancy(); 
    T obj = this[index]; 
    base.SetItem(index, item); 
    this.OnPropertyChanged("Item[]"); 
    this.OnCollectionChanged(NotifyCollectionChangedAction.Replace, (object) obj, (object) item, index); 
} 

執行,你可以看到它提出了OnPropertyChanged("Item[]"),然後OnCollectionChanged(NotifyCollectionChangedAction.Replace, (object) obj, (object) item, index)。 OnCollectionChanged具有參數'oldItem'和'newItem'。我期望如果我們將代碼追溯到組合框實現中,我們會看到舊項目被刪除並替換爲null,然後插入新項目,這就是爲什麼你會得到你所經歷的行爲(我也看到它)。

我的工作是不是替換項目,添加新項目,更改當前選定的項目,然後刪除舊項目。

private void ButtonClick(object sender, System.Windows.RoutedEventArgs e) 
{ 
    Hat newHat = new Hat { Name = "hat 2", Color = "Red" }; 

    var viewModel = (ViewModel)DataContext; 

    var oldHat = viewModel.Collection[1]; 

    if (viewModel.SelectedHat == oldHat) 
    { 
     viewModel.Collection.Add(newHat); 
     viewModel.SelectedHat = newHat; 
     viewModel.Collection.Remove(oldHat); 
    } 
    else 
    { 
     viewModel.Collection[1] = newHat; 
    } 
} 
+0

查看我的回答。直接更新該項目並且沒有調用OnCollectionChanged。 – Paparazzi 2012-03-22 22:46:38

+0

是的,我想說的是除了你提出的建議之外的其他工作:-) – Phil 2012-03-23 07:26:58

0

直接更改項目。我只是測試它。 vm.Collection [1] .name =「hat 2」

相關問題