I`m quite begginer at WPF.
I have checkBox and I want that every check changes will excecute a command that gets IsChecked parameter and do some action.
I have the next code in my XAML file:
At my viewModel I have the next code:
private ICommand _addSelectedItemsCommand;
public ICommand AddSelectedItemsCommand
{
get
{
if (_addSelectedItemsCommand == null)
{
_addSelectedItemsCommand = new RelayCommand(param => this.AddSelectedItems());
}
return _addSelectedItemsCommand;
}
}
private void AddSelectedItems()
{
Do something...
}
But for "Do somthing" I need IsChecked parameter, How can i get it?
Thanks
In Your ViewModel RelayCommand Look Like
private RelayCommand<string> AddSelectedItemsCommand{get;set;}
And in your ViewModel Constructor code look like
AddSelectedItemsCommand=new RelayCommand<string>(AddSelectedItemsMethod);
void AddSelectedItemsMethod(string AddItem)
{
Your Code Goes Here.
}
You should use InvokeCommandAction class. You can find it in Expression Blend SDK or you can simply add this NuGet package to your project.
<CheckBox
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<ei:InvokeCommandAction Command="{Binding AddSelectedItemsCommand}" CommandParameter="..." />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
Related
I would like to do something when a click in a combobox, in a MVVM pattern.
I am trying to use input bindings in this way:
<ComboBox.InputBindings>
<KeyBinding Key="Return" Command="{Binding BuscarKeyDownCommand}"/>
<MouseBinding Gesture="LeftClick" Command="{Binding TiposFacturasMouseLeftClickCommand}"/>
</ComboBox.InputBindings>
In my view model I have this code:
private RelayCommand _tiposFacturasMouseLeftClickCommand;
public RelayCommand TiposFacturasMouseLeftClickCommand
{
get { return _tiposFacturasMouseLeftClickCommand ?? (_tiposFacturasMouseLeftClickCommand = new RelayCommand(param => TiposFacturasMouseLeftClick(), param => true)); }
}
private async void TiposFacturasMouseLeftClick()
{
try
{
//search for items.
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
But the command is not fired.
However, the key return input binding works as expected.
Which is the best way to bind the click event of the combobox? Or perhaps there are another better solution to search the items on the combobox the first time that I click on it.
Thanks.
You could install the Microsoft.Xaml.Behaviors.Wpf NuGet package and use an EventTrigger to invoke a command when an event is raised, e.g.:
<ComboBox xmlns:i="http://schemas.microsoft.com/xaml/behaviors">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown" >
<i:InvokeCommandAction Command="{Binding TiposFacturasMouseLeftClickCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ComboBoxItem>1</ComboBoxItem>
<ComboBoxItem>2</ComboBoxItem>
<ComboBoxItem>3</ComboBoxItem>
</ComboBox>
Please refer to this blog for more informatio about how to handle events in MVVM.
How to bind RichTextBox to a flag (true/false value). For example i want the flag to be true if the text in the RTB is edited. And also the binding should be two-way.
You have to use two things to solve your problem.
You have to add System.Windows.Interactivity reference and use this link in your xaml:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Here is an xaml (view part) example:
<Window ...
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
...
<RichTextBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<i:InvokeCommandAction Command="{Binding TextChangedCommand}"
x:Name="textChangedCommand" />
</i:EventTrigger>
</i:Interaction.Triggers>
</RichTextBox>
...
After this, you have to use an ICommand implementation in your ViewModel:
Here is a simple example to use in "ViewModel" part:
public partial class MainWindow : Window
{
RelayCommand _textChangedCommand;
public RelayCommand TextChangedCommand
{
get
{
if (_textChangedCommand == null)
_textChangedCommand = new RelayCommand(() => IsEdited = true);
return _textChangedCommand;
}
}
private bool _isEdited;
public bool IsEdited
{
get
{
return _isEdited;
}
set
{
_isEdited = value;
}
}
public MainWindow()
{
InitializeComponent();
//Use the following code if you want to use xaml.cs as ViewModel but It is not recommended, it is not correct MVVM pattern only simple example.
DataContext = this;
}
}
There are several way to implement the ICommand interface.
Here you can find one with description.
Should I put all events in views code behind or there is a more proper way, like place commands in ViewModel?
For example, I want to open Tab on double click on the datagrid row, where should I handle this event?
No you should not put events in code behind. In MVVM (Model-View-ViewModel) design pattern, the view model is the component that is responsible for handling the application's presentation logic and state. This means that your view's code-behind file should contain no code to handle events that are raised from any user interface (UI) element.
for eg if you have button in your xaml
<Button Content="OK" Click="btn_Click"/>
protected void btn_Click(object sender, RoutedEventArgs e)
{
/* This is not MVVM! */
}
Instead you can use WPF Command.All you have to do is bind to its Execute and CanExecute delegates and invoke your command.
So your code will now be
public class ViewModel
{
private readonly DelegateCommand<string> _clickCommand;
public ViewModel()
{
_clickCommand = new DelegateCommand(
(s) => { /* perform some action */ }, //Execute
null
} //CanExecute );
public DelegateCommand ButtonClickCommand
{
get { return _clickCommand; }
}
}
<Button Content="COOL" Command="ButtonClickCommand"/>
Kyle is correct in that your handlers should appear in the view model. If a command property doesn't exist then you can use an interaction trigger instead:
<DataGrid>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding Mode=OneWay, Path=OpenClientCommand}" CommandParameter="{Binding ElementName=searchResults, Path=SelectedItems}" />
</i:EventTrigger>
</i:Interaction.Triggers>
... other stuff goes here ...
</DataGrid>
Or you can use MVVM Lite's EventToCommand, which also allows you to pass in the message parameters:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<cmd:EventToCommand Command="{Binding ClosingCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
Which is used in in this case to cancel the window close event in response to the "Are you sure you want to quit?" dialog:
public ICommand ClosingCommand { get { return new RelayCommand<CancelEventArgs>(OnClosing); } }
private void OnClosing(CancelEventArgs args)
{
if (UserCancelsClose())
args.Cancel = true;
}
Relevant namespaces are as follows:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd ="http://www.galasoft.ch/mvvmlight"
I am looking at various implementations of hooking a ICommand up to a control's event. So for instance the GotFocus of a TextBox should call a GotFocusCommand in my View Model. I then got an idea to implement my own version (for my own learning) and it is working well, but I can only link one event to one command in the XAML.
( Basically I just use reflection to find the specified Event and then do a AddEventHandler that executes the command )
This works fine :
<Button
local:EventToCommand.Event="Click"
local:EventToCommand.Command="{Binding TestCommand}"
/>
But this does not :
<Button
local:EventToCommand.Event="Click"
local:EventToCommand.Command="{Binding ClickCommand}"
local:EventToCommand.Event="GotFocus"
local:EventToCommand.Command="{Binding GotFocusCommand}"
/>
as you it leads to a duplicate attribute name error.
Would it be possible to do something like :
<Button>
<Some Xaml Element>
<local:EventToCommand Event="Click" Command="{Binding ClickCommand}" />
<local:EventToCommand Event="GotFocus" Command="{Binding GotFocusCommand}" />
</Some Xaml Element>
</Button>
to "map" multiple events to commands ?
There are a couple of ways you could approach this, either using an Attached Property or inheriting from Button and adding your own DependencyProperty that contains a list of EventToCommand objects, and when you add to that collection you wire up the event to command. If this seems confusing, I can try to whip up some examples.
C#
public class EventedButton : Button
{
public static DependencyProperty EventCommandsProperty
= DependencyProperty.Register("EventCommands", typeof(EventToCommandCollection), typeof(EventedButton), new PropertyMetadata(null));
public EventToCommandCollection EventCommands
{
get
{
return this.GetValue(EventCommandsProperty) as EventToCommandCollection;
}
set
{
this.SetValue(EventCommandsProperty, value);
}
}
public EventedButton()
{
this.EventCommands = new EventToCommandCollection(this);
}
}
Xaml:
<local:EventedButton>
<local:EventedButton.EventCommands>
<local:EventToCommand />
</local:EventedButton.EventCommands>
</local:EventedButton>
Inside of EventToCommandCollection, you would attach/detach to the Event you wanted when items are added to the collection.
UPDATE: Attached Property
Here is some code to do the collection as an attached property:
C#
public static DependencyProperty CommandsProperty =
DependencyProperty.RegisterAttached(
"Commands",
typeof(ICollection<EventToCommand>),
typeof(DependencyObject),
new PropertyMetadata(null, OnCommandsChanged));
private static void OnCommandsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Attach/Detach event handlers
}
public static void SetCommands(DependencyObject element, ICollection<EventToCommand> value)
{
element.SetValue(CommandsProperty, value);
}
public static ICollection<EventToCommand> GetCommands(DependencyObject element)
{
return (ICollection<EventToCommand>)element.GetValue(CommandsProperty);
}
Xaml:
<local:EventedButton>
<local:EventToCommand.Commands>
<local:EventToCommandCollection>
<local:EventToCommand/>
</local:EventToCommandCollection>
</local:EventToCommand.Commands>
</local:EventedButton>
Using the Blend Event Triggers and an action negates the need to handle your own collections.
And it can be added to any control.
See MVVM Lights EventToCommand
Or my extension of it here.(source)
GalaSoft MVVM Light ToolKit - EventToCommand you can do this
<Button>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click" >
<cmd:EventToCommand
PassEventArgsToCommand="True"
Command="{Binding ButtonClick}"
/>
</i:EventTrigger>
</i:Interaction.Triggers>
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus" >
<cmd:EventToCommand
PassEventArgsToCommand="True"
Command="{Binding ButtonGotFocus}"
/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
Where import this namespaces
i- xmlns:i="clr-namespace:System.Windows.Interactivity;
assembly=System.Windows.Interactivity"
cmd-xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;
assembly=GalaSoft.MvvmLight.Extras.WPF4"
I've totally lost in the command binding that is used in MVVM. How should I bind my object to the window and/or its command to the control to get method called on the Button Click?
Here is a CustomerViewModel class:
public class CustomerViewModel : ViewModelBase
{
RelayCommand _saveCommand;
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand(param => this.Save(), param => this.CanSave);
NotifyPropertyChanged("SaveCommand");
}
return _saveCommand;
}
}
public void Save()
{
...
}
public bool CanSave { get { return true; } }
...
ViewModelBase implements the INotifyPropertyChanged interface
Here is how Button is bound to the command:
<Button Content="Save" Margin="3" Command="{Binding DataContext.Save}" />
An instance of the CustomerViewModel is assigned to the DataContext of the window that contains a Button.
The given example is not working: I've put break point into the Save method but execution doesn't pass to the method. I've saw a lot of examples (on the stackoverflow too), but can't figure out how binding should be specified.
Please advise, any help will be appreciated.
Thanks.
P.S. Probably I need to specify RelativeSource in the Button binding... something like this:
Command="{Binding Path=DataContext.Save, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
but which type should be specified for ancestor?
What you are trying to do is to bind directly to the Save method. This is not how to do it.
Assuming that you have set the DataContext of your View to an instance of CustomerViewModel, this is how you bind to the SaveCommand:
<Button Content="Save" Margin="3" Command="{Binding SaveCommand}" />
You do not have to call NotifyPropertyChanged("SaveCommand");.