Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: C++ CLI databinding  (Прочитано 7066 раз)
0 Пользователей и 1 Гость смотрят эту тему.
oktonion
Постоялец

ru
Offline Offline

« : 11-03-2015 12:48 » new

Доброго времени суток.

Выпало мне несчастье связаться с элементами windows forms и соответственно managed C++.

Но перейду сразу к проблеме:
Нужно выводить данные на форму + обеспечить их легкое изменение. Лучше всего для этого подошел элемент DataGridView. Для того чтобы привязать данные к ячейкам этой таблицы необходимо иметь managed класс, различные property которого мы будем собственно привязывать и в дальнейшем через них будем менять данные. Сами данные мы получаем из обычного нормального C++, следовательно нужна обертка для связки managed property с unmanaged полями данных.

Класс-обертка:
Код:
ref class ConnectedSignalCLI
{
private:
bool _a;

public:
ConnectedSignalCLI(SignalsManager::ConnectedSignal &sig)
{
_a = sig.size;
}

property bool a
{
bool get() { return _a; }
void set(bool val) { _a = val; }
};
};

В создании формы:
Код:
auto bs_d = gcnew BindingSource();

for (size_t j = 0; j < connectedSignals.size(); j++)
{
if (connectedSignals[j].size == sizeof(bool))
{
auto tmp = gcnew ConnectedSignalCLI(connectedSignals[j]);
bs_d->Add(tmp);
}
}

dgvLocalD1->Columns[0]->DataPropertyName = "a";
dgvLocalD1->DataSource = bs_d;

Загвоздка в том что это поле булево, тоесть у колонки свойство ColumnType мною выставлено в DataGridViewCheckBoxColumn. Я ожидаю что при нажатии на чекбоксы внутри моего dgvLocalD1 будет вызываться "прибинженное" свойство
Код:
property bool a
и его метод set для каждого из чекбоксов. Но этого не происходит.

Вопрос напрашивается сам: что я делаю/понимаю не так? И как бы это реализовать по человечески.
« Последнее редактирование: 11-03-2015 13:32 от oktonion » Записан
oktonion
Постоялец

ru
Offline Offline

« Ответ #1 : 11-03-2015 19:17 » 

UPD:
если ColumnType выставить в DataGridViewTextColumn и вручную прописывать в ячейках False\True то все работает. Но на чекбоксах не работает. Если честно я в тупике. Очень хотелось бы услышать какие то мысли от шарпистов и разбирающихся товарищей.
Записан
oktonion
Постоялец

ru
Offline Offline

« Ответ #2 : 12-03-2015 12:11 » 

После долгих изысканий проблема решена:

Такое поведение DataGridViewCheckBoxCell обусловлено тем, что при редактировании в таблице поля ячейки само значение не меняется пока мы не выйдем из редактирования.

При текстовом типе поле ячейки (DataGridViewTextBoxCell) это выглядит очень логично:
1) Мы выбираем ячейку
2) Мы открываем ее на редактирование, меняем в ней текст как нам нужно
3) Мы выходим из редактирования ячейки (подтверждаем установленное значение) и при этом вызывается событие на изменение значения

При стиле колонки DataGridViewCheckBoxColumn и соответственно поле ячейки типа DataGridViewCheckBoxCell такое поведение сохраняется, но выглядит странно:
1) Мы выбираем ячейку
2) Начинаем кликать по галочке, но значение при этом не меняется хотя кажется что мы поменяли его... На самом же деле мы в режиме редактирования ячейки, и, как и в случае с текстовым полем, пока мы не подтвердим установленное значение (не выйдем из режима редактирования) значение не поменяется.
Нужно выполнить пункт 3:
3) Выходим из редактирования (нажатием enter или перемещением фокуса на другую ячейку) и вызывается событие на изменение значения ячейки

С такой проблемой не очевидного (хотя и верного) поведения сталкивалось довольно много народу, так что наплодилось несколько костылей решений (msdn, so) для того чтобы значение ячейки менялось сразу при клике на галочку чекбокса.

Я же смог написать немного более универсальное решение, которое работает не только на клик, хотя все же есть что еще там дополнить:
Код: (C++)
System::Void dgvCurrentCellDirtyStateChanged(System::Object^ sender, System::EventArgs^  e)
{
        auto dgv = dynamic_cast<System::Windows::Forms::DataGridView^>(sender);
        if (dgv == nullptr)
                return;
        if (dgv->CurrentCell->GetType() != System::Windows::Forms::DataGridViewCheckBoxCell::typeid)
                return;

        if (dgv->IsCurrentCellDirty)
                dgv->CommitEdit(DataGridViewDataErrorContexts::Commit);
}

данный обработчик нужно повесить на событие CurrentCellDirtyStateChanged вашего DataGridView
Код: (C++)
DataGridView1->CurrentCellDirtyStateChanged += gcnew System::EventHandler(dgvCurrentCellDirtyStateChanged);

Обращаю внимание на то что данный обработчик будет вызываться каждый раз когда будет происходить какое либо редактирование любой ячейки вашей таблицы. Так что производительность приложения может снизиться если у вас смешанная таблица из редактируемых чекбоксов, текстовых полей и т.п.
« Последнее редактирование: 12-03-2015 12:55 от oktonion » Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines