c++ cli Сортировка ListBox

393
27 июня 2017, 21:23

Есть xml файл, у каждой ноды есть 2 атрибута, допустим name и number, хочу сделать ListBox с сортировкой по одному из атрибутов, для наглядности xml:

<xml>
 <node name="al capone" number="3" />
 <node name="hyunday" number="1" />
 <node name="lego" number="2" />
</xml>

Я могу сортировать ListBox по алфавиту, но мне нужно сортировать его по нажатии кнопки по одному из атрибутов. Хотел сейчас формировать List из этого xml и уже сортировать его, но что-то для C++/CLI примеров маловато, а перевести с C# как-то не получается. Добавлю еще тег C#, так как обычно у меня нету проблем с переводом на CLI, а народу там побольше.

Answer 1

Самый простой способ - перейти на C#. Готов поспорить, что кода у вас от силы несколько сотен строк. Переписать их можно за несколько дней максимум, после чего жизнь станет легка и приятна.

Впрочем, после этого вам станут советовать перейти с WinForms на WPF. Потом на .NET Core (кроссплатформенность же!) и т. д.

Также уверен, что это задание по учёбе. Поэтому от C++/CLI никуда не деться. Что ж, поехали!

В xml могут быть использованы любые имена элементов за одним исключением: корневой тег не может называться xml. Так что придётся переименовать. Например, назовём его nodes.

<nodes>
 <node name="al capone" number="3" />
 <node name="hyunday" number="1" />
 <node name="lego" number="2" />
</nodes>

В современной разработке ПО самым правильным подходом считается создание модели для каждой используемой сущности. Поэтому создадим класс node:

namespace CppWinForm1 {
    using namespace System;
    using namespace System::Xml::Serialization;
    using namespace System::Collections::Generic;
    public ref class node
    {
    public:
        [XmlAttributeAttribute]
        property String^ name;
    public:
        [XmlAttributeAttribute]
        property int number;
    public:
        static int Sort(node^ node1, node^ node2)
        {
            return node1->number.CompareTo(node2->number);
        }
    public:
        static Comparison<node^>^ comparison = gcnew Comparison<node^>(&Sort);
    };
    typedef List<node^>^ NodeList;
}

Пространство имён замените на своё.

Обратите внимание: названия класса и свойств совпадают с именами тегов xml. Свойства и класс объявлены public - это нужно для того, чтобы десериализатор их мог увидеть.

Также в классе имеется метод Sort (думаю, назначение понятно) и Comparison, необходимый для передачи в метод сортировки коллекции.

Ещё имеется typedef, также необходимый для использования в сериализаторе.

Подключаем этот файл в файле формы с помощью #include.

В классе формы объявляем поле - это коллекция, в которой будет храниться список наших классов:

NodeList nodes; // List<node^>^ nodes;

Её можно объявить и как List<node^>^ nodes;, но раз уж у нас имеется typedef, то почему бы его не использовать.

Создаём ещё одно поле. Это класс, автоматически (де)сериализующий данные в/из xml. Именно для него нужны публичные свойства и совпадения имён.

XmlSerializer^ serializer = gcnew XmlSerializer(NodeList::typeid, gcnew XmlRootAttribute(L"nodes"));

В конструктор нужно передать тип класса, с которым он будет работать. Написать List<node^>^::typeid нельзя. Поэтому и был использован typedef.

В том месте, где нужно считать данные из файла xml и поместить их в ListBox, пишем следующий код:

FileStream^ stream = File::OpenRead(L"in.txt");
nodes = (NodeList)serializer->Deserialize(stream);
stream->Close();
listBox1->ValueMember = L"number";
listBox1->DisplayMember = L"name";
listBox1->DataSource = nodes;

Открываем поток. Сериализатор считывает данные и заполлняет коллекцию данными - одна строка кода! Удобно, не правда ли? Закрываем поток.

Потом привязываем коллекцию к листбоксу. Это тоже делается одной строкой! Если ещё не знакомы с привязкой данный - бегом читать документацию.

Осталось сделать сортировку. Всё просто:

nodes->Sort(node::comparison);
listBox1->DataSource = nullptr;
listBox1->ValueMember = L"number";
listBox1->DisplayMember = L"name";
listBox1->DataSource = nodes;

У коллекции List есть метод Sort, его и используем. В него передаём наш comparison. После чего делаем перепривязку данных.

Используемые пространства имён:

using namespace System;
using namespace System::IO;
using namespace System::Collections::Generic;
using namespace System::Xml::Serialization;
READ ALSO
Остановить все Windows службы, не содержащихся в списке

Остановить все Windows службы, не содержащихся в списке

Останавливаю службы из списка List<string> таким способом:

256
Сортировка текста в тхт файле по алфавиту

Сортировка текста в тхт файле по алфавиту

В тхт файле есть строки типа :

323
Сценарий обработки запросов в Telegram Bot c#

Сценарий обработки запросов в Telegram Bot c#

Как в Telegram bot обрабатывать команды?

239