Список с несколькими значениями автоматически выбирает нежелательный элемент

#c# #winforms #listbox

#c# #winforms #список

Вопрос:

У меня есть объект, у которого есть некоторые атрибуты из выбранного списка — скажем, рекламная акция, которая может иметь от 0 до X каналов связи. Для отображения / редактирования этой информации я использую список с параметром SelectionMode==MultiExtended.

Но в некоторых случаях он ведет себя странно

  1. У меня есть продвижение с выбранными 2 каналами связи (первый и последний из трех каналов),

  2. Я нажимаю на второй канал (который ранее был единственным невыбранным каналом) и знаю, что он показывает, что выбраны 1-й и 2-й каналы (я установил флажок в начале события listbox SelectedIndexChanged — и он показывает, что SelectedItems .Count == 2, хотя я нажал на один элемент, не удерживая клавиши Ctrl или Shift), и в этом случае событие SelectedIndexChanged запускается дважды, во всех остальных случаях оно запускается только один раз

  3. Это происходит только после первого открытия этой диалоговой формы, если я вручную выбираю 1-й и 3-й элементы каналов, а затем нажимаю на 2-й элемент — тогда он работает правильно

Скринкаст проблемы в действии

http://screencast.com/t/lVs0e9oau

Вот как я загружаю список всех возможных каналов в listbox

 foreach (var ct in Promotion_operations.Configuration.PromoCommunicationTypes)
{
    KeyValuePair<string, PromotionCommunicationType> nct = 
        new KeyValuePair<string, PromotionCommunicationType>(ct.Name, ct);
    communications.Add(nct);
}
PromotionCommunicationList.DataSource = communications; //Promotion_operations.Configuration.PromoCommunicationTypes;
PromotionCommunicationList.DisplayMember = "Key";
PromotionCommunicationList.ValueMember = "Value";
  

Вот как я загружаю выбранные элементы на основе данных Promotion

 private void LoadSelectedCommunicationsList(ListBox lstbox, List<PromotionCommunication> communications)
{
    lstbox.SelectedItems.Clear();
    foreach (var ct in communications)
    {
        for (int j = 0; j < lstbox.Items.Count; j  )
        {                    
            if (ct.CommunicationType.Id == ((KeyValuePair<string, PromotionCommunicationType>)lstbox.Items[j]).Value.Id)
            {
                lstbox.SelectedItems.Add(lstbox.Items[j]);
            }
        }
    }
}
  

Что может быть причиной такого поведения?

при нажатии на один ранее невыбранный список выбирается как вновь выбранный элемент, так и первый элемент списка?

Комментарии:

1. итак, вы говорите, что у вас есть, например, 10 элементов в списке, и вы выбираете, например, третий, что еще будет выбрано?

2. @terrybozzio будет выбран третий, а также первый вариант, но когда я повторяю его во второй раз, он работает правильно. На самом деле это происходит только в одном конкретном сценарии (тот, который я описал — если изначально выбран 1-й и 3-й элементы, и я вручную нажимаю на 2-й элемент — в результате я получаю 1-й и 2-й выбранные элементы)

3. @terrybozzio и в тех случаях, когда этот 1-й элемент выбирается автоматически, событие selectedindexchanged в списке listbox запускается дважды, но в других случаях (когда выбор работает правильно) это событие запускается только один раз

4. вы пробовали метод listbox.clearSelected()?

5. @terrybozzio Мне нужна опция для выбора нескольких значений… и я не вижу, в каком месте я мог бы это использовать? В списке выберите событие? Но тогда я должен каким-то образом фильтровать только те случаи, когда я не пытаюсь выполнить множественный выбор (не используя клавиши Ctrl, Shift)?

Ответ №1:

Ваши PromotionCommunicationList и HistoryCommunicationList совместно используют ту же ссылку на ваш список объектов , DataSource что и . Тем не менее, у них одно и то же BindingContext , и они разделяют одно и то же CurrencyManager . CurrencyManager запоминает выбранные элементы вашего ListBox элемента управления, и именно здесь возникает ваш конфликт, потому что он сохраняет выбранные элементы обоих ваших ListBoxes элементов управления. Вы уже нашли решение своей проблемы, потому что new CurrencyManager создается, когда вы устанавливаете «другой» список (копию вашего исходного) как DataSource . Другим возможным решением было бы создание нового BindingContext для одного из ваших ListBox элементов управления.
Вы можете попробовать это сделать:

 PromotionCommunicationList.DataSource = communications;
(..)
HistoryCommunicationList.BindingContext = new BindingContext(); // Add this
HistoryCommunicationList.DataSource = communications;
  

Это должно решить вашу проблему. Для получения дополнительной информации о BindingContext проверьте эту ссылку в MSDN.

Ответ №2:

Я нашел причину проблемы, хотя я действительно не понимаю, почему это вызвало такое поведение (если кто-нибудь ответит на этот вопрос, я приму это как ответ на этот вопрос)

У меня было 2 списка в моей форме, и оба они использовали одну и ту же коллекцию в качестве источника данных, НО!!! SelectedItems был выбран с помощью кода (фактически кажется, что в winforms невозможно привязать выбранные элементы списка к данным)

ИЗНАЧАЛЬНО мой код был:

 PromotionCommunicationList.DataSource = communications;
(..)
HistoryCommunicationList.DataSource = communications;
  

Исправленная версия:

 PromotionCommunicationList.DataSource = communications.ToList();
(..)
HistoryCommunicationList.DataSource = communications.ToList();
  

Я знаю, что ToList() создает копию, но я не понимаю, что плохого в том, что для элементов списка из 2 списков используется та же коллекция, что и для источника данных? Почему это влияет на коллекцию SelectedItems?