WPF Как проверить выбранный CheckBox?
Есть таблица, в столбце Статус заявки находятся CheckkBox'ы. Вывод данных в эту таблицу идет из БД.
<ListView x:Name="userList" Margin="10,73,10,58">
<ListView.View>
<GridView>
<GridViewColumn Header="№" Width="30" DisplayMemberBinding="{Binding numReq}"/>
<GridViewColumn Header="Название" Width="250" DisplayMemberBinding="{Binding shortDesc}"/>
<GridViewColumn Header="Описание" Width="200" DisplayMemberBinding="{Binding longDesc}"/>
<GridViewColumn Header="ФИО" Width="400" DisplayMemberBinding="{Binding fioUser}"/>
<GridViewColumn Header="Статус заявки" Width="400">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding statusReq}" IsEnabled="{Binding enableCheck}" Click="checkBox" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Я пытался заново перебрать всю таблицу, чтобы определить номер строки (id), на которой CheckBox стал активным. Также поставил фильтр(первая конструкция if) на те CheckBox'ы, которые уже выведены из БД, то есть true и являются неактивными, так как у пользователя нет возможности изменять уже включенные CheckBox'ы.
private void checkBox(object sender, RoutedEventArgs e)
{
DataTable req_out = specWindow.Select("SELECT * FROM [dbo].[Request]");
for (int j = 0; j < req_out.Rows.Count; j++)
{ // перебираем данные
active_table = ("" + req_out.Rows[j][4]);
if(active_table=="0")
{
if (statusReq)
{
MessageBox.Show("Отмечен столбец № " + j);
}
}
}
Реализация класса коллекции
public class monitorReq
{
public string numReq { get; set; }
public string fioUser { get; set; }
public string department { get; set; }
public string cabinet { get; set; }
public string numPc { get; set; }
public string shortDesc { get; set; }
public string longDesc { get; set; }
public bool statusReq { get; set; }
public bool enableCheck { get; set; }
public monitorReq(string _numReq, string _fioUser, string _department, string _cabinet, string _numPc, string _shortDesc, string _longDesc, bool _statusReq, bool _enableCheck)
{
this.numReq = _numReq;
this.fioUser = _fioUser;
this.department = _department;
this.cabinet = _cabinet;
this.numPc = _numPc;
this.shortDesc = _shortDesc;
this.longDesc = _longDesc;
this.statusReq = _statusReq;
this.enableCheck = _enableCheck;
}
}
Подскажите пожалуйста, как определить строку(по сути id), в которой пользователь только что отметил checkbox, чтобы можно было записать это в переменную и отправить в БД?
Вот скрин таблицы
Ответы (1 шт):
Вы боретесь с контролами, и при этом не используете встроенные возможности WPF. Обратите внимание на шаблон программирования MVVM.
Я покажу короткий пример на базе этого шаблона.
Потребуется вспомогательный класс для реализации INotifyPropertyChanged интерфейса. Суть его заключается в том, чтобы уведомлять UI о любых изменениях просто изменяя данные.
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Затем потребуется класс с данными, и сразу сделаю его так, чтобы он уведомлял интерфейс об изменениях. Другими словами, если вы внесете изменения в DataGrid, они сразу поменяются в данных, и наоборот. Вам не придется больше взаимодействовать с DataGrid, а только с данными.
public class UserItem : NotifyPropertyChanged
{
private int _numReq;
private string _shortDesc;
private string _longDesc;
private string _fioUser;
private bool _statusReq;
public int NumReq
{
get => _numReq;
set
{
_numReq = value;
OnPropertyChanged(); // уведомляет UI об изменении
}
}
public string ShortDesc
{
get => _shortDesc;
set
{
_shortDesc = value;
OnPropertyChanged();
}
}
public string LongDesc
{
get => _longDesc;
set
{
_longDesc = value;
OnPropertyChanged();
}
}
public string FioUser
{
get => _fioUser;
set
{
_fioUser = value;
OnPropertyChanged();
}
}
public bool StatusReq
{
get => _statusReq;
set
{
// сюда попадаем как только изменен чекбокс
// при этом не важно, програмно или из UI
// можно прямо отсюда кинуть запрос в БД, все нужные данные в прямой видимости
_statusReq = value;
OnPropertyChanged();
}
}
}
Затем, основной класс для MainWindow, который будет содержать все свойства, к которыйм в свою очередь будут привязаны зависимые свойства контролов интерфейса в помощью Binding.
public class MainViewModel : NotifyPropertyChanged
{
private ObservableCollection<UserItem> _userList;
public ObservableCollection<UserItem> UserList // коллекция, к которой привязана DataGrid
{
get => _userList;
set
{
_userList = value;
OnPropertyChanged();
}
}
public MainViewModel()
{
UserList = new ObservableCollection<UserItem>();
}
}
А чтобы интерфейс узнал, в каком классе все свойства, куда будут привязываться все биндинги, нужно задать DataContext у окна, два самых простых способа (выберите любой или придумайте свой):
1) в конструкторе окна
public MainWindow()
{
InitializeComponent();
MainViewModel vm = new MainViewModel();
DataContext = vm;
}
2) разметке
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
Ну и сама разметка таблицы
<ListView ItemsSource="{Binding UserList}" Margin="10,73,10,58">
<ListView.View>
<GridView>
<GridViewColumn Header="№" Width="30" DisplayMemberBinding="{Binding NumReq}"/>
<GridViewColumn Header="Название" Width="250" DisplayMemberBinding="{Binding ShortDesc}"/>
<GridViewColumn Header="Описание" Width="*" DisplayMemberBinding="{Binding LongDesc}"/>
<GridViewColumn Header="ФИО" Width="400" DisplayMemberBinding="{Binding FioUser}"/>
<GridViewColumn Header="Статус заявки" Width="400">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding StatusReq, UpdateSourceTrigger=PropertyChanged}"/>
<!-- UpdateSourceTrigger перезаписывает свойство сразу как юзер на него нажмет -->
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Работать с ObservableCollection можно точно так же как с уже знакомым вам List. Она отличается от List в основном тем, что внутри нее вызывается событие CollectionChanged при добавлении или удалнии элементов коллекции, а на него автоматически подписывается DataGrid.
UserList.Add(new UserItem() { NumReq = 1, FioUser = "Семён Семёнович", ShortDesc = "Монитор", LongDesc = "Выключился", StatusReq = false });
Про загрузку данных, просто грузите их не в DataGrid, а в коллекцию.
Если решитесь попробовать MVVM, есть еще команды, к ним можно биндить кнопки, меню и прочие контролы, в которых не меняются зависимые свойства, а просто надо что-то сделать, когда что-то нажато. Я не буду добавлять примеры использования команд в этот ответ, но их можно найти в других моих ответах StackOverflow, у меня в профиле.
Примеры
private ObservableCollection<MonitorReq> _monitorReqList = new ObservableCollection<MonitorReq>();
public ObservableCollection<MonitorReq> MonitorReqList // я бы так назвал
{
get => _monitorReqList;
set
{
_monitorReqList = value;
OnPropertyChanged();
}
}
public class MonitorReq : NotifyPropertyChanged
{
// реализация класса данных
}