Creating RelayCommand without implementing ICommand - c#

My query is how can I create a class behaving same as RelayCommand but without implementing ICommand for my MVVM application? Any suggestions are much appreciated.
My RelayCommand [which implements ICommand] is as below:
public class RelayCommand:ICommand
{
private readonly Action<object> m_Execute;
private readonly Predicate<object> m_CanExecute;
public RelayCommand(Action<object> exec) : this(exec, null) { }
public RelayCommand(Action<object> exec, Predicate<object> canExec)
{
if (exec == null)
throw new ArgumentNullException("exec");
m_Execute = exec;
m_CanExecute = canExec;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
if (parameter == null)
return true;
else
return m_CanExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add
{
if (m_CanExecute != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (m_CanExecute != null)
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter)
{
m_Execute(parameter);
}
#endregion
}

Related

C# WPF => commands doesn't work though binding and using ICommand. Compiler doesn't throw any exception

!!! SOLVED, THANK YOU VERY MUCH !!!
I'm writing my first MVVM application (in WPF C#). Because of that, I want to use commands instead "Click" event defined in a view. The command, which I want to induce is really simple, it should to create and open a view.
I have written RelayCommand class which inherits ICommand interface.
internal class RelayCommand : ICommand
{
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute ?? throw new ArgumentNullException("execute");
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
I write a method changing value of the field, which represent a view.
private bool openSoundsWindow;
private bool openChordsWindow;
public bool OpenSoundsWindow
{
get { return openSoundsWindow; }
set { openSoundsWindow = value; }
}
public bool OpenChordsWindow
{
get { return openChordsWindow; }
set { openChordsWindow = value; }
}
public void OpenSounds()
{
openSoundsWindow = true;
}
public void OpenChords()
{
OpenChordsWindow = true;
}
I wrote in view model class commands by RelayCommand and OnPropertyChanged event. View model class inherits INotifyPropertyChanged.
private MainModel model = new MainModel();
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public bool OpenSoundsWindow
{
get { return model.OpenSoundsWindow; }
set
{
model.OpenSoundsWindow = value;
OnPropertyChanged(nameof(OpenSoundsWindow));
}
}
private ICommand openSounds = null;
public ICommand OpenSounds
{
get
{
if (openSounds == null)
{
openChords = new RelayCommand(
(object o) =>
{
model.OpenSounds();
OnPropertyChanged(nameof(OpenSoundsWindow));
var newSoundsWindow = new Sounds();
newSoundsWindow.Show();
},
(object o) =>
{
return model.OpenSoundsWindow != null;
});
}
return openSounds;
}
}
I created instance of view model in view's xaml code.
xmlns:vm="clr-namespace:HearingTeacher.ViewModels"
d:DataContext="{d:DesignInstance Type=vm:MainViewModel}"
<Window.Resources>
<vm:MainViewModel x:Key="mainViewModel" />
</Window.Resources>
I binded property command for buttons with created commands in view model.
<Button Grid.Row="0" Content="Sounds" Command="{Binding Path=OpenSounds,
UpdateSourceTrigger=PropertyChanged}" />
Compiler doesn't throw any exception, and .NET starts an application correctly, but commands doesn't work.

Usercontrol doesn`t update textbox mvvm WPF C#

sorry for so much code.
But unfortunately there is so much connected.
That's why I had to insert so much code.
I tried to keep it to a minimum.
I hope it is enough.
To my problem:
As you can see here there is a button to select a path on the computer.
There is also a textbox which shows the path again.
XAML UserControl Code:
<DockPanel Grid.Row="1" Grid.Column="1">
<Button
Content="Repo Pfad"
Command="{Binding SelectRepoPathCommand}"/>
</DockPanel>
<DockPanel Grid.Row="1" Grid.Column="2">
<TextBox Text="{Binding repoPath, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</DockPanel>
Here the code is stored in the config for the user.
So that he does not have to enter the path again and again at the next start.
Small additional Info:
Since the path to the config is saved successfully, the test box will be updated after the second time you select the path.
This is because the second time the previously saved path is displayed.
ViewModel:
class BuildToolViewModel : ObservableObject
{
private string _repoPath;
public string repoPath
{
get
{
if (Properties.Settings.Default.repoPath != null)
{
return Properties.Settings.Default.repoPath;
}
else
{
return _repoPath;
}
}
set
{
_repoPath = value;
OnPropertyChanged("repoPath");
Properties.Settings.Default.repoPath = _repoPath;
Properties.Settings.Default.Save();
}
}
public RelayCommand SelectRepoPathCommand{ get; private set; }
#endregion #Properties
#region ctor
public BuildToolViewModel()
{
SelectRepoPathCommand = new RelayCommand(SelectRepoPath);
}
#endregion //ctor
#region Methods
public void SelectRepoPath(object sender)
{
repoPath = explorerDialog.OpenFileDialogPath();
}
}
Here is my ObservableObject that inherits from INotifyPropertyChanged.
ObservableObject (INotifyPropertyChanged):
class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
this.VerifyPropertyName(propertyName);
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
}
Here is my RelayCommand that inherits from ICommand.
RelayCommand (ICommand):
class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region ctor
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 //ctor
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameters)
{
return _canExecute == null ? true : _canExecute(parameters);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameters)
{
_execute(parameters);
}
#endregion // ICommand Members
}
Here still like it in the MainWindowViewModel with the ICommand implement.
MainWindowViewModel (ObservableObject):
class MainWindowViewModel : ObservableObject
{
private ICommand _changePageCommand;
private IPageViewModel _currentPageViewModel;
private List<IPageViewModel> _pageViewModels;
public ICommand ChangePageCommand
{
get
{
if (_changePageCommand == null)
{
_changePageCommand = new RelayCommand(
p => ChangeViewModel((IPageViewModel)p),
p => p is IPageViewModel);
}
return _changePageCommand;
}
}
Fix you property repoPatch code:
private string _repoPath;
public string repoPath
{
get
{
if (string.IsNullOrEmpty(_repoPath))
{
_repoPath= Properties.Settings.Default.repoPath;
}
return _repopath
}
....................
............
I found the error, the problem is that the "repoPath" can be null or empty, and you are only validating that it is not null. but if the value of "repoPath" is empty, it will always return an empty value, since the value is different from null. You need to change your validation to
if (!string.IsNullOrEmpty(Properties.Settings.Default.repoPath))
also, I can see that you are saving the value of the variable "_repoPath" to the user settings "avlPath" instead of "repoPath", is it correct?

CS0201 error in ICommand impmentation for WPF application

I develop a WPF application, obviously, I use MVVM pattern. Without an external library (MvvmCross, MvvmLight, ...)
And I've tried to implement ICommand:
Option 1
public class Command : ICommand
{
private readonly Func<bool> _canExecute;
private readonly Action _action;
public Command1(Action action, Func<bool> canExecute)
{
_action = action;
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter) => true;
public void Execute(object parameter) => _action();
}
Option 2
public class Command : ICommand
{
private readonly Func<bool> _canExecute;
private readonly Action<object> _action;
public Command1(Action<object> action, Func<bool> canExecute)
{
_action = action;
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter) => true;
public void Execute(object parameter) => _action(parameter);
}
Option 3
...with some delegates
public class Command : ICommand
{
private readonly Func<object, bool> _canExecute;
private readonly Action<object> _execute;
public Command(Action<object> execute) => _execute = execute ?? throw new ArgumentNullException(nameof(execute));
public Command(Action execute)
: this((Action<object>)delegate { execute(); })
{
if (execute == null)
{
throw new ArgumentNullException(nameof(execute));
}
}
public Command(Action<object> execute, Func<object, bool> canExecute)
: this(execute) => _canExecute = canExecute ?? throw new ArgumentNullException(nameof(canExecute));
public Command(Action execute, Func<bool> canExecute)
: this(delegate
{
execute();
}, (object o) => canExecute())
{
if (execute == null)
{
throw new ArgumentNullException(nameof(execute));
}
if (canExecute == null)
{
throw new ArgumentNullException(nameof(canExecute));
}
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter) => _canExecute != null ? _canExecute(parameter) : true;
public void Execute(object parameter) => _execute(parameter);
}
In all cases:
public class MainViewModel : BaseViewModel
{
public ICommand MyCommand = new Command(() => MyVoid());
private void MyVoid()
{
// do something
}
}
public class MainViewModel : BaseViewModel
{
public ICommand MyCommand = new Command(MyVoid);
private void MyVoid()
{
// do something
}
}
I've a CS0201 error (Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement).
I don't understand why.
In other projects, which use MVVM pattern (Xamarin.Forms, Xamarin, ...), I use Xamarin.Forms.Command or MvxCommand (MvvmCross) and it works...
I don't suggest to name the realying class Command because you may get naming conflict with some built-in classes.
The closest to your try code:
public ICommand MyCommand => new Command(parameter => { MyVoid(); });
or the same in "block" syntax
public ICommand MyCommand
{
get
{
return new Command(parameter => { MyVoid(); });
}
}
But it's wrong approach because it will create new Command instance each time the command was called. Give to Garbage Collector as less work as possible. Examples of the correct ways doing it you may find below.
You're developing another bicycle. :) Look here.
Here is copy-paste from my project. It's exactly the same as in above link.
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
}
And the usage
<Button Contecnt="Click me!" Command="{Binding MyCommand}"/>
private ICommand _myCommand;
public ICommand MyCommand => _myCommand ?? (_myCommand = new RelayCommand(parameter =>
{
// do here the execution
}));
And with parameter (Binding for CommandParameter is available too)
<Button Contecnt="Click me!" Command="{Binding MyCommand}" CommandParameter="test value"/>
public ICommand MyCommand => _myCommand ?? (_myCommand = new RelayCommand(parameter =>
{
if (parameter is string p && p == "test value")
{
// do here the execution
}
}));
And finally, usage of optional CanExecute
public ICommand MyCommand => _myCommand ?? (_myCommand = new RelayCommand(parameter =>
{
// do here the execution
// don't put the same condition as in CanExecute here,
// it was already checked before execution has entered this block
},
parameter => (x > y) && (a + b > c) // any condition or just return a bool
));
if CanExecute returns false, the command will not be executed and Button or MenuItem becomes automatically disabled. Just test it.

Missing understanding of MVVM

Trying to get to grips with MVVM in WPF c#.
I am a slow learner...
I have my MainWindow.xaml.
This is the markup in question:
<Viewbox x:Name="vbxucProductCostMenu" Stretch="{Binding Stretch}" StretchDirection="Both">
//a user control
</Viewbox>
<Button Command="{Binding MagnifyMinimiseCommand}" CommandParameter="UniformToFill">
<Image Source="Images/button_plus_green.png"/>
</Button>
Part of my MainWindow.cs
public MainWindow()
{
InitializeComponent();
this.DataContext = new MagnifyMinimise();
}
My Viewmodel?
public class MagnifyMinimise : INotifyPropertyChanged
{
public MagnifyMinimise()
{
Minimise();
}
MagnifyMinimiseCommand _magnifyMinimiseCommand = new MagnifyMinimiseCommand();
public MagnifyMinimiseCommand MagnifyMinimiseCommand
{
get { return _magnifyMinimiseCommand; }
}
public event PropertyChangedEventHandler PropertyChanged;
public void Magnify()
{
Stretch = "UniformToFill";
}
public void Minimise()
{
Stretch = "None";
}
public string Stretch { get; set; }
private void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
my 'ICommand' class:
public class MagnifyMinimiseCommand : ICommand
{
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
//how do I set the property of stretch here!!
}
}
When I run this it starts up minimized which is good.
I then want to 'maximize' the viewbox when the user clicks that button.
By setting the breakpoint in the 'Execute' method i can see that it is being invoked and the 'parameter' is set to 'UniformToFill'.
But how do I get the Stretch property to 'read' that?
ADDITONAL:
I have changed it all to this (which does not work):
public class MagnifyMinimise : INotifyPropertyChanged
{
private ActionCommand<string> _magnifyMinimiseCommand;
public MagnifyMinimise()
{
Minimise();
_magnifyMinimiseCommand = new ActionCommand<string>(Magnify);
}
private void Magnify(string stretch)
{
// now the viewmodel handles it instead of the action
Stretch = stretch;
}
public event PropertyChangedEventHandler PropertyChanged;
public void Magnify()
{
Stretch = "UniformToFill";
}
public void Minimise()
{
Stretch = "None";
}
public string Stretch { get; set; }
private void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
public class ActionCommand<T> : ICommand where T : class
{
private readonly Action<T> mAction;
public ActionCommand(Action<T> action)
{
mAction = action;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
mAction(parameter as T);
}
public event EventHandler CanExecuteChanged;
}
<Button Command="{Binding ActionCommand}" CommandParameter="UniformToFill">
<Image Source="Images/button_plus_green.png" />
</Button>
The easiest way is, like suggested by #Default, to use a RelayCommand. There is one (or an alternative) provided in every major MVVM framework (Prism, MVVM Light, Caliburn.Micro, ...).
That said, if you wanted to solve the issue with your vanilla implementation of a command, you'd just have to pass a reference to the viewmodel in the constructor:
public class MagnifyMinimiseCommand : ICommand
{
public MagnifyMinimiseCommand(MagnifyMinimise viewModel)
{
this.ViewModel = viewModel;
}
protected MagnifyMinimise ViewModel { get; }
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
this.ViewModel.IsMagnifying = "...";
}
}
You need to invoke PropertyChanged for Stretch. That's how i would do it:
private string _stretch;
public string Stretch
{
get { return _stretch; }
set {_stretch = value; OnPropertyChanged("Stretch"); }
}
Also you might want to consider using RelayCommand or DelegateCommand
Another sidenote: In MVVM try not to write any code in the view's code behind. Use App.xaml.cs for setting the DataContext of the view.
EDIT: To answer your question, i would create a DelegateCommand class like this:
class DelegateCommand : ICommand
{
private readonly Action<Object> _execute;
private readonly Func<Object, Boolean> _canExecute;
public DelegateCommand(Action<Object> execute) : this(null, execute) { }
public DelegateCommand(Func<Object, Boolean> canExecute, Action<Object> execute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
_execute = execute;
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged;
public Boolean CanExecute(Object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public void Execute(Object parameter)
{
if (!CanExecute(parameter))
{
throw new InvalidOperationException("Command execution is disabled.");
}
_execute(parameter);
}
public void OnCanExecuteChanged()
{
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}
and use it like this in your viewmodel:
public DelegateCommand MagnifyMinimiseCommand { get; private set; }
.....
MagnifyMinimiseCommand = new DelegateCommand(param => { Stretch = UniformToFill; });
then
<Button Command="{Binding MagnifyMinimiseCommand}">
<Image Source="Images/button_plus_green.png"/>
</Button>
Instead of using such a specific type of Command, you can create a more generic command and allow the viewmodel to handle the action itself. So create a generic type of ICommand:
public class ActionCommand<T> : ICommand where T : class
{
private readonly Action<T> mAction;
public ActionCommand(Action<T> action)
{
mAction = action;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
mAction(parameter as T);
}
public event EventHandler CanExecuteChanged;
}
and then create it like this:
private ActionCommand<string> _magnifyMinimiseCommand;
public MagnifyMinimise()
{
_magnifyMinimiseCommand = new ActionCommand<string>(Magnify);
....
}
private void Magnify(string stretch)
{
// now the viewmodel handles it instead of the action
Stretch = stretch;
}
Also, as a common practice I usually expose the properties to the View as it's interfaces, so the MagnifyMinimiseCommand would for instance be an ICommand instead (you can still use the field to access the ActionCommands stuff).

MVVM - Commands on special events

I try to use commands with the MVVM - Pattern and I don't know how to "bind" a command to a special event, e.g. MouseUp or MouseEnter. How to do this?
First you should define ICommnad property in your ViewModel.
public ICommand MouseUpCommand
{
get
{
if (this.mouseUpCommand == null)
{
this.mouseUpCommand = new RelayCommand(this.OnMouseUp);
}
return this.mouseUpCommand;
}
}
private void OnMouseUp()
{
// Handle MouseUp event.
}
You can find lot of ICommand implementations. One of them:
public class RelayCommand : ICommand
{
public RelayCommand(Action<object> execute)
{
this._execute = execute;
...
}
...
public void Execute(object parameter)
{
_execute(parameter);
}
}
Then add event trigger within which invoke your Command:
<i:EventTrigger EventName="MouseUp">
<i:InvokeCommandAction Command="{Binding MouseUpCommand}"/>
</i:EventTrigger>
Read the EventToCommand at the following page, please
Look at WPF Binding UI events to commands in ViewModel.
For this you need System.Windows.Interactivity.dll which you can get from Nuget
Completing #AnatoliiG post here's an implementation and a sample usage of the RelayCommand class.
Code:
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
[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 // ICommand Members
}
Usage:
// To use this class within your viewmodel class:
RelayCommand _myCommand;
public ICommand MyCommand
{
get
{
if (_myCommand == null)
{
_myCommand = new RelayCommand(p => this.DoMyCommand(p),
p => this.CanDoMyCommand(p) );
}
return _myCommand;
}
}

Categories

Resources