CheckBox not Updating when Source Changed - c#

I'm still very new to WPF/XAML so bear with me here...
I have a DataGrid that contains three columns: 2 DataGridTextColumns and a DataGridTemplateColumn, which contains a CheckBox. The DataGrid is bound to a collection that displays objects of type Field. The IsChecked property of the CheckBox is also bound to a property in a ViewModel.
What I'd like to be able to achieve is that when a Field i.e. a row in the DataGrid is clicked, the Field's corresponding CheckBox becomes checked or unchecked.
I have bound to the SelectedItem of the DataGrid and can retrieve the Field that's clicked. I then set the "IsChecked" property of the Field accordingly.
However, the check in the CheckBox does not appear (or disappear) seemingly until the row in the DataGrid is repainted. That is, if I scroll down so that the row disappears out of view and then scroll back up to it, the check is displayed in the CheckBox. I am raising an INotifyPropertyChanged event when the IsChecked property value is set.
Would anyone be able to suggest what might be going wrong here?
The code for the column containing the CheckBox is shown below.
Any ideas/suggestions/help would be greatly appreciated.
Many thanks.
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="5" />
</DataTemplate>
</DataGridTemplateColumn>
</DataGridTemplateColumn>

Try this:
First define new DataGridRow style to subscribe PreviewMouseButtonDownEvent:
<Style TargetType="{x:Type DataGridRow}">
<EventSetter Event="PreviewMouseLeftButtonDown"
HandledEventsToo="True"
Handler="PreviewDataGridRowClick"
></EventSetter>
</Style>
And eventhandler:
private void PreviewDataGridRowClick(object sender, MouseButtonEventArgs e)
{
var datagridRow = (DataGridRow) sender;
var underlyingVm = datagridRow.Item as YourVM;
underlyingVm.IsChecked = !underlyingVm.IsChecked;
e.Handled = true;
}

Related

WPF switching column visibility in DataGrid triggers unwanted event

I have a weird issue where changing data grid column visibility with a press of a button, it triggers a "Checked" event tied to a checkbox in that data grid column.
So here's my setup:
I have a label lblUpdateMode with a text either "single row" or "every row";
A datagrid with 10 columns, where initially 5 columns are visible and 5 are hidden;
Pressing a button btnChangeView flips visibility of each column;
In one of the data grid columns I have a CheckBoxColumn, with Checked/Unchecked events. If label text = "every row" pressing on a single checkbox updates every row.
However, if label = "every row" and I press on btnChangeView, it also triggers Checked event and updates checkboxes in every row.
Why is this happening and how can I avoid it?
Here's the code to the Checked event - nothing fancy or strange:
private void UpdateDataGridCheckBox(string colname, bool v)
{
if (lblUpdateMode.Content.ToString() == "Every Row")
{
foreach (DataRow dr in DataAccess.Instance.sourceFiles.Rows)
{
dr[colname] = v;
}
}
}
And here's the XAML for this column:
<DataGrid x:Name="dataGridFiles" Grid.Row="2" Margin="10" Visibility="Collapsed"
ItemsSource="{Binding Path=DataAccess.Instance.sourceFiles, Mode=TwoWay}">
<DataGrid.Columns>
<!--Import-->
<DataGridTemplateColumn Header="Import" Width="60" CanUserReorder="True" Visibility="Collapsed">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="checkBoxImport" HorizontalAlignment="Center" VerticalAlignment="Center"
IsChecked="{Binding Path=Import, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Checked="checkBoxImport_Checked"
Unchecked="checkBoxImport_Unchecked"></CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
Thanks
In your XAML, you bind the IsChecked property of your CheckBox to a property called Import.
<CheckBox x:Name="checkBoxImport" HorizontalAlignment="Center" VerticalAlignment="Center"
IsChecked="{Binding Path=Import, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Checked="checkBoxImport_Checked"
Unchecked="checkBoxImport_Unchecked"></CheckBox>
However, the binding Mode is set to TwoWay, which means,
If there's a change of value in the IsChecked property of the CheckBox in your XAML, that change will be reflected in your Import property in your code,
and,
If there's a change of value in the Import property in your code, that change will be reflected in the actual CheckBox in your XAML.
In other words, if the user checks the check box, Import value will be set to true. If user unchecks the check box, Import will be false. Conversely, if you change the value of Import to false at any point in your code, your GUI check box will be unchecked. If Import is set to true in code, GUI check box will be checked.
I'm assuming that in the Click even of the btnChangeView (which you haven't shown in your post), you change the value of Import.
So, instead of Mode=TwoWay, assuming that you want to do something when the user checks/unchecks the CheckBox, I think you want to set Mode=OneWayToSource.
Read this for a detailed explanation of binding modes in WPF.

How to bind CheckBox IsChecked to ListBox of CheckBoxes

I have a list of check boxes and a single check box that acts as CheckAll/UncheckAll for all items in the listbox.
How can I make the chkAll Check Box checked if all the items are checked in the listbox binding ?
I could create a property in the view model to achieve that. I would like to do it in the xaml code.
<ListBox Name="listBox" ItemsSource="{Binding mySource}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelectedProperty}">
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<CheckBox Name="chkAll" Content="CheckAll/UnCheckAll" IsChecked ={}/>
I think you will need to have a higher-level view model property that reflects this additional state. The state has three possible values too, so be sure to set IsThreeState to true, and bind it to a Nullable<bool>.
Then in this property's setter, you can update all the other checkbox properties.
For each item's IsSelectedProperty, you'll need to update the three-state property too.

WPF How to get current edited content in datagrid?

Given a data-grid bound to a CollectionViewSource who's source is an ObservableCollection, when first displayed the OC is instantiated to show a single row with nothing in it.
<DataGridTextColumn x:Name="observationNameColumn" Width="auto" Header="Observation Name" Binding="{Binding ObservationName}"/>
I want to enter text in any of the given fields to kick off a EF back end query based on user input. To do this I added a button like this to the same data-grid. A simple button with a click handler...
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button x:Name="XBTNSearch" Click="XBTNSearch_Click" Padding="5,0,5,0">Enter Search Criteria and Search</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
When the row is clicked with the edited value this is the type of code used.
private void XBTNSearch_Click(object sender, RoutedEventArgs e)
{
var context = ((Button)sender).DataContext;
Debugger.Break();
FindStuff();
}
When the break point is hit is shows an empty model of the observable collection type even though I did type something into one of the fields... I want that value so I can use EF to 'FindStuff'
How do I get the value in the row cell based on the Button's datacontext which should be that very row I edited the text?
The solution to this problem was this in the Button click event Hanlder as the first statement...
XDG.CommitEdit();
Where XDG is the Xaml Data Grid....

Can we have a grid inside the cell of the DataGrid in WPF?

I require to have a DataGrid having multiple rows and 3 columns. Now each cell of the DataGrid is to show some information (6 to 8 parameters) and a button. On click of this button a pop-up is to be shown.
Now for displaying the data inside the cell of the DataGrid, I need to align them properly and was thinking of using the Grid. How to achieve this.
Also how do I get to know at the click event of the button that which cell button was clicked ?
Kindly help.
You may add DataGridTemplateColumn(s) to your DataGrid, and then define usual data template for the column:
<DataGrid.Columns>
<DataGridTemplateColumn Header="Foo" Width="SizeToCells">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
...
<Button Command="{Binding SomeCommand}" />
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGrid.Columns>
Now about the click event. Bind your grid with items source. Each item in that source must be a view model with any ICommand property. Bind this property to the button's command in cell template, and you will get it.

GridView Row Does not get select or Affected When Checkbox checked on Grid

I am using WPF Application Form with Telerik Gridview using C#.
In that Gridview i inserted checkboxes using Data template.
Its created but when i click or check the checkbox the current row is not getting selected.
How can i solve this problem?
Please anyone tell me the solution of this problem.
My xaml code for creating checkbox in grid is:
<telerik:GridViewDataColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<CheckBox Name="CheckBox" IsChecked="{Binding IsSelected,UpdateSourceTrigger=PropertyChanged}" Click="CheckBox_Click" />
</StackPanel>
</DataTemplate>
</telerik:GridViewDataColumn.CellTemplate>
In that checkbox i have created click event.
And also i want to know the current row number of the CheckBox Placed row in the gridview in checkbox click event. Give me some suggestion for this.
Here My CheckBox Click event Code:
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox selectedCheckbox = (CheckBox)sender;
//this.selectedCasePackRadGrid -- This is my gridview
// Here I want to get the selected row number
}
Thanks in Advance.
First of all, I don't see you actually setting the row as Selected anywhere.
Your binding currently is setting a property in your DataContext called IsSelected. If this property actually exists, you can bind it to GridViewRow.IsSelected in a style
<Style TargetType="{x:Type telerik:GridViewRow}">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
If it doesn't exist in your data object, you need to use a RelativeSource binding to find the GridViewRow and bind to it's IsSelected property
Checked="{Binding RelativeSource={RelativeSource AncestorType={x:Type telerik:GridViewRow}}, Path=IsSelected}"
As for finding the row number, there is no RowIndex property I know of that you can use to find the row number. One alternative is to get the GridView's ItemsSource and call IndexOf(dataobject), however that does break the separation of MVVM layers
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox checkBox = (CheckBox)sender;
var dataItem = checkBox.DataContext as MyDataItem;
var parentDataObject = myGridView.ItemsSource as SomeDataObject;
if (dataItem == null || parentDataObject == null)
return;
var index = parentDataObject.SomeCollection.IndexOf(dataItem);
// Do something with index
}
There are also other alternatives such as setting AlternationCount to something higher than the the number of rows, and accessing GridViewRow.AlternationIndex, although I don't know if that will work with Telerik's GridView
But perhaps the best thing you could do is evaluate what you actually need the index for, and see if you can use some other alternative to accomplish what you want. For example, if you want to pass the index of the selected row to a button command, it would be better to just pass the SelectedItem as the CommandParameter.

Categories