Combo-box теряет выбор после изменения коллекции - PullRequest
1 голос
/ 22 марта 2012

У меня есть поле со списком WPF, привязанное к наблюдаемой коллекции (OC):

    <ComboBox Name="cbCombination" ItemsSource="{Binding Combinations}" 
              SelectedIndex="0" />

В другом месте, в объекте, заданном в качестве контекста данных:

    public ObservableCollection<Combination> Combinations { get; set; }

Комбинация переопределяет его ToStringи все великолепно: в раскрывающемся списке со списком отображаются все элементы Комбинации в ОК комбинаций.Поле выбора комбинированного списка отображает значение первой комбинации.

Теперь объект контекста данных должен изменить значения в своих комбинациях. OC:

    var combinationsList = CombinationsManager.CombinationsFor(someParam);
    this.Combinations.Clear();
    foreach (var combination in combinationsList)
        this.Combinations.Add(combination);
    NotifyPropertyChanged(@"Combinations");

Это вызывает комбинированиеПоле выбора -box показывает пустую строку.(Раскрывающийся список закрыт. Однако, когда я делаю его выпадающим, он показывает правильные новые комбинации, поэтому привязан к обновленной коллекции ).

Я пыталсязахватывать события как SourceUpdated, так и (в моем случае) события TargetUpdated (неважно, как там настроить SelectedIndex), но мои обработчики событий не вызывались!

Поэтому мой вопрос: Как мне сделать WPFComboBox обновляет значение своего поля выбора, когда наблюдаемая коллекция, к которой он привязан, изменяется?

Обновление :

Я совершенно забыл упомянутьи я не знаю, важно ли это, но поле со списком находится внутри UserControl.XAML UserControl выглядит следующим образом:

<UserControl x:Class="...CombinationsToolBar"
         .... mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<ToolBarTray Name="toolBarTray1" >
    <ToolBar Name="toolBar1">
        <ComboBox Name="cbCombination" 
         ItemsSource="{Binding Path=Combinations, NotifyOnSourceUpdated=True, 
                                                                     IsAsync=True}"
            SelectedIndex="0" IsEditable="False"  
            SelectionChanged="CbCombinationSelectionChanged"
            SourceUpdated="CbCombinationSourceUpdated"
            TargetUpdated="CbCombinationTargetUpdated"></ComboBox>
    </ToolBar>
</ToolBarTray>

В коде UserControl у меня есть точки останова на CbCombinationSelectionChanged, CbCombinationSourceUpdated и CbCombinationTargetUpdated.

CbCombinationSelectionChanged запускается один раз при первой загрузке формы, содержащей пользовательский элемент управления.Он действительно вызывается во второй раз, когда очищается коллекция комбинаций, как сказал @asktomsk.

Обновленный источник и обновленная цель не срабатывают - CbCombinationSourceUpdated и CbCombinationTargetUpdated не вызываются.

Поскольку поле со списком находится внутри пользовательского элемента управления, а коллекция комбинаций находится внутри модели представления, а модель представления не имеет доступа к полю со списком, У меня нет возможности установить выбранноеИндекс комбо, если события не срабатывают .

: (

1 Ответ

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

Проблема в вашем this.Combinations.Clear();
Когда вы делаете это, он устанавливает SelectedItem = null и SelectedIndex = -1

Таким образом, вы должны снова установить выбор. Если у вас есть доступ к вашему ComboBox, просто напишите это cbCombination.SelectedIndex = 0; после заполнения списка комбинаций.
Конечно, вы также можете привязать SelectedItem / SelectedIndex к некоторому свойству в коде позади.

КСТАТИ
Также не требуется вызывать NotifyPropertyChanged(@"Combinations"); после заполнения коллекции, потому что Combinations уже реализует INotifyPropertyChanged.

Обновление

Чтобы обнаружить, что ваша ObservableCollection была изменена, подпишитесь на событие CollectionChanged в вашем коде UserControl . Убедитесь, что вы подписались до того, как коллекция изменилась!

Combinations.CollectionChanged += (s, e) =>
{
    if (cbCombination.Items.Count > 0)
        cbCombination.SelectedIndex = 0;
};

Еще одно предложение

Подход выше работает, когда вам не нужна более умная логика, чем просто выбрать нулевой индекс в выпадающем списке. Но часто вам понадобится более сложная логика для выбора какого-либо элемента. В этом случае вы можете добавить новое свойство к вашей модели:

public Combination SelectedCombination
{
    get{ return _selectedCombination; }
    set
    {
        _selectedCombination = value;
        NotifyPropertyChanged("SelectedCombination");
    }
}

и привяжите это свойство к вашему списку:

<ComboBox Name="cbCombination" ItemsSource="{Binding Combinations}" 
          SelectedIndex="0" SelectedItem={Bindings SelectedCombination} />

В этом случае вы можете выбрать любой элемент при заполнении коллекции комбинаций, и он будет автоматически выбран в выпадающем списке:

var combinationsList = CombinationsManager.CombinationsFor(someParam);
this.Combinations.Clear();
foreach (var combination in combinationsList)
    this.Combinations.Add(combination);

if (Combinations.Count > 0)
    SelectedCombination = Combinations[0];
...