Как изменить имя элемента в CheckedListBox?

У меня есть CheckedListBox, в котором есть X элементов. Эти элементы помещаются туда во время выполнения. Предполагается, что эти элементы представляют собой отчеты, которые могут отображаться в файле DataGridView. Теперь мне нужно отобразить количество записей для каждого отчета в круглых скобках рядом с именем отчета. Я пытался, не так уж долго, редактировать фактическое имя элемента, но не мог найти, как это сделать. Итак, я грубо заставил его. Сохранил элементы в массив, очистил элементы, добавил количество записей к каждому элементу в массиве, создал новые элементы. Что ж, это вызвало проблемы, потому что теперь он не сохраняет мои чеки, и причина этого в том, что всякий раз, когда я генерирую отчеты, я очищаю элементы и воссоздаю их. Ну, вместо того, чтобы делать еще один цикл foreach для сохранения проверенного статуса, кто-нибудь знает способ изменить текст существующих элементов в CheckedListBox?

Вот код, который у меня сейчас есть:

В MainForm.Designer.cs:

this.clbReports.Items.AddRange(new object[] {
"Report 1",
"Report 2",
"Report 3",
"Report 4",
"Report 5",
"Report 6",
"Report 7",
"Report 8",
"Report 9",
"Report 10",
"Report 11"});

И это выглядит так:

альтернативный текст

И я хочу, чтобы это выглядело так (но не все будут 0):

альтернативный текст

Вот функция SelectedIndexChanged:

private void clbReports_SelectedIndexChanged(object sender, EventArgs e)
{
    string strCheckBox = clbReports.SelectedItem.ToString();
    bool bShowAllIsChecked = clbReports.GetItemChecked(clbReports.FindString("Show All Error Reports"));
    bool bSelected = clbReports.GetItemChecked(clbReports.FindString(strCheckBox));
    int nIndex = -1;

    if (strCheckBox.Contains("Show All Error Reports"))
    {
        foreach (string str in _strReports)
        {
            if (!str.Contains("Show All Error Reports") && !str.Contains("Show Tagged Records"))
            {
                nIndex = clbReports.FindString(str);
                if (nIndex > -1)
                {
                    clbReports.SetItemChecked(nIndex, bSelected);
                }
            }
        }
    }
    else
    {
        if (strCheckBox.Contains("Show All Error Reports") || bShowAllIsChecked)
        {
            foreach (string str in _strReports)
            {
                nIndex = clbReports.FindString(str);
                if (nIndex > -1)
                {
                clbReports.SetItemChecked(nIndex, false);
                }
            }
        }

        nIndex = clbReports.FindString(strCheckBox);
        if (nIndex > -1)
        {
            clbReports.SetItemChecked(nIndex, bShowAllIsChecked ? true : bSelected);
        }
    }

    string[] strCheckedItems = new string[clbReports.CheckedItems.Count];
    clbReports.CheckedItems.CopyTo(strCheckedItems, 0);
    List<string> checkBoxReportFilter = new List<string>();
    foreach (ReportRecord obj in this._lstReportRecords)
    {
        foreach (string str in strCheckedItems)
        {
            if (str.Contains(obj.Description))
            {
                checkBoxReportFilter.Add(obj.PartID.ToString());
            }
        }
    }
    try
    {
        if (checkBoxReportFilter.Count == 0 && clbReports.CheckedItems.Count > 0)
        {
            throw new NullReferenceException();
        }

        _strReportFilter = String.Join(",", checkBoxReportFilter.ToArray());
    }
    catch (NullReferenceException)
    {
        _strReportFilter = "-1";
    }

    generateReport();
}

А вот код, в котором я очищаю элементы, получаю количество отчетов и создаю новые элементы.

_lstReportRecords = _dataController.ReportList;
bool[] bChecked = new bool[clbReports.Items.Count];
int nCounter = 0;
foreach (string str in _strReports)
{
    foreach (string str2 in clbReports.SelectedItems)
    {
        bChecked[nCounter] = str2.Contains(str);
    }
    nCounter++;
}

clbReports.Items.Clear();
nCounter = 0;

foreach (string str in _strReports)
{
    int nCount = _lstReportRecords.Where<ReportRecord>(delegate(ReportRecord rr) {
        return rr.Description == str;
    }).Count();

    string newReport = str + " (" + nCount + ")";
    clbReports.Items.Add(newReport);
    clbReports.SetItemChecked(nCounter, bChecked[nCounter]);
    nCounter++;
}

Скажите, пожалуйста, есть ли более простой способ сделать это. Я пытался выполнять циклы foreach через clbReports.Items, но он хочет, чтобы я привел его к строке (с ошибкой при попытке приведения к CheckBox), поэтому я не мог изменить значение. И даже если бы я мог привести его к CheckBox, у меня есть ощущение, что это даст мне ошибку, что перечисление не удалось, потому что список был изменен (или как они это называют). Любая помощь приветствуется. Спасибо.

Изменить. Имейте в виду, что отчет X предназначен только для того, чтобы фактические имена отчетов не отображались, чтобы он оставался универсальным. Однако в коде я просто скопировал и вставил, поэтому отчеты «Показать все отчеты об ошибках» и «Показать все записи с тегами» — это отчеты, которые мне нужно проверить.


person XstreamINsanity    schedule 08.09.2010    source источник
comment
Вам не нужен if strCheckBox.Contains(Show All Error Reports) в операторе else clbReports_SelectedIndexChanged, потому что он никогда не будет истинным, поскольку все они войдут в раздел «если», а не в другое. Это мелочь, но она поможет сделать код чище.   -  person Iain Ward    schedule 08.09.2010
comment
Почему бы не просто int nCount = _lstReportRecords.Where(rr => rr.Description == str) вместо запутанного пути?   -  person Timwi    schedule 08.09.2010
comment
@Timwi - Честно говоря, я не знал, что это проще. :) Я думал, вам нужно сделать это похоже на javascript, где вы определяете функцию. Теперь это изменилось в моем коде... во ВСЕХ местах, где я так делал. :)   -  person XstreamINsanity    schedule 08.09.2010
comment
@ w69rdy - На самом деле strCheckBox - это SelectedItem, что означает, что он мог быть выбран или отменен. Я думал то же самое, когда кодировал его, но обнаружил, что мне нужно проверить его.   -  person XstreamINsanity    schedule 08.09.2010
comment
@XstreamINsanity: Не беспокойтесь, учиться всегда полезно. ☺ Между прочим, технически это все еще определяет функцию, просто это гораздо более короткий синтаксис, чем синтаксис делегата.   -  person Timwi    schedule 08.09.2010
comment
@XstreamNsanity ? Все, что вам нужно во втором операторе if, это if(bShowAllIsChecked), так как он будет вводить только else, если strCheckBox.Contains(Show All Error Reports) == false, так зачем снова проверять, верно ли это, если причина, по которой это есть в во-первых, потому что это ложь??   -  person Iain Ward    schedule 08.09.2010
comment
@Timwi - Да, это так. :) Я все еще должен использовать его, когда есть больше решений.   -  person XstreamINsanity    schedule 08.09.2010
comment
@ w69rdy - Мои извинения. Я смотрел на что-то еще и запутался. Я думаю, что, когда я вносил изменения, копировал и вставлял частично рабочий код в более новый код, я, возможно, забыл это проверить. Спасибо, что дал мне знать.   -  person XstreamINsanity    schedule 08.09.2010
comment
@XstreamINsanity Нет проблем, это всего лишь мелочь, но она поможет сделать ваш код более понятным;)   -  person Iain Ward    schedule 08.09.2010


Ответы (4)


Правильный (== самый простой и самый прямой) ответ и решение:

this.clbReports.Items[nIndex] = "new text of the item"

да, эти предметы относятся к типу "объект". Нет, никто не против, строка тоже объект ;)

person sh code    schedule 13.04.2017

На вашем месте я бы попробовал интерфейс INotifyPropertyChanged. Вы не должны связываться с событиями без необходимости. это будет означать, что вы не можете использовать конструктор для создания элементов, но, насколько я понял, это все равно список, изменяемый во время выполнения...

В деталях:

• Создайте класс (например, «Foo»), который реализует INotifyPropertyChanged (по сути, это сообщит любому слушателю, что свойство текста изменилось). Этот класс будет содержать имена всех записей.

• создайте ObservableCollection и привяжите CheckedListBox к этой коллекции. В WinForms вам нужно будет создать DataBindingSource и подключить свою коллекцию к одному концу, а ComboBox к другому концу.

• Любые изменения, внесенные в коллекцию, будут видны в элементе управления.

HTH Себи

person Sebastian Edelmeier    schedule 08.09.2010
comment
Спасибо за предложение, но это может быть немного больше, чем нужно прямо сейчас. Я просматриваю другие примеры в Интернете и думаю, что могу просто использовать ListView с CheckBoxes = true и View = List. Я не знаю, почему предыдущий программист хотел использовать CheckedListBox, поскольку он кажется очень ограниченным. Спасибо хоть. - person XstreamINsanity; 08.09.2010

Чтобы изменить элементы в ListBox (или CheckedListBox), вы должны изменить ToString() результат этих элементов.

Самым простым решением было бы создать класс «Держатель», у которого есть ссылка на отчет, который он представляет. Тогда метод ToString() класса Holder должен быть примерно таким:

public override string ToString()
{
   return String.Format("{0} ({1})", BaseStr, MyReport.RecordCount);
}

Если вы как-то измените MyReport.RecordCount (из-за изменения количества записей в отчете), вы можете просто вызвать clbReports.Refresh(), и он автоматически покажет новое значение.

Я думаю, что таким образом вам даже не нужно решение временного массива во втором блоке кода; однако я хотел бы предложить альтернативный способ получения проверенного состояния элемента. Вы можете выполнить итерацию по clbReports.CheckedIndices и заполнить массив bChecked значениями true только для индексов в этом массиве.

person CreoValis    schedule 08.09.2010

Ну, из-за нехватки времени я попробовал что-то еще. Я выбрал ListView, где CheckBoxes = true и View = List. Я также снял флажки «Показать все отчеты об ошибках» и «Показать записи с тегами» вне списка. Это значительно упростило выполнение функций, которые я хотел. Вот новый код.

MainForm.Designer.cs

    // 
    // cbTaggedRecords
    // 
    this.cbTaggedRecords.AutoSize = true;
    this.cbTaggedRecords.Location = new System.Drawing.Point(151, 9);
    this.cbTaggedRecords.Name = "cbTaggedRecords";
    this.cbTaggedRecords.Size = new System.Drawing.Size(106, 17);
    this.cbTaggedRecords.TabIndex = 3;
    this.cbTaggedRecords.Text = "Tagged Records";
    this.cbTaggedRecords.UseVisualStyleBackColor = true;
    this.cbTaggedRecords.CheckedChanged += new System.EventHandler(this.ShowTaggedRecords_CheckChanged);
    // 
    // cbAllErrorReports
    // 
    this.cbAllErrorReports.AutoSize = true;
    this.cbAllErrorReports.Location = new System.Drawing.Point(6, 9);
    this.cbAllErrorReports.Name = "cbAllErrorReports";
    this.cbAllErrorReports.Size = new System.Drawing.Size(102, 17);
    this.cbAllErrorReports.TabIndex = 2;
    this.cbAllErrorReports.Text = "All Error Reports";
    this.cbAllErrorReports.UseVisualStyleBackColor = true;
    this.cbAllErrorReports.CheckedChanged += new System.EventHandler(this.ShowAllErrorReports_CheckChanged);
    // 
    // listView1
    // 
    this.listView1.CheckBoxes = true;
    listViewItem1.StateImageIndex = 0;
    listViewItem2.StateImageIndex = 0;
    listViewItem3.StateImageIndex = 0;
    listViewItem4.StateImageIndex = 0;
    listViewItem5.StateImageIndex = 0;
    listViewItem6.StateImageIndex = 0;
    listViewItem7.StateImageIndex = 0;
    listViewItem8.StateImageIndex = 0;
    listViewItem9.StateImageIndex = 0;
    this.listView1.Items.AddRange(new System.Windows.Forms.ListViewItem[] {
    listViewItem1,
    listViewItem2,
    listViewItem3,
    listViewItem4,
    listViewItem5,
    listViewItem6,
    listViewItem7,
    listViewItem8,
    listViewItem9});
    this.listView1.Location = new System.Drawing.Point(6, 29);
    this.listView1.Name = "listView1";
    this.listView1.Size = new System.Drawing.Size(281, 295);
    this.listView1.TabIndex = 1;
    this.listView1.UseCompatibleStateImageBehavior = false;
    this.listView1.View = System.Windows.Forms.View.List;
    this.listView1.ItemChecked += new System.Windows.Forms.ItemCheckedEventHandler(this.listView_ItemChecked);

MainForm.cs

    private void listView_ItemChecked(object sender, ItemCheckedEventArgs e)
    {
        if (e != null)
        {
            int nLength = e.Item.Text.IndexOf("(") - 1;
            string strReport = nLength <= 0 ? e.Item.Text : e.Item.Text.Substring(0, nLength);
            if (e.Item.Checked)
            {
                _lstReportFilter.Add(strReport);
            }
            else
            {
                _lstReportFilter.Remove(strReport);
            }
        }

        List<string> checkBoxReportFilter = new List<string>();
        foreach (ReportRecord obj in this._lstReportRecords)
        {
            foreach (string str in _lstReportFilter)
            {
                if (str.ToLower().Contains(obj.Description.ToLower()))
                {
                    checkBoxReportFilter.Add(obj.PartID.ToString());
                }
            }
        }
        try
        {
            if (checkBoxReportFilter.Count == 0 && listView1.CheckedItems.Count > 0)
            {
                throw new NullReferenceException();
            }

            _strReportFilter = String.Join(",", checkBoxReportFilter.ToArray());
        }
        catch (NullReferenceException)
        {
            _strReportFilter = "-1";
        }

        if (!bShowAll)
        {
            generateReport();
        }
    }

    private void ShowAllErrorReports_CheckChanged(object sender, EventArgs e)
    {
        bShowAll = true;
        foreach (ListViewItem lvi in listView1.Items)
        {
            lvi.Checked = ((CheckBox)sender).Checked;
        }

        _lstReportFilter.Clear();
        bShowAll = false;
        generateReport();
    }

    private void ShowTaggedRecords_CheckChanged(object sender, EventArgs e)
    {
        bool bChecked = ((CheckBox)sender).Checked;
        if (bChecked)
        {
            if (!_lstReportFilter.Contains("Show Tagged Records"))
            {
                _lstReportFilter.Add("Show Tagged Records");
            }
        }
        else
        {
            _lstReportFilter.Remove("Show Tagged Records");
        }

        listView_ItemChecked(null, null);
    }

Код для добавления счетчиков в CheckBoxes

            _lstReportRecords = _dataController.ReportList;

            int nTotalCount = 0;

            foreach (ListViewItem lvi in listView1.Items)
            {
                int nCount = _lstReportRecords.Where(rr => lvi.Text.Contains(rr.Description)).Count();
                nTotalCount += nCount;
                lvi.Text = (lvi.Text.Contains("(") ? lvi.Text.Substring(0, lvi.Text.IndexOf("(") + 1) : lvi.Text + " (") + nCount.ToString() + ")";
            }

            cbAllErrorReports.Text = (cbAllErrorReports.Text.Contains("(") ? cbAllErrorReports.Text.Substring(0, cbAllErrorReports.Text.IndexOf("(") + 1) : cbAllErrorReports.Text + " (") + nTotalCount.ToString() + ")";
            int nTaggedCount = _lstReportRecords.Where(rr => rr.Description.Contains("Tagged")).Count();
            cbTaggedRecords.Text = (cbTaggedRecords.Text.Contains("(") ? cbTaggedRecords.Text.Substring(0, cbTaggedRecords.Text.IndexOf("(") + 1) : cbTaggedRecords.Text + " (") + nTaggedCount.ToString() + ")";

Всем спасибо за помощь и идеи.

person XstreamINsanity    schedule 08.09.2010