WPF disable command for a while it running - c#

I need to disable button for a while it running. I have this code:
RelayCommand.cs This is my command class.
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("execute");
}
_execute = execute;
_canExecute = canExecute;
}
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);
}
}
MainWindowViewModel.cs This is my command for binding.
private RelayCommand _getTextCommand;
public ICommand GetTextCommand
{
get
{
if (_getTextCommand == null)
{
_getTextCommand = new RelayCommand(
param => this.GetText(param),
param => true
);
}
return _getTextCommand;
}
}
MainWindow.xaml This is XAML code where i bind my command.
<Button x:Name="getTextButton" Command="{Binding GetTextCommand}" CommandParameter="{Binding ElementName=textTypeSelector, Path=SelectedIndex}"/>
This is the code i am launching in command:
public async void GetText(object o)
{
await Task.Factory.StartNew(() =>
{
// code
});
}

Try this: add a boolean property in view model and implement INotifyPropertyChanged in view model
private bool isEnable = true;
public bool IsEnable
{
get { return isEnable; }
set
{
isEnable = value;
NotifyPropertyChanged();
}
}
public async void GetText(object o)
{
await Task.Factory.StartNew(() =>
{
IsEnable = false;
});
IsEnable = true;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Bind it to button IsEnable property
<Button x:Name="abc"
Command="{Binding GetTextCommand}"
IsEnabled="{Binding IsEnable}" />
Set IsEnable whereever you want.

Add a boolean to your ViewModel to indicate that the command is executing and set the boolean in your GetText() method.
private bool _isRunning = false;
public async void GetText(object o)
{
await Task.Factory.StartNew(() =>
{
_isRunning = true;
CommandManager.InvalidateRequerySuggested();
// code
_isRunning = false;
CommandManager.InvalidateRequerySuggested();
});
}
public bool CanGetText(object o){
return ! _isRunning;
}
Then change your RelayCommand to the following
_getTextCommand = new RelayCommand(this.GetText,CanGetText);

The problem is that you are passing true for the CanExecute delegate. Pass it a method that will execute every time it needs evaluation, and within that method you can test to see whether the Command should be executable or otherwise.

Here is an implementation that I'm using. It doesn't need an additional property in the ViewModel.
public sealed class AsyncDelegateCommand : ICommand
{
private readonly Func<bool> _canExecute;
private readonly Func<Task> _executeAsync;
private Task _currentExecution;
public AsyncDelegateCommand(Func<Task> executeAsync)
: this(executeAsync, null)
{
}
public AsyncDelegateCommand(Func<Task> executeAsync, Func<bool> canExecute)
{
if (executeAsync == null) throw new ArgumentNullException("executeAsync");
_executeAsync = executeAsync;
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
if (_currentExecution != null && !_currentExecution.IsCompleted)
{
return false;
}
return _canExecute == null || _canExecute();
}
public async void Execute(object parameter)
{
try
{
_currentExecution = _executeAsync();
await _currentExecution;
}
finally
{
_currentExecution = null;
CommandManager.InvalidateRequerySuggested();
}
}
}

Related

WPF Command bindings not updating button enabled state

Simple RelayCommand defined as follows:
public class RelayCommand : IDelegateCommand
{
readonly Predicate<object> _canExecute;
readonly Action<object> _execute;
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
: this(canExecute, execute, true)
{
}
public RelayCommand(Predicate<object> canExecute, Action<object> execute, bool isCommandAllowed)
{
_canExecute = canExecute;
_execute = execute;
IsAllowed = isCommandAllowed;
}
public void RaiseCanExecuteChanged()
{
CanExecuteChanged(this, EventArgs.Empty);
}
#region ICommand Members
public virtual bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public event EventHandler CanExecuteChanged = delegate { };
public virtual void Execute(object parameter)
{
_execute(parameter);
}
IDelegateCommand is defined as follows:
public interface IDelegateCommand : ICommand
{
void RaiseCanExecuteChanged();
}
Is bound to a WPF Button as follows:
<Button Command="{Binding StartSimulationCommand}" Content="Start Simulation"/>
And corresponding ViewModel usage of the Command is given as follows:
public class MainViewModel
{
// missing irrelevant bits
public ICommand StartSimulationCommand
{
get { return new RelayCommand(arg => true, arg =>
{
var inputValidationResponse = ValidateInputs();
if (!string.IsNullOrEmpty(inputValidationResponse))
{
_logger.Error(inputValidationResponse);
return;
}
// this method opens a websocket and if that operation is
// successful, property called IsWebSocketOpen is updated.
OpenWebSocketChannel();
// update command states
StopSimulationCommand.RaiseCanExecuteChanged();
});
}
}
public RelayCommand StopSimulationCommand
{
get { return new RelayCommand(arg => IsWebSocketOpened, arg => { CloseWebSocketChannel(); }); }
}
private bool _isWebSocketOpened;
public bool IsWebSocketOpened {
get { return _isWebSocketOpened; }
set { SetField(ref _isWebSocketOpened, value, "IsWebSocketOpened"); }
}
}
When I invoke StopSimulationCommand.RaiseCanExecuteChanged, the state of the button bound to StopSimulationCommand does not changed to enabled, even through the predicate for that command now returns true.
What did I miss?
You are creating a new instance of the RelayCommand in the setter of the StopSimulationCommand. You should create the command once in the constructor of the view model class:
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel ()
{
StopSimulationCommand = new RelayCommand(arg => IsWebSocketOpened, arg => { CloseWebSocketChannel(); });
}
public RelayCommand StopSimulationCommand { get; private set; }
}

RoutedCommand replacement in uwp

I need to create an RoutedCommand in my custome control. I had used RoutedCommands in wpf but in uwp there is no RoutedCommand class. Whats the replacement for this?
[Edit] It seems that the whole CommandBinding which is supported by the RoutedCommand is gone in uwp! Since there also exists no IInputElement which was implemented by the FrameworkElement
https://msdn.microsoft.com/en-us/library/ms752070(v=vs.100).aspx
The answer might be a RelayCommand, which also implements ICommand
public class RelayCommand : ICommand
{
private Action _handler;
public RelayCommand(Action handler)
{
_handler = handler;
}
public RelayCommand(Action handler, Func<bool> p) : this(handler)
{
this.p = p;
}
private bool _isEnabled;
private Func<bool> p;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
if (value != _isEnabled)
{
_isEnabled = value;
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
}
public bool CanExecute(object parameter)
{
//return IsEnabled;
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_handler();
}
}

WPF MVVM command canexecute enable/disable button

I want to enable RibbonButton when textbox property text isn't null. Disable RibbonButton when textbox property text is null. I want to use CanExecute method in ICommand for it. How can I do it?
View:
<Custom:RibbonButton
LargeImageSource="..\Shared\img\save_diskete.png"
Label="Save"
Command="{Binding ButtonCommand}">
</Custom:RibbonButton>
ViewModel
class KomentarViewModel:BaseViewModel
{
#region Data
private ICommand m_ButtonCommand;
public ICommand ButtonCommand
{
get
{
return m_ButtonCommand;
}
set
{
m_ButtonCommand = value;
}
}
private string textKomentar;
public string TextKomentar
{
get
{
return this.textKomentar;
}
set
{
// Implement with property changed handling for INotifyPropertyChanged
if (!string.Equals(this.textKomentar, value))
{
textKomentar = value;
OnPropertyChanged("TextKomentar");
}
}
}
private ObservableCollection<Komentar> allCommentsInc;
public ObservableCollection<Komentar> AllCommentsInc
{
get
{
return allCommentsInc;
}
set
{
allCommentsInc = value;
OnPropertyChanged("AllCommentsInc");
}
}
public int idIncident { get; private set; }
public Incident incident { get; private set; }
#endregion
#region Constructor
public KomentarViewModel(int id)
{
CC_RK2Entities context = new CC_RK2Entities();
this.idIncident = id;
AllCommentsInc = new ObservableCollection<Komentar>(context.Komentar.Where(a => a.Incident_id == idIncident));
incident = context.Incident.Where(a => a.id == idIncident).First();
//ButtonCommand = new RelayCommand(new Action<object>(ShowMessage));
}
#endregion
#region Methods
//ukaz napsany text
public void ShowMessage(object obj)
{
//MessageBox.Show(obj.ToString());
MessageBox.Show(this.TextKomentar);
}
}
RelayCommand
namespace Admin.Shared.Commands
{
class RelayCommand : ICommand
{
private Action<object> _action;
public RelayCommand(Action<object> action)
{
_action = action;
}
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action(parameter);
}
#endregion
}
}
You need to modify your RelayCommand class like this
class RelayCommand : ICommand
{
private Action<object> _action;
private Func<bool> _func;
public RelayCommand(Action<object> action,Func<bool> func)
{
_action = action;
_func = func;
}
public void RaiseCanExecuteChanged()
{
if(CanExecuteChanged!=null)
CanExecuteChanged(this,new EventArgs());
}
#region ICommand Members
public bool CanExecute(object parameter)
{
if (_func != null)
return _func();
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action(parameter);
}
#endregion
}
Initialize ButtonCommand as
ButtonCommand = new RelayCommand((s) => ShowMessage(s),()=>!string.IsNullOrEmpty(TextKomentar));
RaiseCanExcuteChanged from the setter of Text property
public string TextKomentar
{
get
{
return this.textKomentar;
}
set
{
// Implement with property changed handling for INotifyPropertyChanged
if (!string.Equals(this.textKomentar, value))
{
textKomentar = value;
OnPropertyChanged("TextKomentar");
}
ButtonCommand.RaiseCanExecuteChanged();
}
}
implement this for canexecute:
public bool CanExecute(object parameter)
{if(thistext available)
return true;
else
return false;
}
Since, CanExecuteChanged is raised when the CanExecute method of an ICommand gets changed. it gets invoked when some command that could change canexecute.
and can execute changed should be changed to this:
public event EventHandler CanExecuteChanged {
add {
CommandManager.RequerySuggested += value;
}
remove {
CommandManager.RequerySuggested -= value;
}
}
EDIT
in your view model constructor:
m_ButtonCommand= new RelayCommand(Submit, CanSubmit);
now method for this submit:
private bool CanSubmit(object obj)
{
if(thistext available)
return true;
else
return false;
}
public void Submit(object _)
{//... code}
public event EventHandler CanExecuteChanged {
add {
CommandManager.RequerySuggested += value;
}
remove {
CommandManager.RequerySuggested -= value;
}
}
do it like this.
In straightforward words, you need the following:
Let's first create our own delegate command:
public class DelegateCommand : DelegateCommandBase
{
private Action _executeMethod;
private Func<bool> _canExecute;
public DelegateCommand(Action executeMethod)
: this(executeMethod, () => true) {}
public DelegateCommand(Action executeMethod, Func<bool> _canExecute): base()
{
if (executeMethod == null || _canExecute == null) {
throw new ArgumentNullException(nameof(executeMethod),
Resources.DelegateCommandDelegatesCannotBeNull);
}
_executeMethod = executeMethod;
_canExecute = _canExecute;
}
public void Execute() => _executeMethod();
public bool CanExecute() => _canExecute();
protected override void Execute(object parameter) => Execute();
protected override bool CanExecute(object parameter) => CanExecute();
public DelegateCommand ObservesProperty<T>(Expression<Func<T>> propertyExpression)
{
ObservesPropertyInternal(propertyExpression);
return this;
}
public DelegateCommand ObservesCanExecute(Expression<Func<bool>> canExecuteExpression)
{
_canExecute = canExecuteExpression.Compile();
ObservesPropertyInternal(canExecuteExpression);
return this;
}
}
Here, DelegateCommandBase is actually from Prism.Commands namespace.
If you don't use Prism as an MVVM framework for WPF, you can create your own copy of DelegateCommandBase (look for the solution here).
In your View Model, create a member with type DelegateCommand and initialize it in the constructor:
public class MyViewModel
{
private DelegateCommand _okCommand;
public DelegateCommand OkCommand
{
get => _okCommand;
set => SetProperty(ref _okCommand, value);
}
public MyViewModel()
{
OkCommand = new PrismCommands.DelegateCommand(OkCommandHandler,
OkCanExecuteCommandHandler);
}
private void OkCommandHandler()
{
// ...
}
// This is important part: need to return true/false based
// on the need to enable or disable item
private bool OkCanExecuteCommandHandler() =>
return some_condition_to_enable_disable_item;
}
Note: make sure to raise execution changed event, every time something changes that can affect some_condition_to_enable_disable_item condition behavior.
For example, in the case of Prism, you can call RaiseCanExecuteChanged method once a change happens related to the condition (in our case OkCommand.RaiseCanExecuteChanged();).
Small hint: for Telerik WPF Controls, you need to call InvalidateCanExecute() instead of RaiseCanExecuteChanged().
Finally, our XAML will look like this:
<Button x:Name="btnOk"
Content="Ok"
Command="{Binding OkCommand}"/>
Last time I used Microsoft.Practices.Prism.Commands namesapce from Microsoft.Practices.Prism.dll. Class DelegateCommand has own RaiseCanExecuteChanged() method. So the benifit is you don't have to write yout own implementation of ICommand.
XAML:
<StackPanel>
<CheckBox IsChecked="{Binding IsCanDoExportChecked}" />
<Button Command="{Binding ExportCommand}" Content="Export" />
</StackPanel>
ViewModel:
public class ViewModel
{
public DelegateCommand ExportCommand { get; }
public ViewModel()
{
ExportCommand = new DelegateCommand(Export, CanDoExptor);
}
private void Export()
{
//logic
}
private bool _isCanDoExportChecked;
public bool IsCanDoExportChecked
{
get { return _isCanDoExportChecked; }
set
{
if (_isCanDoExportChecked == value) return;
_isCanDoExportChecked = value;
ExportCommand.RaiseCanExecuteChanged();
}
}
private bool CanDoExptor()
{
return IsCanDoExportChecked;
}
}

Relay Command can execute and a Task

i want to start a task when a relay command is called, however i want to disable the button as long as that task is running
take this example
private ICommand update;
public ICommand Update
{
get
{
if (update == null)
{
update = new RelayCommand(
param => Task.Factory.StartNew(()=> StartUpdate()),
param => true); //true means the button will always be enabled
}
return update;
}
}
what is the best way to check if that task is running?
here is my solution but not sure if its the best way
class Vm : ObservableObject
{
Task T;
public Vm()
{
T = new Task(() => doStuff());
}
private ICommand myCommand;
public ICommand MyCommand
{
get { return myCommand ?? (myCommand = new RelayCommand( p => { T = new Task(() => doStuff()); T.Start(); }, p => T.Status != TaskStatus.Running)); }
}
private void doStuff()
{
System.Threading.Thread.Sleep(5000);
}
}
Update : Every answer here works fine, but still they dont agree with each other, and i just reached a 100 reputation , i start a bounty whenever i reach 100, so what i am looking for is an implementation for an optimal non memory leaking asynchronous RelayCommand that executes within a task in .net 4.0
I strongly recommend that you avoid new Task as well as Task.Factory.StartNew. The proper way to start an asynchronous task on a background thread is Task.Run.
You can create an asynchronous RelayCommand easily using this pattern:
private bool updateInProgress;
private ICommand update;
public ICommand Update
{
get
{
if (update == null)
{
update = new RelayCommand(
async () =>
{
updateInProgress = true;
Update.RaiseCanExecuteChanged();
await Task.Run(() => StartUpdate());
updateInProgress = false;
Update.RaiseCanExecuteChanged();
},
() => !updateInProgress);
}
return update;
}
}
I think, you can use this implementation of AsyncCommand.
public class AsyncCommand : ICommand, IDisposable
{
private readonly BackgroundWorker _backgroundWorker = new BackgroundWorker {WorkerSupportsCancellation = true};
private readonly Func<bool> _canExecute;
public AsyncCommand(Action action, Func<bool> canExecute = null, Action<object> completed = null,
Action<Exception> error = null)
{
_backgroundWorker.DoWork += (s, e) =>
{
CommandManager.InvalidateRequerySuggested();
action();
};
_backgroundWorker.RunWorkerCompleted += (s, e) =>
{
if (completed != null && e.Error == null)
completed(e.Result);
if (error != null && e.Error != null)
error(e.Error);
CommandManager.InvalidateRequerySuggested();
};
_canExecute = canExecute;
}
public void Cancel()
{
if (_backgroundWorker.IsBusy)
_backgroundWorker.CancelAsync();
}
public bool CanExecute(object parameter)
{
return _canExecute == null
? !_backgroundWorker.IsBusy
: !_backgroundWorker.IsBusy && _canExecute();
}
public void Execute(object parameter)
{
_backgroundWorker.RunWorkerAsync();
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_backgroundWorker != null)
_backgroundWorker.Dispose();
}
}
}
So your solution to use RelayCommand almost works. The problem is that the UI won't immediately update after the task finishes running. This is because something needs to trigger the ICommand's CanExecuteChanged event in order for the UI to properly update.
One way to solve this problem is by creating a new kind of ICommand. For example:
class AsyncRelayCommand : ICommand
{
private Func<object, Task> _action;
private Task _task;
public AsyncRelayCommand(Func<object,Task> action)
{
_action = action;
}
public bool CanExecute(object parameter)
{
return _task == null || _task.IsCompleted;
}
public event EventHandler CanExecuteChanged;
public async void Execute(object parameter)
{
_task = _action(parameter);
OnCanExecuteChanged();
await _task;
OnCanExecuteChanged();
}
private void OnCanExecuteChanged()
{
var handler = this.CanExecuteChanged;
if (handler != null)
handler(this, EventArgs.Empty);
}
}
Now your view model can do something like the following
private ICommand myCommand;
public ICommand MyCommand
{
get { return myCommand ?? (myCommand = new AsyncRelayCommand(p => Task.Factory.StartNew(doStuff))); }
}
private void doStuff()
{
System.Threading.Thread.Sleep(5000);
}
Or you could make your doStuff function an "async" function like so
private ICommand myCommand2;
public ICommand MyCommand2
{
get { return myCommand2 ?? (myCommand2 = new AsyncRelayCommand(p => doStuff2())); }
}
private async Task doStuff2()
{
await Task.Delay(5000);
}
You could have a static variable IsRunning, which you can set to True when your task starts, to false when it finishes, and just bind that enabled button to the state of the IsRunning
I am trying to avoid Prism library to keep my control simple as possible from point of view of mount of reference assemblies and I ended up with this solution
_cmd = new RelayCommand(async delegate
{
await Task.Run(() => <YourMethod>());
}, delegate { return !IsInProgress; }) );
Seems to be working well. (if you don't need to pass commandParameter in). Unfortunately this is still a problem.
RelayCommand class inherits from ICommand
public class RelayCommand : ICommand
{
private Action<object> _execute;
private Predicate<object> _canExecute;
private event EventHandler CanExecuteChangedInternal;
public RelayCommand(Action<object> execute)
: this(execute, DefaultCanExecute)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
if (canExecute == null)
{
throw new ArgumentNullException("canExecute");
}
_execute = execute;
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
CanExecuteChangedInternal += value;
}
remove
{
CommandManager.RequerySuggested -= value;
CanExecuteChangedInternal -= value;
}
}
public bool CanExecute(object parameter)
{
return _canExecute != null && _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public void OnCanExecuteChanged()
{
EventHandler handler = CanExecuteChangedInternal;
if (handler != null)
{
//DispatcherHelper.BeginInvokeOnUIThread(() => handler.Invoke(this, EventArgs.Empty));
handler.Invoke(this, EventArgs.Empty);
}
}
public void Destroy()
{
_canExecute = _ => false;
_execute = _ => { return; };
}
private static bool DefaultCanExecute(object parameter)
{
return true;
}
}

ICommand MVVM implementation

So in this particular MVVM implementation I'm doing, I need several commands. I really got tired of implementing the ICommand classes one by one, so I came up with a solution, but I don't know how good it is, so the input of any WPF expert here will be greatly appreciated. And if you could provide a better solution, even better.
What I did is a single ICommand class and two delegates which take an object as a parameter, one delegate is void (for OnExecute), the other bool (for OnCanExecute). So in the constructor of my ICommand (which is called by the ViewModel class) I send the two methods, and on each ICommand method I invoke the delegates' methods.
It works really good, but I'm not sure if this is a bad way to do it, or if there's a better way. Below is the complete code, any input will be greatly appreciated, even negative, but please be constructive.
ViewModel:
public class TestViewModel : DependencyObject
{
public ICommand Command1 { get; set; }
public ICommand Command2 { get; set; }
public ICommand Command3 { get; set; }
public TestViewModel()
{
this.Command1 = new TestCommand(ExecuteCommand1, CanExecuteCommand1);
this.Command2 = new TestCommand(ExecuteCommand2, CanExecuteCommand2);
this.Command3 = new TestCommand(ExecuteCommand3, CanExecuteCommand3);
}
public bool CanExecuteCommand1(object parameter)
{
return true;
}
public void ExecuteCommand1(object parameter)
{
MessageBox.Show("Executing command 1");
}
public bool CanExecuteCommand2(object parameter)
{
return true;
}
public void ExecuteCommand2(object parameter)
{
MessageBox.Show("Executing command 2");
}
public bool CanExecuteCommand3(object parameter)
{
return true;
}
public void ExecuteCommand3(object parameter)
{
MessageBox.Show("Executing command 3");
}
}
ICommand:
public class TestCommand : ICommand
{
public delegate void ICommandOnExecute(object parameter);
public delegate bool ICommandOnCanExecute(object parameter);
private ICommandOnExecute _execute;
private ICommandOnCanExecute _canExecute;
public TestCommand(ICommandOnExecute onExecuteMethod, ICommandOnCanExecute onCanExecuteMethod)
{
_execute = onExecuteMethod;
_canExecute = onCanExecuteMethod;
}
#region ICommand Members
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return _canExecute.Invoke(parameter);
}
public void Execute(object parameter)
{
_execute.Invoke(parameter);
}
#endregion
}
This is almost identical to how Karl Shifflet demonstrated a RelayCommand, where Execute fires a predetermined Action<T>. A top-notch solution, if you ask me.
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);
}
}
This could then be used as...
public class MyViewModel
{
private ICommand _doSomething;
public ICommand DoSomethingCommand
{
get
{
if (_doSomething == null)
{
_doSomething = new RelayCommand(
p => this.CanDoSomething,
p => this.DoSomeImportantMethod());
}
return _doSomething;
}
}
}
Read more:
Josh Smith (introducer of RelayCommand): Patterns - WPF Apps With The MVVM Design Pattern
I have written this article about the ICommand interface.
The idea - creating a universal command that takes two delegates: one is called when ICommand.Execute (object param) is invoked, the second checks the status of whether you can execute the command (ICommand.CanExecute (object param)).
Requires the method to switching event CanExecuteChanged. It is called from the user interface elements for switching the state CanExecute() command.
public class ModelCommand : ICommand
{
#region Constructors
public ModelCommand(Action<object> execute)
: this(execute, null) { }
public ModelCommand(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region ICommand Members
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return _canExecute != null ? _canExecute(parameter) : true;
}
public void Execute(object parameter)
{
if (_execute != null)
_execute(parameter);
}
public void OnCanExecuteChanged()
{
CanExecuteChanged(this, EventArgs.Empty);
}
#endregion
private readonly Action<object> _execute = null;
private readonly Predicate<object> _canExecute = null;
}
I've just created a little example showing how to implement commands in convention over configuration style. However it requires Reflection.Emit() to be available. The supporting code may seem a little weird but once written it can be used many times.
Teaser:
public class SampleViewModel: BaseViewModelStub
{
public string Name { get; set; }
[UiCommand]
public void HelloWorld()
{
MessageBox.Show("Hello World!");
}
[UiCommand]
public void Print()
{
MessageBox.Show(String.Concat("Hello, ", Name, "!"), "SampleViewModel");
}
public bool CanPrint()
{
return !String.IsNullOrEmpty(Name);
}
}
}
UPDATE: now there seem to exist some libraries like http://www.codeproject.com/Articles/101881/Executing-Command-Logic-in-a-View-Model that solve the problem of ICommand boilerplate code.
#Carlo I really like your implementation of this, but I wanted to share my version and how to use it in my ViewModel
First implement ICommand
public class Command : ICommand
{
public delegate void ICommandOnExecute();
public delegate bool ICommandOnCanExecute();
private ICommandOnExecute _execute;
private ICommandOnCanExecute _canExecute;
public Command(ICommandOnExecute onExecuteMethod, ICommandOnCanExecute onCanExecuteMethod = null)
{
_execute = onExecuteMethod;
_canExecute = onCanExecuteMethod;
}
#region ICommand Members
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return _canExecute?.Invoke() ?? true;
}
public void Execute(object parameter)
{
_execute?.Invoke();
}
#endregion
}
Notice I have removed the parameter from ICommandOnExecute and ICommandOnCanExecute and added a null to the constructor
Then to use in the ViewModel
public Command CommandToRun_WithCheck
{
get
{
return new Command(() =>
{
// Code to run
}, () =>
{
// Code to check to see if we can run
// Return true or false
});
}
}
public Command CommandToRun_NoCheck
{
get
{
return new Command(() =>
{
// Code to run
});
}
}
I just find this way cleaner as I don't need to assign variables and then instantiate, it all done in one go.

Categories