How to Bind a Command to a CheckBox - wpf

I'm trying to bind the checkbox checkchange event to a command - MVVM
Why doesn't this work? or do anything while the same works on button?
<CheckBox x:Name="radRefresh" IsChecked="{BindingREADY, Mode=TwoWay}" Command="{Binding Refresh_Command}" Content=" Refresh " Margin="10,25,0,0" />
<Button Command="{Binding Refresh_Command}" />
thanks

You don't need to bind it to an event.
All you need to do is bind IsChecked to a boolean dependency property, and do whatever logic you'd like on its setter.
Like this -
<CheckBox x:Name="radRefresh" IsChecked="{Binding IsChecked, Mode=TwoWay}" Content=" Refresh " Margin="10,25,0,0" />
This xaml should bind you to this property on the VM
public bool IsChecked
{
get
{
return isChecked;
}
set
{
isChecked = value;
NotifyPropertChanged("IsChecked");
//Add any logic you'd like here
}
}

This will work...
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<cmd:EventToCommand Command="{Binding Path=YourCommand,Mode=OneWay}" CommandParameter="{Binding IsChecked, ElementName=YourCheckBox}"></cmd:EventToCommand>
</i:EventTrigger>
</i:Interaction.Triggers>
where i is
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Add namespace for cmd
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
This is one of the preferred ways for MVVM if you are utilizing the MVVMLight Framework.

This is a simple situation:
Bind the CheckBox.IsChecked to a boolean value in your ViewModel.
In your viewmodel, subscribe to the property changed event and watch for the boolean value to change.
Done.

That would be because only a handful of controls (Button, MenuItem of the top of my head) implement the functionality to directly bind commands.
If you need to bind to a control, I would recommend creating a UserControl that executes the ViewModel's command when the CheckBox's property IsChecked is changed in codebehind.

Related

How can I disable combobox before button clicked in WPF MVVM

In my project I have a "Generate Reports" Button and a "Select Location" ComboBox. I want the user to be unable to choose a location before clicking
"Generate Report" Button.
the xaml containing the combobox and the button:
<Button Content="Generate Reports" Command="{Binding GenerateReportsCommand}" Height="36" Margin="4" />
<ComboBox Grid.Column="2" ItemsSource="{Binding Locations}" SelectedItem="{Binding SelectedLocation}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding LocationFilterCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
What can I do in the ViewModel or UI? Thank you for all your helps.
I'm going to assume you know how to use data binding (based on your post you already use it).
Create a new Boolean in your ViewModel and bind the ComboBox's IsEnabled to it. (Something like IsEnabled="{Binding YOURBOOLEAN}")
Update that Boolean from your GenerateReportsCommand after the user successfully generated the report. If you set that variable to true, the ComboBox's IsEnabled will also be set to true.
You should have an additional property inside the ViewModel.
private bool _areReportsGenerated = false;
public bool AreReportsGenerated
{
get => _areReportsGenerated;
set
{
_areReportsGenerated = value;
OnPropertyChanged(); // you method's implementation of INotifyPropertyChanged
}
}
If you don't have an implementation of INotifyPropertyChanged you can take a look at Microsoft one.
Inside GenerateReportsCommand you should set AreReportsGenerated to true.
In the xaml then you only have to bind the newly created property to the IsEnabled property of the ComboBox
<ComboBox Grid.Column="2" ItemsSource="{Binding Locations}" SelectedItem="{Binding SelectedLocation}" IsEnabled="{Binding AreReportsGenerated}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding LocationFilterCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
It should work.
I hope I was helpful.

WPF Set Visibility on DataTemplate UI Element from MVVM View Model

I have a control that is set up as a DataTemplate:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<BooleanToVisibilityConverter x:Key="BoolToVis" />
<DataTemplate x:Key="KEYBOARD_EN">
<StackPanel>
<Button Visibility="{Binding Path=RegisterButtonVisible}" Style="{StaticResource RegisterKeyboardButtonStyle}">Register</Button>
</StackPanel>
</DataTemplate>
In this DataTemplate there is a control on which I wish to set the Visibility from various view models:
<Button Visibility="{Binding Path=RegisterButtonVisible}" Style="{StaticResource ...} > Register </Button>
I do routed events with my control, so I tried to set up something similar, but no matter what I try, the RegisterButtonVisible property does not get picked up:
public partial class MainKeyboard : UserControl
{
public static DependencyProperty RegisterButtonVisibleProperty;
public Visibility RegisterButtonVisible
{
get { return (Visibility)GetValue(RegisterButtonVisibleProperty); }
set { SetValue(RegisterButtonVisibleProperty, value); }
}
static MainKeyboard()
{
RegisterButtonVisibleProperty = DependencyProperty.Register("RegisterButtonVisible", typeof (Visibility),
typeof (MainKeyboard));
}
}
In my ViewModel I do this:
public Visibility RegisterButtonVisible // get, set, raisepropchange, etc
My DataTemplate with the button in it is wrapped in a userControl:
<UserControl x:Class="Bleh.Assets.MainKeyboard"
x:Name="TheControl"
Unloaded="UserControl_Unloaded">
<Viewbox>
<Grid>
<ContentControl Name="ctrlContent" Button.Click="Grid_Click" />
</Grid>
</Viewbox>
and is used in my views like this:
<assets:MainKeyboard
RegisterButtonVisible="Collapsed"
Loaded="MainKeyboard_Loaded">
<b:Interaction.Triggers>
<b:EventTrigger EventName="Register">
<b:InvokeCommandAction Command="{Binding ConfirmEmailAddressCommand}"/>
</b:EventTrigger>
<b:EventTrigger EventName="Enter">
<b:InvokeCommandAction Command="{Binding EnterKeyCommand}"/>
</b:EventTrigger>
</b:Interaction.Triggers>
</assets:MainKeyboard>
Please note this attribute:
RegisterButtonVisible="Collapsed"
This is my dependency property. It shows up in intelliesense, so the CLR has registered it correctly, but it does NOT pick up the property assignment (Collapsed is ignored).
This makes me feel like it is very close, but I do remember someone telling me I can not do this, thus the EventTriggers (this is a common issue with datatemplates and MVVM apparently).
So one option is to use something in the Interaction namespace, like I do my event triggers ( I just need to fire a "Visibility" trigger on this button somehow, at least I figure).
What is the right ANY way to do this in MVVM?
Fixing your code
In order to make your existing code work, you need to tell need to tell WPF what object RegisterButtonVisible should be read from. If it's a user control, give the UserControl a name and then reference that element via ElementName, like so:
<UserControl ... lots of stuff here
x:Name="TheControl"
>
In your button binding:
<Button Visibility="{Binding ElementName=TheControl, Path=RegisterButtonVisible}" Style="{StaticResource RegisterKeyboardButtonStyle}">Register</Button>
Of course, if you can't do that because the button and the usercontrol are in different files, you can still use an ancestor binding:
<Button Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type assets:MainKeyboard}},
Path=RegisterButtonVisible}"
Style="{StaticResource RegisterKeyboardButtonStyle}">Register</Button>
which, for each button, will walk up to find the closest instance of assets:MainKeyboard and then bind to the RegisterButtonVisible property.
Using MVVM
If you want to achieve the same using MVVM (instead of on a control), you need to use a converter to convert a boolean to a visibility property, like so:
<Button Visibility="{Binding IsRegistrationAllowed, Converter={StaticResource BoolToVis}}" Style="{StaticResource RegisterKeyboardButtonStyle}">Register</Button>
Of course, that assumes that your DataContext is set up correctly and pointing at your ViewModel.

Hook up the key down in TextBox (MVVM)

Have a little problem with hooking up the keydown event without codebehind!
So, we have the combobox
<ComboBox Height="20" Width="auto"
ItemsSource="{Binding AlignComboItems}"
SelectedValue="{Binding SelectedComboItem, Mode=TwoWay}"
SelectedValuePath="Key" DisplayMemberPath="Value"
SelectedItem="{Binding SelectedItem}"
x:Name="cmbBoxAlign">
</ComboBox>
and some TextBox.
<TextBox Text={Binding SomeSource}></TextBox>
How to catch the keydown event on the TextBox for selecting the (for example) the last element in ComboBox? I cant use the TextBox DataSource property changing, because need hook the user input up.
If you don't mind installing the Expression Blend SDK you should be able to do this in your textbox
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<i:InvokeCommandAction Command="{Binding Path=TheCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
After adding a reference to System.Windows.Interactivity and the following namespace in your xaml
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Link to the Expression SDK for 4.0
http://www.microsoft.com/en-us/download/details.aspx?id=10801
If you want to have code fire in your view model every time there is a key down in the text box you need to change the binding slightly:
<TextBox Text="{Binding SomeSource, UpdateSourceTrigger=PropertyChanged}"
Then in the view model the setter will be called:
private string _someSource;
public string SomeSource{
get { return _someSource; }
set {
//this will fire on key down
_someSource= value;
//based off the value you can set SelectedComboItem accordingly
OnPropertyChanged( "SomeSource" );
}
}
Also, make sure you have INotifyPropertyChanged set up on your view model.

Handling Mouse events in Viewmodel in WPF MVVM project

I am using System.Windows.Interactivity.dll and Microsoft.Expression.Interaction.dll to do event handling in Viewmodel in my MVVM WPF project.
below is the code inside my Xaml:
<ItemsControl ItemsSource="{Binding Path= HeaderList}" Grid.Row="0" Grid.Column="0" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" Width="100" HorizontalAlignment="Left" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<ie:CallMethodAction MethodName="PrevMouseDownEventHandler" TargetObject="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
for this I added namespaces in the same Xaml.
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ie="http://schemas.microsoft.com/expression/2010/interactions"
and in my viewmodel I have created a method having PrevMouseDownEventHandler name which is same as that of I mentioned as CallMethod inside EventTigger in the Xaml.
On running my application when I presses mouse button on TextBlock event is generated and look for PrevMouseDownEventHandler method and leave me into following exception:
Could not find method named 'PrevMouseDownEventHandler' on object of type 'string' that matches the expected signature.
this method is as below in my ViewModel.
public void PrevMouseMoveEventHandler(object sender, MouseButtonEventArgs e)
{
// Some implementation here;
}
I don't have any idea where I am going wrong.
Except this all the functionalities inside Viewmodel is working fine for me.
what would be possible solution for this?
CallMethodAction is a delegate with no parameters and no return value. So the "handler" (really an action trigger) would have to look like this:
public void PrevMouseMoveEventHandler()
{
// Some implementation here;
}
Also, you'll need to bind to the View Model (your current binding points to the current item in the ItemsControl). You could do this using RelativeSource binding:
<ie:CallMethodAction MethodName="PrevMouseDownEventHandler"
TargetObject="{Binding Path=DataContext,RelativeSource={RelativeSource AncestorType=ItemsControl}" />
It is looking for the method on the String object you have bound your Text property to.
Basically your data context has changed from the view model to a property of the View Model.

Show calender on TextBox.GotFocus() event in MVVM

I have an application which is having TextBox. Upon getting the focus, I need to show the Calendar as Popup.
My question is how to show subscribe the GotFocus event and show the calendar through view model?
It is fairly acceptable to write code-behind for view-specific tasks like this one, however if you insist to have clean code-behind files , do the following
you will need MvvmLight.Extras.WPF4.dll and System.Windows.Interactivity.dll, the second DLL comes mainly with blend , google the first and at any case you can find them both on the MVVMLight package.
reference them as follows:
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
see your textBox
<TextBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<cmd:EventToCommand Command="{Binding showCalendar, Mode=OneWay}" MustToggleIsEnabledValue="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
on your view model you should have a property that is bound to your Calendar Visibility property , change it to Visible inside the method invoked by the command.
You really don't need to go to the ViewModel for this - it can be done very simply in XAML. Use a BooleanToVisibilityConverter on a binding that is attached to the TextBox's IsFocused property.
<TextBox x:Name="_textBox" Text="{Binding Text}" />
<myNameSpace:Calendar Visibility="{Binding ElementName=_textBox, Path=IsFocused, Converter={x:Static _boolToVisibilityConverter}, Mode=OneWay}" />

Resources