How can I disable combobox before button clicked in WPF MVVM - wpf

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.

Related

How to pass textbox KeyEventArgs and textbox value in command wpf

I am struggling with a thing like i have a textbox
<TextBox Name="FilterInputText" Visibility="{Binding VisibiltyAttr}" Width="500" Height="30" Text="{Binding InputText}" HorizontalAlignment="Left" Margin="5">
<TextBox.InputBindings>
<KeyBinding Command="{Binding EnterCommand}" Key="Enter" />
<KeyBinding Command="{Binding DownSelectionCommand}" Key="Down" />
</TextBox.InputBindings>
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<i:InvokeCommandAction Command="{Binding CompleteCommand}" CommandParameter="{Binding Text, ElementName=InputText}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
i have a event triggered here with something input inside textbox with "KeyUp" event. now i am working for autocomplete textbox so i showed suggestions on typing in a list box that is working fine. so i need to bind down key to bind with this text box so that after showing suggestions user can press down key and select his desired option from there.
It will work fine for keybinding for down key.
The problem is with event keyup because any key press inside textbox then this event triggerd. now i am sending textbox value as command parmeter but i also need to send keyeventargs with comamnd pararmter so that i can findout which key is pressed and when downkey comesup i will not further execute the method.
So how i can i pass both textbox value and keyeventargs as command parameter, i am strictly following mvvm pattern.
By default, InvokeCommandAction passes the event args if you do not specify a command parameter. Also, you're textbox is bound to a property on your view model. So, if you change the the code as follows:
<TextBox Name="FilterInputText" Visibility="{Binding VisibiltyAttr}" Width="500" Height="30" Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="5">
<TextBox.InputBindings>
<KeyBinding Command="{Binding EnterCommand}" Key="Enter" />
<KeyBinding Command="{Binding DownSelectionCommand}" Key="Down" />
</TextBox.InputBindings>
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<i:InvokeCommandAction Command="{Binding CompleteCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
And then make sure your command's execute method has the right event args type for a parameter, then when the CompleteCommand is invoked you should have the event args as the parameter, and you should be able to check the InputText property on your view model for the text value.
Notice that I added "UpdateSourceTrigger=PropertyChanged" to the binding on the TextBox Text property. That will cause the property to be updated in the view model every single time the user types.
See the following link for my source on InvokeCommandAction's default behavior:
https://github.com/Microsoft/XamlBehaviors/issues/126

How to use an EventToCommand with an editable Combobox to bind TextBoxBase.TextChanged with a command?

I have an editable ComboBox.
<ComboBox IsEditable="True">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding CritereChangedCommand, Mode=OneWay}"/>
</i:EventTrigger>
<i:EventTrigger EventName="TextBoxBase.TextChanged">
<cmd:EventToCommand Command="{Binding CritereChangedCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
I use GalaSoft.MvvmLight.Command.EventToCommand to bind the SelectionChanged event.
I also would like to bind the TextChanged event, but it is a little bit tricky:
This event is only accessible by the ComboBox TextBoxBase property, and I can't find the proper way to bind this event.
You can see one of my unsuccessful attempt: SelectionChanged binding works fine, but TextChanged binding does not.
I also tried this syntax:
<ComboBox IsEditable="True">
<TextBoxBase>
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<cmd:EventToCommand Command="{Binding CritereChangedCommand, Mode=OneWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBoxBase>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding CritereChangedCommand, Mode=OneWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
But this won't even compile. I get an error "Type that can be instantiated expected" on the TextBoxBase tag.
Any idea ?
I know, very late response... but I hope it will help someone.
The problem here is that the EventTrigger class in Microsoft.Expression.Interactivity.dll uses reflection to find the event by the value of the EventName property and this won't work for attached events like TextBoxBase.TextChanged.
One option, which I use, is to implement your own custom EventTrigger class as described here and use this one instead of EventTrigger (the link there to CommandAction implementation is broken, but I managed to get it using internet archive).
Another option, which I don't like because it's not classic MVVM Command use, is to bind the Text property of the ComboBox to a property in the ViewModel and invoke the command from the ViewModel code on the setter, like this:
<ComboBox IsEditable="True"
Text="{Binding Text, Mode=TwoWay}" />
And in the ViewModel:
private string text;
public string Text
{
get { return text; }
set
{
text = value;
OnPropertyChanged("Text");
if(CritereChangedCommand.CanExecute())
CritereChangedCommand.Execute();//call your command here
}
}
I have found a way to work around the problem:
I create an invisible TextBox, bound to the ComboBox, and I bind the command on the TextChanged event of the TextBox.
It's not pretty, but it works...
<ComboBox Name="CbRubrique" IsEditable="True">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding CritereChangedCommand, Mode=OneWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
<TextBox Text="{Binding ElementName=CbRubrique, Path=Text, UpdateSourceTrigger=PropertyChanged}" Visibility="Collapsed">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<cmd:EventToCommand Command="{Binding CritereChangedCommand, Mode=OneWay}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>

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.

Implementing EventHandlers within ViewModel with MVVM WPF

I have a ComboBox:
<ComboBox x:Name="cbConnection"
ItemsSource="{Binding Source={StaticResource XmlConnectionList}, XPath=//ComboItem}"
DisplayMemberPath="Key"
SelectedValuePath="Value"
SelectedValue="{Binding Path=ConnectionString,ValidatesOnDataErrors=True,UpdateSourceTrigger=PropertyChanged}"
Margin="{StaticResource ConsistentMargins}"
Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}" Width="120"
LostFocus="{Binding Path=cbConnection_LostFocus}"/>
I am trying to get the LostFocus event handler moved to the ViewModel because I do some error handling within the setter for the SelectedValue binding "ConnectionString" found in the ViewModel. I want this to happen if a user reselects the same ComboBoxItem, which does fire OnPropertyChanged unless a different list item is selected.
The above binding results in error
A 'Binding' cannot be set on the 'AddLostFocusHandler' property of
type 'ComboBox'. A 'Binding' can only be set on a DependencyProperty
of a DependencyObject.
How can I fire repeatable code within the ViewModel on selection of any item within a ComboBox, regardless of the user's selection?
You'll need to include a reference to the System.Windows.Interactivity dll, but it will look something like this:
xmlns:b="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<ComboBox>
<b:Interaction.Triggers>
<b:EventTrigger EventName="LostFocus">
<b:InvokeCommandAction Command="{Binding cbConnection_LostFocus}" CommandParameter="{Binding}"/>
</b:EventTrigger>
</b:Interaction.Triggers>
</ComboBox>
Josh's answer worked for me with a different namespace:
xmlns:b="http://schemas.microsoft.com/expression/2010/interactivity"
<ComboBox>
<b:Interaction.Triggers>
<b:EventTrigger EventName="LostFocus">
<b:InvokeCommandAction Command="{Binding cbConnection_LostFocus}" CommandParameter="{Binding}"/>
</b:EventTrigger>
</b:Interaction.Triggers>
</ComboBox>

How to Bind a Command to a CheckBox

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.

Resources