SelectedItem ComboBox неожиданно установлен в ноль перед фактическим значением - PullRequest
3 голосов
/ 23 марта 2012

У меня есть ComboBox, у которого ItemsSource связан с новым (не по умолчанию) ListCollectionView, который связан с ObservableCollection.Свойство ComboBox SelectedItem привязано к общедоступному свойству SelectedHat.

Шаг 1. Выберите второй элемент в ComboBox.SelectedHat теперь является второй шляпой в списке, как и ожидалось.Шаг 2: (Нажмите кнопку, чтобы) Установите второе место в списке для новой шляпы.SelectedHat сначала устанавливается в значение null, а затем в новую шляпу.

Почему SelectedHat устанавливается в значение null перед новой шляпой?

Я хочу иметь возможность vm.Collection [index] =new Hat () и
(1), если в ComboBox выбран этот индекс, оставьте его выбранным, вместо того, чтобы становиться пустым
(2) установите SelectedHat только один раз на новую Hat, вместо NULL и ТОГДА на новую Hat

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 ]

3 голосов
/ 23 марта 2012

Это реализация 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'. Я ожидаю, что если мы проследим код до реализации поля со списком, мы увидим, что старый элемент был удален и заменен на ноль, а затем был добавлен новый элемент, поэтому вы получаете поведение, которое вы испытываете (я также вижу ).

Моя работа заключается в том, чтобы вместо замены элемента добавить новый элемент, изменить текущий выбранный элемент, а затем удалить старый элемент.

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 голосов
/ 23 марта 2012

Изменить предмет напрямую. Я только что проверил это. vm.Collection [1] .name = "hat 2"

...