Command Binding to Routed Event in WPF User-control - wpf

I want to bind Viewmodel command to Usercontrol's Routed Event.
Here is the detailed explanation of what I have.
I have a User Control which have one Image (which shows image) and one Button at bottom (Button to remove Image). I am using a Usercontrol in a ListView.
In my Usercontrol's Code behind I have a RoutedEventHandler to remove the Image:
public event RoutedEventHandler RemoveImage;
In the window where I use this Usercontrol, I have put:
<uc:ucImageListItem x:Name="ImageListItem" RemoveImage="ImageListItem_RemoveImage" />
This code works correctly if My code to remove image is in code behind. but I want to Bind command of Viewmodel to RemoveImage RoutedEvent.
Probably like (not correct)
<uc:ucImageListItem x:Name="ImageListItem" RemoveImage="{binding CommandtoRemove}" />
How to achieve this?
I found something related to RoutedCommand or DependancyProperty, but could not find any proper way, How to use them.
Let me know if I need to further clear my question.
Thanks in anticipation.

Hi this piece of code shows how to call command:
Command handler
public class CommandHandler : ICommand
{
public CommandHandler(Action<object> action,Func<object,bool> canexecute)
{
_action = action;
_canExecute = canexecute;
}
Action<object> _action;
Func<object, bool> _canExecute;
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action(parameter);
}
}
ViewModel
public class MainViewModel
{
private CommandHandler _buttonCommand;
public CommandHandler ButtonCommand
{
get
{
return _buttonCommand ?? (_buttonCommand = new CommandHandler((param) => OnButtonCommand(param),(param)=>true));
}
}
private void OnButtonCommand(object obj)
{
//DO things here whatever you want to do on Button click
}
}
View
<Button Command="{Binding ButtonCommand}" Content="ok"/>
you need to pass two parameters to CommandHandler Constructor one is Action that you want to fire on Command and second param is func that must return bool. If func evaluates to true only then the Action of Command is fired.And the param in action and func is what you will bind to the CommandParameter in my case above it will be null as I havent binded the CommandParameter.I hope this will help.

Related

WPF: create a binding to a nested property in code behind

I have the following multibinding in my xaml file:
<MyControl:CommandParameter>
<MultiBinding Converter="{commonConverters:MultiBindingConverter}">
<Binding Path="CurrentItem.Id" />
<Binding Path="SelectedItem.Count" />
</MultiBinding>
</Mycontrol:CommandParameter>
How can i define this multibinding in my viewmodel?
Or, when this is not possible, how can I define in my viewmodel that the CanExecute of the command is triggered every time the Id or Count changes?
Another difficulty is that CurrentItem and SelectedItem can be null after initialization and will be initialized while using the application.
Thanks!
To tell WPF your command may have become executable or not executable you can use the ICommand.RaiseCanExecuteChanged event. It'll make WPF call the CanExecute method of your command.
Since you didn't provide your ViewModel's and SelectedItem/CurrentItem's code the following example may not represent your use case but it'll give you the general idea.
Consider having the following custom command class :
public class MyCommand : ICommand
{
public EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
// do some stuff
}
public bool CanExecute(object parameter)
{
// determine if command can be executed
}
public void RaiseCanExecuteChanged()
{
this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
In your ViewModel you could then have something that looks like this
public class MyViewModel
{
private int _id;
public MyCommand SomeCommand { get; set; }
public int Id
{
get => _id;
set
{
// do other stuff (ie: property changed notification)
SomeCommand.RaiseCanExecuteChanged();
}
}
}

WPF Attach a command to a textbox on return key in NET 3.5

I am trying to attach a command and a commandparameter to a textbox on return key but without success. The parameter is the current text in the same textbox.
<TextBox x:Name="txtSearch">
<TextBox.InputBindings>
<KeyBinding Command="{Binding SearchCommand}"
CommandParameter="{Binding Path=Text, ElementName=txtSearch}" Key="Return" />
</TextBox.InputBindings>
</TextBox>
Basically I want to execute the command when user clicks on return/enter key and pass as a parameter the current text in the textbox.
I have found this link where it is said that in .NET 3.5 command parameter for keybinding is not accepting bindings. So a solution is proposed by code in code-behind but how can I pass a parameter to the command from the code?
First, you'll need to add the KeyBinding to your TextBox and set its Command on code-behind. Just add this in the constructor of your View:
public MainWindow()
{
InitializeComponent();
DataContext = new MyViewModel();
KeyBinding kb = new KeyBinding();
kb.Command = (DataContext as MyViewModel).SearchCommand;
kb.Key = Key.Enter;
txtSearch.InputBindings.Add(kb);
}
Then, you can bind the Text property of the TextBox named txtSearch to a property of your ViewModel. This way you don't need to pass a parameter as you can use the value of that property in your ViewModel inside the code that executes your Command.
Your ViewModel should look like this:
public class MyViewModel : ObservableObject
{
private string _txtSearch;
public string TxtSearch
{
get { return _txtSearch; }
set
{
if (value != _txtSearch)
{
_txtSearch = value;
OnPropertyChanged("TxtSearch");
}
}
}
private ICommand _searchCommand;
public ICommand SearchCommand
{
get
{
if (_searchCommand == null)
{
_searchCommand = new RelayCommand(p => canSearch(), p => search());
}
return _searchCommand;
}
}
private bool canSearch()
{
//implement canExecute logic.
}
private void search()
{
string text = TxtSearch; //here you'll have the string that represents the text of the TextBox txtSearch
//DoSomething
}
}
If you have access to C# 6 (Visual Studio 2015 and later versions), you can alter the call to the OnPropertyChanged to: OnPropertyChanged(nameof(TxtSearch));. This way you get rid of the "magic string" and eventual renaming of the property won't cause any problem for you.
And then your XAML should look like this: (Notice that you need to specify that te UpdateSourceTrigger must be PropertyChanged, so that your TxtSearch property of your ViewModel stays up to date when you hit the Enter key on your TextBox.
<TextBox Text="{Binding TxtSearch, UpdateSourceTrigger=PropertyChanged}" x:Name="txtSearch"/>
Your ViewModel needs to implement INotifyPropertyChanged and you need a proper ICommand implementation. Here I'll use the RelayCommand.
Those implementations are shown below.
Since your framework is .NET 3.5, implement it like this:
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
This is a implementation of the RelayCommand:
public class RelayCommand : ICommand
{
private Predicate<object> _canExecute;
private Action<object> _execute;
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
_canExecute = canExecute;
_execute = execute;
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}

ICommand help to replace button events

I am just after some information regarding ICommands,
On my WPF application, I have onClick events that adds to a ObservableCollection. So (ObservableCollection.Add()
However, I have 2 similar events to add to a collection also. So I hear I could use the ICommand interface to "execute" for adding/Editing/Removing etc, so I don't need these separate events.
Can someone provide me a example of how I can do this in MVVM. (All adds are in my ViewModel)
Thanks
You might want to look into the "RelayCommand" - it's a common implementation of an ICommand that will simplify your view-model code, allowing you to specify delegates for the ICommand's "Execute" and "CanExecute" methods. You'll find plenty of implementations on the web, but this is the one I use:
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
this._execute = execute;
this._canExecute = canExecute;
}
public virtual bool CanExecute(object parameter)
{
return this._canExecute == null || this._canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public virtual void Execute(object parameter)
{
this._execute(parameter);
}
}
In your VM, expose a command like this:-
public ICommand FooCommand
{
get
{
if (_fooCommand == null)
{
_fooCommand = new RelayCommand(ExecuteFooCommand, CanDoFooCommand);
}
return _fooCommand;
}
}
private void ExecuteFooCommand(object commandParameter)
{
// Code to execute the command.
}
private bool CanDoFooCommand()
{
// Code that indicates whether the command can be executed.
// This will manifest itself in the view by enabling/disabling the button.
}
As the RelayCommand ctr parameters are delegates, you can of course do stuff like this:-
new RelayCommand(o => { // do something }, o => true);
Finally, bind your command to your view button:-
<Button Content="Click me" Command="{Binding FooCommand}" ... />
You can also pass parameters to the command delegate:-
<Button Content="Click me" Command="{Binding FooCommand}" CommandParamter="123" />
(Written out from memory so may not be 100% syntactically correct!)
Going one step further...
To simplify things even more, I use a dynamic property to expose VM commands to the view. In my VM base class I have the following property:-
public dynamic Commands
{
get
{
return _commands;
}
}
Then in a VM's constructor I can create all of its commands like this:-
Commands.FooCommand = new RelayCommand(.....
Commands.BarCommand = ..etc..
In my XAML I bind commands like this:- Command={Binding Commands.FooCommand}.
It's a timesaver as it just means I can hang as many commands off of a single property as I want, rather than expose each one as a separate property as in my earlier example.

When does the ui detach from commands?

I'm really scratching my head with this one. I have a mainwindow which opens a dialog. After the dialog closes, the CanExecute method on commands bound in the dialog are still executing. This is causing some serious problems in my application.
Example:
MainWindow has a button with a click handler. This is the click event handler:
private void Button_Click(object sender, RoutedEventArgs e)
{
DialogWindow window = new DialogWindow();
window.ShowDialog();
}
In the dialog I bind an items control to a static resource in the dialog window, and each item in the list has a command:
<Window.Resources>
<Collections:ArrayList x:Key="itemsSource">
<local:ItemViewModel Description="A"></local:ItemViewModel>
<local:ItemViewModel Description="B"></local:ItemViewModel>
<local:ItemViewModel Description="C"></local:ItemViewModel>
</Collections:ArrayList>
<DataTemplate DataType="{x:Type local:ItemViewModel}">
<Button Grid.Column="1" Command="{Binding Path=CommandClickMe}" Content="{Binding Path=Description}" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}">
</Button>
</DataTemplate>
</Window.Resources>
<Grid>
<ToolBar ItemsSource="{StaticResource itemsSource}"></ToolBar>
</Grid>
This is the viewmodel:
public class ItemViewModel
{
private RelayWpfCommand<object> _commandClickMe;
public RelayWpfCommand<object> CommandClickMe
{
get
{
if (_commandClickMe == null)
_commandClickMe = new RelayWpfCommand<object>(obj => System.Console.Out.WriteLine("Hei mom"), obj => CanClickMe());
return _commandClickMe;
}
}
private bool CanClickMe()
{
return true;
}
public string Description { get; set; }
And this is the DelegateCommand implementation:
public class RelayWpfCommand<T> : ICommand
{
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
private readonly Predicate<T> _canExecute;
private readonly Action<T> _execute;
public RelayWpfCommand(Action<T> execute, Predicate<T> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
/// <summary>
/// Forces a notification that the CanExecute state has changed
/// </summary>
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
public bool CanExecute(T parameter)
{
return _canExecute(parameter);
}
public void Execute(T parameter)
{
_execute(parameter);
}
bool ICommand.CanExecute(object parameter)
{
if (!IsParameterValidType(parameter))
return false;
return CanExecute((T)parameter);
}
void ICommand.Execute(object parameter)
{
if (!IsParameterValidType(parameter))
throw new ArgumentException(string.Format("Parameter must be of type {0}", typeof(T)));
Execute((T)parameter);
}
private static bool IsParameterValidType(object parameter)
{
if (parameter != null && !typeof(T).IsAssignableFrom(parameter.GetType()))
return false;
return true;
}
}
Now, If I close the dialog window and set a breakpoint in the CanExecute (I'm using Prism DelegateCommand with weak event subscription) method on the viewmodel, I notice that it triggers although the dialog has been closed. Why on earth is the binding between the button in the dialog and the command on the ViewModel still alive?
And I am checking if its being executed by closing the window and at a later time setting a breakpoint in the "CanClickMe" method in the viewmodel. It will get executed for a while, then suddenly stop (probably due to GC). This non-determenistic behaviour is causing problems because in the real application the viewmodel might already bee disposed.
You may use the WeakEvent Pattern to mitigate this problem. Please refer to the following Stackoverflow question: Is Josh Smith's implementation of the RelayCommand flawed?
I've seen this catch many times in different projects, I'm not sure whether this creepy bug lurks in your app too, but it's worth checking.
There is a known memory leak issue in WPF 3.5 (including SP1), basically you can encounter it if you are binding to something that isn’t a DependencyProperty or doesn’t implement INotifyPropertyChanged. And this is exactly what your code is about.
Just implement INotifyPropertyChanged on ItemViewModel and see how it goes. Hope this helps.
You could clear the CommandBindings Collection of your window, when it closes.
rather than having your command as a property, could you try the following:
public ICommand CommandClickMe
{
get
{
return new RelayWpfCommand<object>((obj)=>System.Console.Out.WriteLine("Hei mom"), obj => CanClickMe());
}
}

Refresh WPF Command

Does anyone know how I can force CanExecute to get called on a custom command (Josh Smith's RelayCommand)?
Typically, CanExecute is called whenever interaction occurs on the UI. If I click something, my commands are updated.
I have a situation where the condition for CanExecute is getting turned on/off by a timer behind the scenes. Because this is not driven by user interaction, CanExecute is not called until the user interacts with the UI. The end result is that my Button remains enabled/disabled until the user clicks on it. After the click, it is updated correctly. Sometimes the Button appears enabled, but when the user clicks it changes to disabled instead of firing.
How can I force an update in code when the timer changes the property that affects CanExecute? I tried firing PropertyChanged (INotifyPropertyChanged) on the property that affects CanExecute, but that did not help.
Example XAML:
<Button Content="Button" Command="{Binding Cmd}"/>
Example code behind:
private ICommand m_cmd;
public ICommand Cmd
{
if (m_cmd == null)
m_cmd = new RelayCommand(
(param) => Process(),
(param) => EnableButton);
return m_cmd;
}
// Gets updated from a timer (not direct user interaction)
public bool EnableButton { get; set; }
Calling System.Windows.Input.CommandManager.InvalidateRequerySuggested() forces the CommandManager to raise the RequerySuggested event.
Remarks: The CommandManager only pays attention to certain conditions in determining when the command target has changed, such as change in keyboard focus. In situations where the CommandManager does not sufficiently determine a change in conditions that cause a command to not be able to execute, InvalidateRequerySuggested can be called to force the CommandManager to raise the RequerySuggested event.
I was aware of CommandManager.InvalidateRequerySuggested() a long time ago, and used it, but it wasn't working for me sometimes. I finally figured out why this was the case! Even though it doesn't throw like some other actions, you HAVE to call it on the main thread.
Calling it on a background thread will appear to work, but sometimes leave the UI disabled. I really hope this helps somebody, and saves them the hours I just wasted.
A workaround for that is binding IsEnabled to a property:
<Button Content="Button" Command="{Binding Cmd}" IsEnabled="{Binding Path=IsCommandEnabled}"/>
and then implement this property in your ViewModel. This also makes it a bit easier for the UnitTesting to work with the properties rather than commands to see if the command can be executed at a certain point of time.
I, personally, find it more convenient.
Probably this variant will suit you:
public interface IRelayCommand : ICommand
{
void UpdateCanExecuteState();
}
Implementation:
public class RelayCommand : IRelayCommand
{
public event EventHandler CanExecuteChanged;
readonly Predicate<Object> _canExecute = null;
readonly Action<Object> _executeAction = null;
public RelayCommand( Action<object> executeAction,Predicate<Object> canExecute = null)
{
_canExecute = canExecute;
_executeAction = executeAction;
}
public bool CanExecute(object parameter)
{
if (_canExecute != null)
return _canExecute(parameter);
return true;
}
public void UpdateCanExecuteState()
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, new EventArgs());
}
public void Execute(object parameter)
{
if (_executeAction != null)
_executeAction(parameter);
UpdateCanExecuteState();
}
}
Using simple:
public IRelayCommand EditCommand { get; protected set; }
...
EditCommand = new RelayCommand(EditCommandExecuted, CanEditCommandExecuted);
protected override bool CanEditCommandExecuted(object obj)
{
return SelectedItem != null ;
}
protected override void EditCommandExecuted(object obj)
{
// Do something
}
...
public TEntity SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
//Refresh can execute
EditCommand.UpdateCanExecuteState();
RaisePropertyChanged(() => SelectedItem);
}
}
XAML:
<Button Content="Edit" Command="{Binding EditCommand}"/>
Thanks guys for the tips. Here's a bit of code on how to marshal that call from a BG thread to the UI thread:
private SynchronizationContext syncCtx; // member variable
In the constructor:
syncCtx = SynchronizationContext.Current;
On the background thread, to trigger the requery:
syncCtx.Post( delegate { CommandManager.InvalidateRequerySuggested(); }, null );
Hope that helps.
-- Michael
To update only a single GalaSoft.MvvmLight.CommandWpf.RelayCommand you could use
mycommand.RaiseCanExecuteChanged();
and for me i've created an Extension method:
public static class ExtensionMethods
{
public static void RaiseCanExecuteChangedDispatched(this RelayCommand cmd)
{
System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { cmd.RaiseCanExecuteChanged(); }));
}
public static void RaiseCanExecuteChangedDispatched<T>(this RelayCommand<T> cmd)
{
System.Windows.Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { cmd.RaiseCanExecuteChanged(); }));
}
}

Resources