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
Related
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"); }
}
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}" />
I have this element in my xaml (DevExpress item):
<dxe:ComboBoxEdit IsTextEditable="False" EditValue="{Binding IDTIPOCONN}"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window},Path=DataContext.ttc}" />
All the binding are correct, and when I change the value, I trigger some event from my ViewModel.
My problem is the update of the value is executed only when I leave the focus of my comboBox. I need, instead, to execute my action when the value is changed, before leaving its foucs.
How can I do it? I need this because selecting one or another from the list, I show to the user some hidden elements.
Try for Binding set UpdateSourceTrigger=PropertyChanged:
<dxe:ComboBoxEdit IsTextEditable="False"
EditValue="{Binding Path=IDTIPOCONN, UpdateSourceTrigger=PropertyChanged}" ... />
In this case, most likely the default value of UpdateSourceTrigger is LostFocus.
I have a Grid on a wpf window which I want to add the capability that user can delete some of the items by clicking on a delete button. The application uses Calibrun Micro to bind view to ViewModel.
My question?
1- Is it a good idea to use a button to delete an item from a grid in WPF?
2- How can I bind a button to a method on VM and in the methd get a pointer to the item that should be deleted?
Edit1
I added the buttons in this way to datagrid:
<DataGridTemplateColumn Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Delete" cal:Message.Attach="DeleteFromList($dataContext)" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
and c# code follow:
public void DeleteFromList(object tmp)
{
}
But the buttons on datagrid are disabled and clicking on them doesn't fire DeleteFromList method (I checked using debugger).
Why they are disabled? How can I make them enabled?
This depends on how your button is placed - is there a single 'delete' button or have you added a button per row in the grid (are we talking DataGrid or just Grid?)
Assuming you are talking about DataGrid, you can easily just add an action message command to the button and pass through the item which is being deleted to the message handler on the VM
e.g. in the VM
public class MyViewModel
{
public DataItemCollectionTypeName ItemCollection { get; set; }
public void DeleteItem(DataItemTypeName item)
{
ItemCollection.Remove(item);
}
}
Assuming ItemCollection is bound to the grid, the button XAML may look like this:
<Button cal:Message.Attach="[Click] = [DeleteItem($datacontext)]" />
You may also need to set Action.TargetWithoutContext (it should be bound to the VM) if this is a templated row, as otherwise CM will not be able to locate the VM to invoke the action message on
If you have a single button that isn't contained within the grid you can always target the grids SelectedItem in the action message
<DataGrid x:Name="SomeDataGrid"></DataGrid>
<Button cal:Message.Attach="[Click] = [DeleteItem(SomeDataGrid.SelectedItem)]" />
It may be (and probably is) the default property that CM will look at so you may not need to specify the property name unless you have modified default conventions
<DataGrid x:Name="SomeDataGrid"></DataGrid>
<Button cal:Message.Attach="[Click] = [DeleteItem(SomeDataGrid)]" />
Edit
To clarify: In order for CM to find a VM to call the DeleteItem method it uses the DataContext of the current item. In the case of an ItemsControl derived control, the datacontext for each item points to the item being bound, not the ViewModel.
In order to give CM a hint as to which object it should try to resolve the DeleteItem method on, you can use the Action.TargetWithoutContext attached property, which applies a target object for action messages without changing the DataContext of the bound row/item
You can use element name syntax to point to the correct place:
In this example I've used a grid as the root element and named it LayoutRoot, then I've pointed the action message target to LayoutRoot.DataContext (which will be the ViewModel) using ElementName syntax. You can use any method (AncestorType or whatever)
<Grid x:Name="LayoutRoot">
<DataGridTemplateColumn Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Delete" cal:Message.Attach="DeleteFromList($dataContext)" cal:Action.TargetWithoutContext="{Binding DataContext, ElementName=LayoutRoot}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</Grid>
That should then work!
You could do something like this...
<Button cal:Message.Attach="[Event MouseEnter] = [Action Save($this)]">
Check the docs as they will explain what you need to do and should answer your question: link
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.