为什么通过 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
并查看是否找到项目 DisplayMember
和 assignedStudent.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";
我有这个代码:
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
并查看是否找到项目 DisplayMember
和 assignedStudent.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";