Как добавить DisplayMember и ValueMember к одному элементу ComboBox с назначенным источником данных?

Я успешно добавляю пары Display/Value в комбинированный список следующим образом:

List<Student> BRStudents =
        studentsList.Where(h => h.EnrolledInAYttFM)
            .Where(i =>     
    i.RecommendedNextTalkTypeID.Equals(BIBLE_READING_TALK_TYPE))
            .OrderBy(j => j.WeekOfLastAssignment)
            .ToList();
    comboBoxBR.DataSource = BRStudents;
    comboBoxBR.DisplayMember = "FullName";
    comboBoxBR.ValueMember = "StudentID";

... но я тогда (в некоторых случаях) хочу добавить еще один элемент в comboBoxBR, который отсутствует в списке BRStudents. Если я попытаюсь сделать это:

AssignmentHistory ah = AYttFMConstsAndUtils.AssignmentHistList
    .FirstOrDefault(i => i.WeekOfAssignment == currentWeek && i.TalkType == 1);
string fullName = AYttFMConstsAndUtils.GetStudentFullNameForID(ah.StudentID_FK);
comboBoxBR.Items.Add(fullName);

... Я получаю, "Коллекция предметов не может быть изменена, когда установлено свойство DataSource."

На самом деле, я хочу сделать что-то вроде этого:

comboBoxBR.Items.Add(fullName, ah.StudentID_FK);

Есть ли способ объединить два результата (список Student и одну AssignmentHistory) в словарь или некоторую подобную коллекцию, а затем назначить его в качестве источника данных для comboBoxBR?

Для полного раскрытия, вот определения Студента и AssignmentHistory:

public class Student
{
    public int StudentID { get; set; }
    public int FamilyID { get; set; }
    public bool EnrolledInAYttFM { get; set; }
    public DateTime DateEnrolledOrHiatusAYttFM { get; set; }
    public bool GivesBibleReading { get; set; }
    public bool PresentsICRVBS { get; set; }
    public bool IsHouseholder { get; set; }
    public bool IsMale { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string EmailAddr { get; set; }
    public DateTime WeekOfLastAssignment { get; set; }
    public int RecommendedNextTalkTypeID { get; set; }
    public int NextCounselPoint { get; set; }
    public string FullName => $"{FirstName} {LastName}";
}

public class AssignmentHistory
{
    public DateTime WeekOfAssignment { get; set; }
    public int TalkType { get; set; } 
    public int StudentID_FK { get; set; }
    public int AssistantID_FK { get; set; } 
    public int CounselPoint { get; set; }
    public bool HasBeenEmailed { get; set; }
    public bool SlipHasBeenPrinted { get; set; }        
}

1 ответ

Решение

Вместо добавления элементов в коллекцию Items комбо (невозможно, если вы установили DataSource), первое, что приходит на ум, - это добавление элементов в List<Students> сам по себе используется в качестве источника данных, но это не достигает вашей цели, поскольку отсутствует механизм информирования ComboBox о том, что в источнике данных появился новый элемент. Вы не сможете увидеть добавленный элемент, если не перепривязать список к списку. Для этого сначала нужно отменить привязку предыдущего источника данных, а затем снова связать список.

// Assuming a lot about your student class, hope it's clear the intention
BRStudents.Add(new Student() { newName = "ANewStudent", ID = 1} );
comboBoxBR.DataSource = null;
comboBoxBR.DataSource = BRStudents;
comboBoxBR.DisplayMember = "FullName";
comboBoxBR.ValueMember = "StudentID";

Тем не менее, есть лучшее решение, и это класс BindingList(T)
Этот класс способен обновлять объект, к которому вы привязываете его экземпляр.

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

BindingList<Student> bl = new BindingList<Student>(BRStudents);
comboBoxBR.DataSource = bl;
comboBoxBR.DisplayMember = "FullName";
comboBoxBR.ValueMember = "StudentID";

и когда вы хотите добавить новый элемент в список, вы пишете
(при необходимости переместите bl в глобальную область)

bl.Add(new Student() { newName = "ANewStudent", ID = 1} );

В документации говорится, что вы должны вызывать ResetBindings для принудительного обновления элемента управления, но это не всегда требуется...

Другие вопросы по тегам