2012-03-22 61 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”

相关问题