为什么通过 IndexOf() 找不到 CheckedListBox 中存在的项目?

Why is the item that exists in the CheckedListBox not found via IndexOf()?

我有这个代码:

if (currentWeekSaved)
{
    DateTime currentWeek = Convert.ToDateTime(comboBoxWeekToSchedule.SelectedValue);
    AssignmentHistory ah = AYttFMConstsAndUtils.AssignmentHistList
        .FirstOrDefault(i => i.WeekOfAssignment == currentWeek && i.TalkType == BIBLE_READING_TALK_TYPE);
    if (ah != null)
    {
        var assignedStudentFirstname = AYttFMConstsAndUtils.GetStudentFirstNameForID(ah.StudentID_FK);
        var assignedStudentLastname = AYttFMConstsAndUtils.GetStudentLastNameForID(ah.StudentID_FK);
        assignedStudent = new Student() {FirstName = assignedStudentFirstname, LastName = assignedStudentLastname, StudentID = ah.StudentID_FK};
    }
}
List<Student> BRStudents =
    AYttFMConstsAndUtils.StudentsList.Where(h => h.EnrolledInAYttFM)
        .Where(i => i.RecommendedNextTalkTypeID.Equals(BIBLE_READING_TALK_TYPE))
        .OrderBy(j => j.WeekOfLastAssignment)
        .ToList();
if (null != assignedStudent)
{
    // If exists in list, remove it first, and then add it back at the top
    //int assignedStudentIndex = BRStudents.IndexOf(assignedStudent);
    int assignedStudentIndex = checkedListBoxBR.Items.IndexOf(assignedStudent.FullName);
    if (assignedStudentIndex > -1)
    {
        BRStudents.RemoveAt(assignedStudentIndex);
    }
    BRStudents.Insert(0, assignedStudent);
}
checkedListBoxBR.DataSource = BRStudents;
checkedListBoxBR.DisplayMember = "FullName";
checkedListBoxBR.ValueMember = "StudentID";

如果已经有人为正在处理的那一周分配了人,我想先将他们从 checkedListBoxBR 中删除,然后再将他们添加回索引 0。但是,即使这个人 在 checkedListBoxBR 中,这一行:

int assignedStudentIndex = 
    checkedListBoxBR.Items.IndexOf(assignedStudent.FullName);

...找不到它们。 "assignedStudent.FullName" 的值确实等于其中一项的值;如上所示,"FullName" 是 CheckedListBox 的 ValueMember:

通过它,学生列表 BRStudents 有 2 个成员,一个已经分配的人和另一个人; "assignedStudent"是已经分配的人; checkedListBoxBR 有三个项目,已分配的人加上两个 其他人。

那么,当分配的人用 FullName 表示时,为什么 assignedStudentIndex -1?确实,我没有在这一行中明确分配 FullName:

assignedStudent = new Student() {FirstName = assignedStudentFirstname, LastName = assignedStudentLastname, StudentID = ah.StudentID_FK};

...但是 FullName 是 class 中的一个计算字段:

public class Student
{
    public int StudentID { get; set; }
    . . .
    public string FirstName { get; set; }
    public string LastName { get; set; }
    . . .
    public string FullName
    {
        get
        {
            return $"{FirstName} {LastName}";
        }
        set { } 
    }
}

那么,为什么在 CheckedListBox 的项目中找不到 "So and So" 最明确的地方?

更新

Olivier 的建议似乎不错 ("iterate through checkedListBoxBR.Items and see if you find a match between the item's DisplayMember and the assignedStudent.FullName")。但是怎么办?我想也许像这样的东西可以做到:

for (int i = 0; i < checkedListBoxBR.Items.Count; i++)
{
    if checkedListBoxBR.Items[0].DisplayMember.Equals(assignedStudent.FullName)
    {
        checkedListBoxBR.RemoveAt(i);
    }
}

...但是 "DisplayMember" 在这里不被识别("RemoveAt" 也不被识别)。

更新 2

响应 Olivier 的建议,我将以上内容修改为:

for (int i = 0; i < checkedListBoxBR.Items.Count; i++)
{
    if checkedListBoxBR.Items[i].DisplayMember.Equals(assignedStudent.FullName)
    {
        checkedListBoxBR.Items.RemoveAt(i);
    }
}

...但它仍然认为 DisplayMember 属性-不受欢迎。

更新 3

我已经简化了代码,并且运行良好。这是简化版:

// Called whenever the week changes (a new week is navigated to/selected in the combobox)
private void PopulateBibleReadingComboBox()
{
    int BIBLE_READING_TALK_TYPE = 1;
    Student assignedStudent = null;
    List<Student> assignedStudents = null;

    // If the week has been saved, get the student who has been assigned the Bible Reading
    if (currentWeekSaved)
    {
        DateTime currentWeek = Convert.ToDateTime(comboBoxWeekToSchedule.SelectedValue);
        AssignmentHistory ah = AYttFMConstsAndUtils.AssignmentHistList
            .FirstOrDefault(i => i.WeekOfAssignment == currentWeek && i.TalkType == BIBLE_READING_TALK_TYPE);
        if (ah != null)
        {
            var assignedStudentFirstname = AYttFMConstsAndUtils.GetStudentFirstNameForID(ah.StudentID_FK);
            var assignedStudentLastname = AYttFMConstsAndUtils.GetStudentLastNameForID(ah.StudentID_FK);
            assignedStudent = new Student() {FirstName = assignedStudentFirstname, LastName = assignedStudentLastname, StudentID = ah.StudentID_FK};
            // Use the ID to get the student and put him/her in a 1-person list (needed for
            // the subsequent LINQ Union)
            assignedStudents =
                AYttFMConstsAndUtils.StudentsList.Where(i => i.StudentID == ah.StudentID_FK).ToList();
        }
    }
    // Get all the candidates for assignment
    List<Student> BRStudents =
    AYttFMConstsAndUtils.StudentsList.Where(h => h.EnrolledInAYttFM)
        .Where(i => i.RecommendedNextTalkTypeID.Equals(BIBLE_READING_TALK_TYPE))
        .OrderBy(j => j.WeekOfLastAssignment)
        .ToList();
    if (null != assignedStudent) 
    {
        List<Student> allBRStudents = assignedStudents.Union(BRStudents).ToList();
        checkedListBoxBR.DataSource = allBRStudents;
        checkedListBoxBR.DisplayMember = "FullName";
        checkedListBoxBR.ValueMember = "StudentID";
    }
    else // No assigned student found, bind to the candidate students only
    {
        checkedListBoxBR.DataSource = BRStudents;
        checkedListBoxBR.DisplayMember = "FullName";
        checkedListBoxBR.ValueMember = "StudentID";
    }
    // In either case, highlight and check the first one now
    checkedListBoxBR.SelectedIndex = 0;
    checkedListBoxBR.SetItemChecked(0, true);
}

我可以看出两点错误。

首先,您填充 checkedListBoxBR ,然后 检查是否存在某个项目。

其次,你在比较苹果和橘子。 checkedListBoxBR.Items 是对象的集合,您正在通过 indexOf 将其与字符串 (assignedStudent.FullName) 进行比较。那是行不通的。

更好的解决方案是遍历 checkedListBoxBR.Items 并查看是否找到项目 DisplayMemberassignedStudent.FullName 之间的匹配项。

或者您可以在 indexOf 调用中使用 Student 对象,但是您需要确保实现 IEquatable、覆盖 Equals、GetHashCode 等。

您的 checkedListBoxBR 的项目是 Student 类型,因为您的 DataSource 中的项目是 Student:

类型
List<Student> BRStudents = [...]
checkedListBoxBR.DataSource = BRStudents;

通过使用带有字符串 (Student.FullName) 作为参数的 IndexOf 函数,您可以将多个 Student 对象与一个字符串进行比较。没有 Student 等于您的字符串,因此您得到 -1 的结果。尝试像这样修改您的代码:

int assignedStudentIndex = checkedListBoxBR.Items.IndexOf(assignedStudent);

此外,您可能想要 override the Equals method

编辑: 正如@olivier-de-meulder 正确指出的那样,您需要将这些行移到查找上方才能使任何选项起作用:

checkedListBoxBR.DataSource = BRStudents;
checkedListBoxBR.DisplayMember = "FullName";
checkedListBoxBR.ValueMember = "StudentID";