Capture command Parameter value in mvvm - wpf

I have two radio button.I just want to capture the selected radio button value in viewmodel.I have defined a method GetLOB() in which I want to capture the commandParameter value.
Here is my code
<RadioButton GroupName="Os" Content="Payroll" IsChecked="{Binding ObjEntrySheetManagerViewModel.CheckedProperty}" Command="LobType" CommandParameter="Payroll" Grid.Row="4" Grid.Column="0" Margin="25,15,0,0"/>
<RadioButton GroupName="Os" Content="Sales" Grid.Row="4" Grid.Column="1" Command="LobType" CommandParameter="Payroll" Margin="5,15,0,0"/>
private RelayCommand _LobType;
public ICommand LobType
{
get
{
if (_LobType == default(RelayCommand))
{
_LobType = new RelayCommand(GetLOB);
}
return _LobType;
}
}
private void GetLOB()
{
}

Capture parameter using lambda (assuming RelayCommand used by you have overloaded constructor which will take Action<object> as argument)
public ICommand LobType
{
get
{
if (_LobType == default(RelayCommand))
{
_LobType = new RelayCommand(param => GetLOB(param));
}
return _LobType;
}
}
private void GetLOB(object parameter)
{
}
Relay command sample from MSDN (in case you need):
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion
#region Constructors
public RelayCommand(Action<object> execute)
: this(execute, null)
{ }
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion
}

Related

Datagrid don't show elements MVVM

I am trying to load a list in my datagrid when pressing the button but it does not show anything.
Do you know where the error is?
Thanks a lot
<UserControl x:Class="HiberusHubClient.View.RatesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:HiberusHubClient.View"
mc:Ignorable="d"
x:Name="RatesViewControl"
d:DesignHeight="450" d:DesignWidth="800"
DataContext="RatesViewControlDataContext">
<Grid>
<StackPanel HorizontalAlignment = "Left">
<Button x:Name="btnUpdate" Width="100" Height="20" HorizontalAlignment="Center" Grid.Row="1" Content="Update" Command="{Binding Path=UpdateCommand}" />
<StackPanel Orientation = "Horizontal">
<DataGrid Width="200" Height="400" AutoGenerateColumns="True" ItemsSource="{Binding LstConvertRates,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Name="lstDataGrid" />
</StackPanel>
</StackPanel>
</Grid>
</UserControl>
public partial class RatesView : UserControl
{
public RatesView()
{
InitializeComponent();
DataContext = new ConvertRatesViewModel();
}
}
ConvertRate.cs
public class ConvertRate
{
}
public class ConvertRates : INotifyPropertyChanged
{
private string currencyFrom;
private string currencyTo;
private string rate;
public string CurrencyFrom
{
get
{
return currencyFrom;
}
set
{
if (currencyFrom != value)
{
currencyFrom = value;
RaisePropertyChanged("CurrencyFrom");
}
}
}
public string CurrencyTo
{
get { return currencyTo; }
set
{
if (currencyTo != value)
{
currencyTo = value;
RaisePropertyChanged("CurrencyTo");
}
}
}
public string Rate
{
get { return rate; }
set
{
if (rate != value)
{
rate = value;
RaisePropertyChanged("Rate");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
ConvertRatesViewModel .cs
internal class ConvertRatesViewModel : INotifyPropertyChanged
{
private ObservableCollection<ConvertRates> lstConvertRates;
public ObservableCollection<ConvertRates> LstConvertRates
{
get
{
return lstConvertRates;
}
set
{
lstConvertRates = value;
//if u want Observable Collection to get updated on edit either
RaisePropertyChanged("LstConvertRates");
}
}
public void getConvertRates()
{
HiberusHubeReference.RequestHubeRestService hiberusHubeReference = new HiberusHubeReference.RequestHubeRestService();
JavaScriptSerializer json = new JavaScriptSerializer();
string aa = json.Serialize(hiberusHubeReference.RequestRates());
ObservableCollection<ConvertRates> oMycustomclassname = Newtonsoft.Json.JsonConvert.DeserializeObject<ObservableCollection<ConvertRates>>(aa);
LstConvertRates = oMycustomclassname;
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
private ICommand mUpdater;
public ICommand UpdateCommand
{
get
{
if (mUpdater == null)
mUpdater = new Updater();
return mUpdater;
}
set
{
mUpdater = value;
}
}
}
internal class Updater : ICommand
{
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
ConvertRatesViewModel convertRatesViewModel = new ConvertRatesViewModel();
convertRatesViewModel.getConvertRates();
}
}
If you set DataContext in code behind then there is no need to set DataContext also in xaml. You can remove DataContext="RatesViewControlDataContext" from RatesView.xaml. Btw. DataContext="RatesViewControlDataContext" means DataContext property is set to string "RatesViewControlDataContext". You probably don't this.
Try to use existing implementation of ICommand interface like RelayCommand.
public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
_canExecute = canExecute;
_execute = execute;
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
For your UpdateCommand you can modify the setter and create a new instance of RelayCommand. In the constructor you can specify whether the command should be executed and which method on your ConvertRatesViewModel will be called when you press btnUpdate button.
private ICommand mUpdater;
public ICommand UpdateCommand
{
get
{
if (mUpdater == null)
mUpdater = new RelayCommand(x => true, x => getConvertRates());
return mUpdater;
}
set
{
mUpdater = value;
}
}

Input Binding CommandParameter Bind to Window

I want to have a window level KeyBinding with command paramter as window itself.
e.g.
<KeyBinding Command="{Binding CloseCommand}" CommandParameter="{Binding ElementName=mainWindow}" Key="Esc"/>
Binding works, but paramter comes in as null. What's the work around?
Following is my Command:`
public class DelegateCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public DelegateCommand(Action<object> execute)
: this(execute, null)
{
}
public DelegateCommand(Action<object> execute,
Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("Action excute is null");
_execute = execute;
_canExecute = canExecute;
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
Actually this working for me - but i am using the RelayCommand<FrameworkElement> of [MVVM Light Toolkit1.
<Window.InputBindings>
<KeyBinding Command="{Binding MyCommand, ElementName=MainRoot}" CommandParameter="{Binding ElementName=MainRoot}" Key="Esc"/>
</Window.InputBindings>
In my case the Command comes from a DependencyProperty, but that shouldn't make a big difference.
public RelayCommand<FrameworkElement> MyCommand
{
get { return (RelayCommand<FrameworkElement>)GetValue(MyCommandProperty); }
set { SetValue(MyCommandProperty, value); }
}
// Using a DependencyProperty as the backing store for MyCommand. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyCommandProperty =
DependencyProperty.Register("MyCommand", typeof(RelayCommand<FrameworkElement>), typeof(MainWindow), new PropertyMetadata(null));
public MainWindow()
{
InitializeComponent();
MyCommand = new RelayCommand<FrameworkElement>(DoSthYo);
}
public void DoSthYo(FrameworkElement fwE)
{
var x = fwE;
}
So because this is working - i think its your Command that does not support CommandParameter maybe.
My advice is to use a RelativeSource in your CommandParameter binding:
<Window.InputBindings>
<KeyBinding Command="{x:Static local:CloseWindowCommand.Instance}" CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" Key="Esc" />
</Window.InputBindings>
In this way your binding can be independant from the name of your Window.
Then you can create a static command for closing each window of your application:
public class CloseWindowCommand : ICommand
{
public static readonly ICommand instance = new CloseWindowCommand();
public event EventHandler CanExecuteChanged;
private CloseWindowCommand()
{
}
public bool CanExecute(object parameter)
{
return (parameter is Window);
}
public void Execute(object parameter)
{
Window win;
if (CanExecute(parameter))
{
win = (Window)parameter;
win.Close();
}
}
}
I hope it can help you.

What if CanExecute has to be a method, and not a property?

So I have this View:
<StackPanel>
<TextBox x:Name="Name"/>
<Button x:Name="SayHello"
Content="Click Me" />
</StackPanel>
And I have this ViewModel:
internal class ShellViewModel : PropertyChangedBase
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
NotifyOfPropertyChange(() => Name);
NotifyOfPropertyChange(() => CanSayHello());
}
}
public bool CanSayHello()
{
bool isenabled = !string.IsNullOrWhiteSpace(Name);
return isenabled;
}
public void SayHello()
{
MessageBox.Show(string.Format("Hello, {0}!", Name));
}
}
But whenever I enter some value in the textbox, I got this exception:
{"Unable to cast object of type 'System.Linq.Expressions.InstanceMethodCallExpressionN' to type 'System.Linq.Expressions.MemberExpression'."}
In the commercial app that I'm developing I must have the CanSayHello() member in the VM as a method, not as a property. What should I do?
You have that exception because you are calling NotifyOfPropertyChange on CanSayHello and CanSayHello is a method, not a property.
Change to:
public bool CanSayHello
{
get { return !string.IsNullOrWhiteSpace(Name); }
}
You should use commands to bind actions to UI items. There is an implementation of ICommand called RelayCommand which is typically used in most WPF projects. It allows you to use method, property or predicate.
public class RelayCommand : ICommand
{
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException(nameof(execute));
_execute = execute;
_canExecute = canExecute;
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
}

Button stays disabled - DelegateCommand not re-evaluating CanExecute handler

Problem: Buttons never gets enabled.
<Button Name="btnCompareAxises"Command="{Binding CompareCommand}"
Content="{Binding VM.CompareAxisButtonLabel}"
IsEnabled="{Binding VM.IsCompareButtonEnabled}">
</Button>
ViewModel constructor:
this.CompareCommand = new DelegateCommand(CompareCommand, ValidateCompareCommand);
The problem seems to be related to the CanExecute eventhandler of the registered Command of the button.
The CanExecute handler returns false when the application loads.
This is fine, as the conditions are not met initially.
The canExecute handler only runs on application startup or when the button is clicked. You cannot click a disabled button, so the button stays disabled forever if the initial value returned form the CanExecute handler is false!
Question:
Do I have to enable the button again, only using the command bound to it.
Something like, hey command please reevaluate if the conditions for this buttons are met ?
Why sits the IsEnabled property under section Coercion and not under local?
The command:
public class DelegateCommand : ICommand
{
private readonly Func<object, bool> canExecute;
private readonly Action<object> execute;
public DelegateCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
public void RaiseCanExecuteChanged()
{
this.OnCanExecuteChanged();
}
protected virtual void OnCanExecuteChanged()
{
var handler = this.CanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
Solved:
I had to adapt the DelegateCommand class to make it work:
I have added CommandManager.RequerySuggested to the public CanExecuteChanged Event property.
Now it will automatically re-evaluate the CanExecute method of the command when soemthing changes in the UI!
public class DelegateCommand : ICommand
{
private readonly Func<object, bool> canExecute;
private readonly Action<object> execute;
public DelegateCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
/// CommandManager
/// Go to the "References" part of your class library and select "Add Reference".
/// Look for an assembly called "PresentationCore" and add it.
public event EventHandler CanExecuteChanged
{
add
{
_internalCanExecuteChanged += value;
CommandManager.RequerySuggested += value;
}
remove
{
_internalCanExecuteChanged -= value;
CommandManager.RequerySuggested -= value;
}
}
event EventHandler _internalCanExecuteChanged;
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
public void RaiseCanExecuteChanged()
{
this.OnCanExecuteChanged();
}
protected virtual void OnCanExecuteChanged()
{
var handler = this._internalCanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
Removed this from the button:
IsEnabled="{Binding VM.IsCompareButtonEnabled}"
The binding here is not necessary, as the CanExecute handler will take care of the enabled/disabled state of the button!

WPF Ribbon RibbonCommand replaced by ICommand

I'm looking for an example how to replace this old code for RibbonApplicationMenuItem. Question is how to replace removed RibbonCommand
<ResourceDictionary>
<r:RibbonCommand
x:Key="MenuItem1"
CanExecute="RibbonCommand_CanExecute"
LabelTitle="Menu Item 1"
LabelDescription="This is a sample menu item"
ToolTipTitle="Menu Item 1"
ToolTipDescription="This is a sample menu item"
SmallImageSource="Images\files.png"
LargeImageSource="Images\files.png" />
</ResourceDictionary>
</r:RibbonWindow.Resources>
<r:RibbonApplicationMenuItem Command="{StaticResource MenuItem1}">
</r:RibbonApplicationMenuItem>
You can use RelayCommand.
Binding in this case is very simple:
<ribbon:RibbonApplicationMenuItem Header="Hello _Ribbon"
x:Name="MenuItem1"
ImageSource="Images\LargeIcon.png"
Command="{Binding MyCommand}"
/>
Your ViewModel class in this case, must contain property MyCommand of ICommand type:
public class MainViewModel
{
RelayCommand _myCommand;
public ICommand MyCommand
{
get
{
if (_myCommand == null)
{
_myCommand = new RelayCommand(p => this.DoMyCommand(p),
p => this.CanDoMyCommand(p));
}
return _myCommand;
}
}
private bool CanDoMyCommand(object p)
{
return true;
}
private object DoMyCommand(object p)
{
MessageBox.Show("MyCommand...");
return null;
}
}
Don't forget assign DataContext of MainWindow:
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
RelayCommand class:
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}

Resources