Name checkboxes in ListView - c#

I have a ListView control that contains one column with checkboxes only. Is it possible to give those checkboxes some names (indexes - like 1, 2, 3...)?
I need it because I want to identify a concrete checkbox in ToggleButton_OnCheckedUnchecked event in some way.
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Value, Mode=OneWay}" IsThreeState="False"
Checked="ToggleButton_OnCheckedUnchecked"
Unchecked="ToggleButton_OnCheckedUnchecked"/>
</DataTemplate>
</GridViewColumn.CellTemplate>

Don't do it that way. Instead, have each line in your ListView have an IsChecked property, and change the IsChecked Binding to TwoWay. That way, you don't need to use the Checked and UnChecked events at all.
public class LineViewModel
{
public bool IsChecked
{
get { return _isChecked;
}
set
{
// do something here
}
}
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" IsThreeState="False"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
For best results, implement INotifyPropertyChanged too.

Probably dynamic binding some names can be done through the Binding, like that:
<CheckBox Name="{Binding IdCheckBox}" ... />
Quote from the MSDN:
Data binding a Name is technically possible, but is an extremely uncommon scenario because a data-bound Name cannot serve the main intended purpose of the property: to provide an identifier connection point for code-behind.
In short, the Binding Name property for control is impossible and undesirable. But you can use the attached dependency property, like this:
<CheckBox local:GiveName.Name="{Binding Template_Name1}" ... />
In any case, this is not the solution to your problems.

Related

Datacontext not available in DataGridTemplateColumn

I have the following grid:
<DataGrid
x:Name="CandiesDataGrid"
ItemsSource="{Binding Candies}"
SelectedItem="{Binding SelectedCandy}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding CandySelectedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<DataGrid.Columns>
<DataGridTextColumn KeyboardNavigation.IsTabStop="False" IsReadOnly="True" Width="100" Header="{l:LocText Candy_Prop1}" Binding="{Binding CandyInfo.Name}"/>
<DataGridTemplateColumn >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="IsConfirmed" Grid.Column="0"
Style="{StaticResource CandyCheckBox}"
IsChecked="{Binding IsConfirmed, Mode=TwoWay}"
Margin="-75 0 0 0"
Command="{Binding IsConfirmedCommand}">
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
My property uses the OnPropertyChanged. Not only it does not change the value of IsConfirmed but also does not executes the ICommand IsConfirmedCommand.
I searched on the internet and it seems DataGridTemplateColumn loses the ItemSource of the datagrid.
I did try to put RelativeSource in after the mode=TwoWay on my checkbox but it does not work.
Is there any way to have access to the ItemSource in my TemplateColumn?
EDIT:
//Properties
public ObservableCollection<Candy> Candies{ get; } = new ObservableCollection<Candy>();
public Candy SelectedCandy { get { return _selectedCandy; } set { SetProperty(ref _selectedCandy, value); } } //SetProperty acts as OnPropertyChanged
private Candy _selectedCandy;
//Constructor:
public CandyClass()
{
IsConfirmedCommand = new DelegateCommand(IsConfirmedCommand_Execute);
}
//Method
private void IsConfirmedCommand_Execute()
{
//Doing something
}
Inside your CellTemplate, the DataContext is the DataGrid row, whatever that may be (Candy in this case). So by default, that Candy instance will be the Source property of any Binding in that DataTemplate. That's where the binding will look for the property named in the Path (IsConfirmed and IsConfirmedCommand, in this case).
That's what you want: You've got more than one row in the grid, and the row is what you care about in a cell, usually. That or the field: But very often a cell template will want to look at more than one field, so they give you the whole row.
But in this case, you want to go back up and grab something off the parent viewmodel. Viewmodels have no natural parent/child hierarchy, though you could give them one if you wanted: Candy could have a Parent property that had reference to the viewmodel that owns the Candies collection. If you did, you could bind like this:
Command="{Binding Parent.IsConfirmed}"
But that's not common practice. I don't know if it's a particularly great idea or not.
One reason we don't need to do that is we can tell the binding to use a different source instead. UI elements do have a natural parent/child hierarchy, and bindings can navigate it. If you’re doing things right, your parent viewmodel will be the DataContext of something up there somewhere.
{Binding Path=DataContext.IsConfirmed,
RelativeSource={RelativeSource AncestorType=DataGrid}}
"Walk the UI tree upwards until you find a DataGrid. That's your source. Now, once you have a source, find the source object's DataContext property, if any. If it's got a DataContext, take the value of DataContext and look on that object for some property called IsConfirmed."
DataGrid has a DataContext property. Since your binding to Candies worked, we know that DataContext must be your class that has a Candies property. You assure me that class has IsConfirmed as well.
Hence:
<DataTemplate>
<CheckBox
Style="{StaticResource CandyCheckBox}"
IsChecked="{Binding DataContext.IsConfirmed,
RelativeSource={RelativeSource AncestorType=DataGrid}}"
Margin="-75 0 0 0"
Command="{Binding DataContext.IsConfirmedCommand,
RelativeSource={RelativeSource AncestorType=DataGrid}}"
/>
</DataTemplate>

Event handler can't be found in MVVM

I have a silverlight application. One of StackPanel will display the table. The first column is a check box.
<telerik:RadGridView.Columns>
<telerik:GridViewColumn Width="80" Header="Complete" HeaderTextAlignment="Center" TextAlignment="Center">
<telerik:GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Center" IsChecked="{Binding Something, Converter={StaticResource ShortToBooleanConverter}}" Checked="Complete_Checked"></CheckBox>
</DataTemplate>
</telerik:GridViewColumn.CellTemplate>
</telerik:GridViewColumn>
What I want is that once I click the box, a message box with Y/N pops up. I do have a Complete_Checked method in MVVM. But I get the error
Event handler 'Complete_Checked` not found on class.....
You can't use click event handlers with MVVM you need to use CommandBinding or DataBinding depending on what you're doing.
With your example you'll use data binding. You want to bind to the checkbox dependency property called IsChecked. You'll also want to use the Mode of TwoWay. This will allow the UI to update the bound property when it changes.
<CheckBox IsChecked="{Binding CheckBoxIsChecked, Mode=TwoWay}">
Then in your object model not viewmodel
private bool _checkBoxIsChecked;
public bool CheckBoxIsChecked
{
get{ return _checkBoxIsChecked;}
set{_checkBoxIsChecked = value; OnPropertyChanged("CheckBoxIsChecked"); }
}

CheckBox binding Mode works one way

I have a Datagrid in whitch I have a column who has a CheckBox inside (I know that DataGridCheckBoxColumn exist but I don't like the behavior (clicking once to select and a second time to alter the value)).
This checkbox is binded this way
<DataGridTemplateColumn x:Name="checkColumn" Header="Check">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding load, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The TwoWay mode is supposed to be default but I added it anyway since it seems to work as if it was read only.
And the property load is simply
private bool _load;
public bool load
{
get { return _load; }
set { _load = value;}
}
But in the end the binding doesn't work properly. For each item I have the correct value displayed by default (checked/not checked), but if I check/uncheck the checkboxes, nothing changes on the data (but the checkboxes do change visually, but the setter of the item is never called).
I suspect that the problem is not a big one, since the default values are read, the binding is not completely wrong, but I can't find out why the setter is never called.
Have you tried UpdateSourceTrigger=PropertyChanged?
<CheckBox IsChecked="{Binding load, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

How to enable all checkboxes when items have binding to a ObserverableCollection<MyClass>

I have a listview with multiple checkboxes. The item source in my listview is a ObservableCollection of a class that stores some default data I need when the item is selected. My checkboxes have properties in the class, this part works good.
Question: How can I provide a shortcut to enable all the checkboxes for times they are all needed from one checkbox as seen below. The checkboxes all having bindings to the class in the ObservableCollection so I'm not sure how I can accomplish this. I can't just set them all in the class instance because it's just a model, does not raise events and I'm not sure if I can/should do that with MVVM. My viewmodel does not know about them outside of the MyItem Source property.
code example:
<ListView ItemsSource="{Binding MyItems, Mode=TwoWay}" SelectedItem="{Binding SelectedMyItem, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<!-- When this one is checked I want to enable the rest, shortcut to enable everything -->
<CheckBox Content="Enable All checkboxes" IsChecked="{Binding MyCheckBoxAllIsChecked, Mode=TwoWay}" />
<CheckBox Content="Check Box One" IsChecked="{Binding MyCheckBoxOneIsChecked, Mode=TwoWay}" />
<CheckBox Content="Check Box Two" IsChecked="{Binding MyCheckBoxTwoIsChecked, Mode=TwoWay}" />
<CheckBox Content="Check Box Three" IsChecked="{Binding MyCheckBoxThreeIsChecked, Mode=TwoWay}" />
<CheckBox Content="Check Box Four" IsChecked="{Binding MyCheckBoxFourIsChecked, Mode=TwoWay}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
public class MyItem
{
public bool MyCheckBoxAllIsChecked { get; set; }
public bool MyCheckBoxOneIsChecked { get; set; }
public bool MyCheckBoxTwoIsChecked { get; set; }
public bool MyCheckBoxThreeIsChecked { get; set; }
public bool MyCheckBoxFourIsChecked { get; set; }
}
If having "check all" functionality does make sense from model point of view, then you can code it in the setter of MyCheckBoxAllIsChecked (though you will need INotifyPropertyChanged for it to work correctly in UI). But I think a method instead of property will make more sense in this case.
If you added MyCheckBoxAllIsChecked just for UI, then it's better to remove it altogether and instead create a command or method in ViewModel which will set all the bool properties of the Model. You can call in via Command binding on CheckBox using its value as a parameter or just use standard Checked and Unchecked event handlers to call VM (it's a UI interaction, so code behind is ok to use here).

Getting Checked property from CheckBox when Command is called in WPF

I have a grid of CheckBoxes in a WPF C# project. Each CheckBox's Command property is bound to a CheckBoxChangedCommand in my WView.xaml file, like so:
<CheckBox Grid.Row="0" IsChecked="true" x:Name ="CheckBox0"
Command="{Binding CheckBoxChangedCommand}" />
<CheckBox Grid.Row="1" IsChecked="true" x:Name="CheckBox1"
Command="{Binding CheckBoxChangedCommand}" />
Each time one of the CheckBoxes is either checked or unchecked, I call CheckBoxChanged. How would I go about displaying a pop-up window showing either 1. the row number in the grid of the CheckBox and the name of the CheckBox ("CheckBox0", for example) and 2. The Checked value (true/false) for the checkbox?
My CheckBoxChangedCommand, in WViewModel.cs file, looks like this:
public ICommand CheckBoxChangedCommand
{
get
{
return new RelayCommand(param =>
{
MessageBox.Show("CheckBoxChanged!");
});
}
}
How can I access the IsChecked property and the row number of the CheckBox that triggered CheckBoxChanged from withinCheckBoxChanged? How can I pass the data from my View to my ViewModel?
You definitely need to do more with binding here.
First of all, you should probably be binding the IsChecked property of your Checkboxes to a property on your viewmodel.
Second, based on your comment about needing to know the row number of the checkbox that was checked, I'd say you probably need to be generating the "row" including the CheckBox via databinding, so that you can then pass the object that represents the row as the CommandParameter to your CheckBoxChangedCommand.
So something like:
<ListBox ItemsSource="{Binding MyItems}" />
and then in your resources:
<DataTemplate DataType="{x:Type local:MyItemType}">
<CheckBox IsChecked="{Binding IsChecked}"
Command="{Binding CheckChangedCommand}"
CommandParameter="{Binding}" />
</DataTemplate>
Note: Your CheckChangedCommand is probably on the main ViewModel, not the item-level ViewModel, so you probably need to do some other type of lookup to make it find it - this example is just for simplicity

Categories

Resources