为什么 CheckedListBox 的 SelectedItem 会因 CLB 的填充方式而有所不同?

Why do CheckedListBox's SelectedItem work differently depending on how the CLB was populated?

我有两个看起来一样的 CheckedListBoxes(除了内容)。我这样加载一个:

private void PopulateReportsListBox()
{         
    checkedListBoxReports.Items.AddRange(
        ReportSchedulerConstsAndUtils.Reports.ToArray<object>());
}

public static List<string> Reports = new List<string>
{ 
        "Produce Usage", 
        "Delivery Performance",
        "Fill Rate by Customer / Location",
        "Price Compliance"
};

有了那个,我可以像这样获取 CLB 的 ItemCheck 事件中显示的值:

private void checkedListBoxReports_ItemCheck(object sender, 
    ItemCheckEventArgs iceargs)
{
    for (int i = 0; i < checkedListBoxReports.Items.Count; ++i)
    {
        if (i != iceargs.Index) checkedListBoxReports.SetItemChecked(i, 
false);
    }
    String selectedRpt = checkedListBoxReports.SelectedItem.ToString();
    DisableParameterGroupBoxes();
    EnableParameterGroupBox(selectedRpt);
}

"selectedRpt" 包含我期望的值("Produce Usage" 如果第一项被选中,等等)。

但是,我像这样从数据库加载另一个 CLB:

private void PopulateUnitsListBox()
{
    using (SqlConnection con = new 
        SqlConnection(ReportSchedulerConstsAndUtils.CPSConnStr))
    {
        using (SqlCommand cmd = new 
            SqlCommand(ReportSchedulerConstsAndUtils.SelectUnitsQuery, con))
        {
            cmd.CommandType = CommandType.Text;
            using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
            {
                DataTable dt = new DataTable();
                sda.Fill(dt);
                ((ListBox)checkedListBoxUnits).DataSource = dt;
                ((ListBox)checkedListBoxUnits).DisplayMember = "Unit";
                ((ListBox)checkedListBoxUnits).ValueMember = "Unit";
            }
        }
    }
}

...而且我无法访问其 ItemCheck 事件中的显示值。我必须使用 CLB 的文本属性而不是 SelectedItem.ToString()。如果我使用后者,我会得到(对于所有项目),"System.Data.DataRowView"

为什么?使用 "Text" 时有什么我应该注意的 "gotchas" 吗?难道reliable/do我需要Trim()吗?

SelectedItem 属性 returns 集合中当前选定的用作源的对象,而不是控件中显示的文本。

CheckedListBox 将显示项目时,控件首先检查 属性 DisplayMember,如果对象上不存在指定的 属性 或 DisplayMember 是一个空字符串,而是显示对象的 ToString() 方法的结果。

在您的第一个 CheckedListBox 中,您使用对象数组作为项目集合,其中元素实际上是字符串,DisplayMember 属性 为空。因此项目和显示的文本是相同的,字符串。

在您的第二个 CheckedListBox 中,您使用 DataTable(您可以将其视为 DataRowView 的可枚举)作为项目集合,使用 DisplayMember = "Unit"。因此,在这种情况下 SelectedItemDataRowView,显示的文本是成员 "Unit".

如果您希望始终使用两个 CheckedListBox 中显示的文本,请使用您所说的 属性 Text。 属性 获取当前所选项目的显示文本(无论来源如何)。

private void checkedListBoxReports_ItemCheck(object sender, ItemCheckEventArgs iceargs)
{
    for (int i = 0; i < checkedListBoxReports.Items.Count; ++i)
    {
        if (i != iceargs.Index) 
            checkedListBoxReports.SetItemChecked(i, false);
    }

    string selectedRpt = checkedListBoxReports.Text;

    DisableParameterGroupBoxes();
    EnableParameterGroupBox(selectedRpt);
}

关于您对此的担忧属性:

Text 将 return 恰好是函数 ToString() 的值或 DisplayMember.

中指定的 属性 的值

另外,您可以搜索设置此属性的项目,显示文本等于指定文本的项目将被选中。

如果 SelectionMode 属性 设置为 SelectionMode.MultiExtended,则此 属性 return 是第一个选定项目的文本。

希望对您有所帮助。

Why do CheckedListBox's SelectedItem work differently depending on how the CLB was populated?

它的工作方式没有什么不同。它总是 returns 来自 Items collection 的 object 或 null。这是类似这样的东西的捷径

int selectedIndex = listBox.SelectedIndex;
object selectedItem = selectedIndex >= 0 ? listBox.Items[selectedIndex] : null;

"selectedRpt" holds the value I expect ("Produce Usage" if the first item is selected, etc.).

然后

I have to use the CLB's Text property rather than SelectedItem.ToString(). If I use the latter, I get (for all items), "System.Data.DataRowView"

您不应该首先使用 SelectedItem(或任何 Items collection 项目).ToString() 方法来获取显示文本。

控件本身使用一些逻辑来确定该文本 - 是的,在某些情况下可能是 ToString() 方法,但并非总是如此 - 例如 DisplayMember 属性 改变了行为。

但关键是你不需要知道那个逻辑。该控件公开了它在内部使用的方法。它被称为(令人惊讶的)GetItemText

public string GetItemText(
    object item
)

并根据文档

Returns the text representation of the specified item.

还有

If the DisplayMember property is not specified, the value returned by GetItemText is the value of the item's ToString method. Otherwise, the method returns the string value of the member specified in the DisplayMember property for the object specified in the item parameter.

很快,您应该始终使用该方法。

  • 所选项目:

    listBox.GetItemText(listBox.SelectedItem)

  • 具体索引:

    listBox.GetItemText(listBox.Items[index])