i have the following problem:
I have a relaycommand with a execute an a canexecute method, but everytime i call raisecanexecutechanged(); it calls raisecanexecutechanged in relaycommand, sets a new delegate for it and then returns back to the view model.
The same setup works in another viewmodel. I checked like 1000 times what's different but i don't find anything.
I would really appreciate if you could help me.
public RelayCommand UpdateAMSCommand { get; private set; }
public AMSSettingsViewModel(IEventAggregator eventAggregator)
{
UpdateAMSCommand = new RelayCommand(OnUpdateAMS, CanUpdateAms);
CustomAMSOffices.ListChanged += listChanged;
CustomAMSContacts.ListChanged += listChanged;
}
private void listChanged(object sender, ListChangedEventArgs e)
{
if (sender != null)
{
if (sender is BindingList<CustomAMSOffice>)
{
BindingList<CustomAMSOffice> temp = (BindingList<CustomAMSOffice>)sender;
if (temp.Count > _amsOfficesItemsCounter)
{
_amsOfficesItemsCounter = temp.Count;
for (int i = 0; i < temp.Count; i++)
{
temp[i].ErrorsChanged += RaiseCanExecuteChanged;
}
}
}
else if (sender is BindingList<CustomAMSContact>)
{
BindingList<CustomAMSContact> temp = (BindingList<CustomAMSContact>)sender;
if (temp.Count > _amsContactsItemsCounter)
{
_amsContactsItemsCounter = temp.Count;
for (int i = 0; i < temp.Count; i++)
{
temp[i].ErrorsChanged += RaiseCanExecuteChanged;
}
}
}
}
UpdateAMSCommand.RaiseCanExecuteChanged();
}
private void RaiseCanExecuteChanged(object sender, DataErrorsChangedEventArgs e)
{
UpdateAMSCommand.RaiseCanExecuteChanged();
}
private bool CanUpdateAms()
{
foreach (var cao in CustomAMSOffices)
{
if (!cao.Check() || cao.HasErrors)
{
return false;
}
}
foreach (var cac in CustomAMSContacts)
{
if (!cac.Check() || cac.HasErrors)
{
return false;
}
}
return true;
}
Edit:
the relaycommand i use: https://github.com/briannoyes/WPFMVVM-StarterCode/blob/master/ZzaDashboard/ZzaDashboard/RelayCommand.cs
Ok, I'm just going to copy paste some code that I have in use, so that you should be able to pop these into your project and use.
First off, the RelayCommand() class. I lifted this code from this msdn page:
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
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
}
Now our ModelView.cs class needs to inherit from INotifyPropertyChangedand will have our RaisePropertyChanged(). Now I usually make just make this a it's own file and have all my ModelViews inherit from it so the code is a little cleaner, but you can do as you please.
Here's how I have it setup though:
BaseViewModel.cs:
public class BaseViewModel : INotifyPropertyChanged
{
internal void RaisePropertyChanged(string prop)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
public event PropertyChangedEventHandler PropertyChanged;
// Any other code we want all model views to have
}
Now for our MainViewModel.cs we will just inherit from BaseViewModel, add our event handlers in, and run it!
Example: ServerViewModel.cs
public class ServerViewModel : BaseViewModel
{
public RelayCommand BroadcastMessageCommand { get; set; }
private string _broadcastmessage;
public string broadcastmessage
{
get { return _broadcastmessage; }
set { _broadcastmessage = value; RaisePropertyChanged("broadcastmessage"); }
}
Server server;
public ServerViewModel()
{
server = new Server();
server.run();
BroadcastMessageCommand = new RelayCommand(BroadcastMessage, CanBroadcast);
}
private bool CanBroadcast(object param)
{
if (string.IsNullOrWhiteSpace(broadcastmessage))
return false;
if (!server.running)
return false;
return true;
}
public void BroadcastMessage(object param)
{
server.BroadcastMessage(broadcastmessage);
broadcastmessage = "";
RaisePropertyChanged("broadcastmessage");
}
}
Now anything in our MainView.xaml that is bound with Command="{Binding broadcastmessage}" will update appropriately. In my case I have this bound to a button and the button will be disabled if there message is empty, or if we are not connected to the server.
Hopefully that's enough code example to get you headed in the right direction! Let me know if you have any questions on it.
Let's try simplifying the code as much as we can until we get this working properly, and then we will slowly add code back until we find the code(s) that are causing trouble.
So let's reduce this to it's barebones and see if we have any success. Try this code:
public RelayCommand UpdateAMSCommand { get; private set; }
public AMSSettingsViewModel(IEventAggregator eventAggregator)
{
UpdateAMSCommand = new RelayCommand(OnUpdateAMS, CanUpdateAms);
CustomAMSOffices.ListChanged += listChanged;
CustomAMSContacts.ListChanged += listChanged;
}
private void listChanged(object sender, ListChangedEventArgs e)
{
UpdateAMSCommand.RaiseCanExecuteChanged();
}
private void RaiseCanExecuteChanged(object sender, DataErrorsChangedEventArgs e)
{
UpdateAMSCommand.RaiseCanExecuteChanged();
}
// This will simply flip from true to false every time it is called.
private bool _canupdate = false;
private bool CanUpdateAms()
{
_canupdate = !_canupdate;
return _canupdate;
}
Edit: I don't know why it doesn't work.
Related
My question is how go show progress on progressbar if I have to call my method only once? I am working on MVVM project in WPF. I have to display progress of my loop on the progressBar. If i have got something like this in Model class, my ProgressBar is updating correctly, but only once
public double progressBarValue;
public string inputText;
public int quantityOfNumbers
{
get;
set;
}
public void inputTextToInt(string inputText)
{
progressBarValue = Convert.ToInt32(inputText);
quantityOfNumbers = Convert.ToInt32(inputText);
//work();
}
But if I've tried to updating in real time my progressbar, with these code:
public void inputTextToInt(string inputText)
{
//progressBarValue = Convert.ToInt32(inputText);
quantityOfNumbers = Convert.ToInt32(inputText);
work();
}
private async void work()
{
RandNumbers randNumbers = new RandNumbers(quantityOfNumbers);
var progress = new Progress<double>(value =>
{
progressBarValue = value;
Console.WriteLine(progressBarValue);
});
await Task.Run(() => randNumbers.RandAllNumbers(progress));
}
There isn't any progress on my ProgressBar. I've checked on console and in this line my progressBarValue is changing correctly But it isn't sending to my ViewModel class.
progressBarValue = value;
And this is my ViewModel class:
private ModelTME_App model = new ModelTME_App();
public string inputText
{
get { return model.inputText; }
set { model.inputText = value;
onPropertyChanged(nameof(inputText));
}
}
public double progressBarValue
{
get {
Console.WriteLine(model.progressBarValue);
return model.progressBarValue;
}
}
private ICommand inputTextToInt = null;
public ICommand InputTextToInt
{
get
{
if(inputTextToInt == null)
{
inputTextToInt = new RelayCommand(
(object o) =>
{
model.inputTextToInt(inputText);
onPropertyChanged(nameof(progressBarValue));
},
(object o) =>
{
return model.progressBarValue == 0;
});
}
return inputTextToInt;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void onPropertyChanged(string nameOfProperty)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(nameOfProperty));
}
}
}
My RelayCommandClass
public class RelayCommand : ICommand
{
private Action<object> execute;
private Func<object, bool> canExecute;
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
if (execute == null)
{
throw new ArgumentNullException(nameof(execute));
}
else
{
this.execute = execute;
}
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public bool CanExecute(object parameter)
{
if(canExecute == null)
{
return true;
}
else
{
return canExecute(parameter);
}
}
public void Execute(object parameter)
{
execute(parameter);
}
}
The Binding.Source must always raise the INotifyPropertyChanged.PropertyChanged event to trigger the Binding to update update the Binding.Target.
You should avoid binding to the Model via a delegating property. The Model shouldn't expose an API to allow this (data hiding).
The proper pattern would be to implement a ProgressChanged event in the Model that the View Model can observe.
Also avoid a few code smells:
Never return void from an async method except the method is an event handler. An async method must return Task or Task<T>. The returned Task must be propagated and awaited up the call chain.
Avoid capturing member variable in lambdas. This can create a memory leak in certain situations
Pass values from View Model to Model using methods. Exposing all Model properties to the View Model exposes too much information details (like which properties to set to change the Model to a valid state). Instead make public method request the required data as parameters or parameter objects. The properties should be private (except those required to configure the object).
Using member and parameter names like ProgressBar... or InputText... gives a hint that your model is not properly designed. Since the model is unaware of the view, it is not interested in progress bars or input text too. Could be a simple naming issue or a serious design issue.
You should try to implement the official C# Naming Guidelines
Model.cs
The ProgressChanged event is defined using the ProgressChangedEventArgs.
class Model
{
public event EventHandler<ProgressChangedEventArgs> ProgressChanged;
private double ProgressPercentage { get; set; }
private string NumericText { get; set; }
private int QuantityOfNumbers { get; set; }
protected virtual void OnProgressCHanged(double percentage)
=> this.ProgressChanged?.Invoke(new ProgressChangedEventArgs(percentage, string.Empty);
public async Task<int> ToIntAsync(string numericText)
{
NumericText = numericText;
QuantityOfNumbers = Convert.ToInt32(NumericText);
await WorkAsync();
return QuantityOfNumbers;
}
private async Task WorkAsync()
{
// Can you guarantee that this method is called from the UI thread?
var progress = new Progress<double>(value =>
{
ProgressPercentage = value;
Console.WriteLine(ProgressBarValue);
OnProgressChanged(ProgressBarValue);
});
// Avoid capturing member variables in lambdas
int quantityOfNumbers = QuantityOfNumbers;
await Task.Run(() =>
{
var randNumbers = new RandNumbers(quantityOfNumbers);
randNumbers.RandAllNumbers(progress));
});
}
}
ViewModel.cs
class ViewModel : INotifyPropertyChanged
{
private Model _model;
// TODO::Let property raise PropertyChanged event
public double ProgressValue { get; set; }
public ICommand InputTextToIntCommand => new RelayCommand(ExecuteInputTextToIntCommandAsync);
// TODO::Let property raise PropertyChanged event
public string NumericText { get; set;}
public ViewModel()
{
_model = new Model();
}
// Make sure RelayCommand can execute async delegates
private async Task ExecuteInputTextToIntCommandAsync()
{
_model.PropgressChnaged += OnProgressChanged;
// Pass value to model
var quantityOfNumbersResult = await _model.ToIntAsync(this.NumericText);
}
private void OnProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.ProgressValue = e.ProgressPercentage;
if (this.ProgressValue >= 100)
{
_model.PropgressChnaged -= OnProgressChanged;
}
}
}
A simple async command implementation that allows cancellation (based on the posted example):
public class RelayCommand : ICommand
{
private CancellationTokenSource cancellationTokenSource;
private readonly Func<object, Task> executeAsync;
private readonly Func<object, CancellationToken, Task> executeCancellableAsync;
private Action<object> execute;
private Func<object, bool> canExecute;
public RelayCommand(Func<object, CancellationToken, Task> executeCancellableAsync, Func<object, bool> canExecute)
{
this.executeCancellableAsync = executeCancellableAsync;
this.canExecute = canExecute;
}
public RelayCommand(Func<object, Task> executeAsync, Func<object, bool> canExecute)
{
this.executeAsync = executeAsync;
this.canExecute = canExecute;
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
if (execute == null)
{
throw new ArgumentNullException(nameof(execute));
}
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
public bool CanExecute(object parameter)
{
return canExecute?.Invoke(parameter) ?? true;
}
public void Execute(object parameter)
{
_ = ExecuteAsync(parameter);
}
public async Task ExecuteAsync(object commandParameter)
{
using (this.cancellationTokenSource = new CancellationTokenSource())
{
await ExecuteAsync(commandParameter, this.cancellationTokenSource.Token);
}
}
public Task ExecuteAsync(object commandParameter, CancellationToken cancellationToken)
{
if (this.executeCancellableAsync is not null)
{
return this.executeCancellableAsync.Invoke(commandParameter, cancellationToken);
}
else if (this.executeAsync is not null)
{
return this.executeAsync.Invoke(commandParameter);
}
else
{
this.execute.Invoke(commandParameter);
return Task.CompletedTask;
}
}
public void Cancel()
{
this.cancellationTokenSource?.Cancel();
}
}
So I'm making a slot machine in C#. I'm really new to C# and I am really bad at it.
Up to this point my project has been going fine. But now I want to randomize the images shown, when the 'spin' Button is clicked.
I've tried a lot of different things. The solutions I have found are either with the use of a PictureBox or nothing close to what I'm working on.
If someone could take a look at my code and push me in the right direction, I would be really grateful.
Thanks in advance!
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
namespace Prb.Slot.Machine.Wpf
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
int CoinInsert = 0;
private static Random random;
public enum SlotMachineIcon
{
Banana,
BigWin,
Cherry,
Lemon,
Orange,
Plum,
Seven,
Strawberry,
Watermelon
}
public MainWindow()
{
InitializeComponent();
}
private static void Init()
{
if (random == null) random = new Random();
}
public static int Random(int min, int max)
{
Init();
return random.Next(min, max);
}
void UpdateImage(Image wpfImage, SlotMachineIcon newIcon)
{
DirectoryInfo directoryInfo = new DirectoryInfo(Environment.CurrentDirectory);
directoryInfo = new DirectoryInfo(directoryInfo.Parent.Parent.Parent.Parent.FullName);
Uri uri = new Uri($"{directoryInfo.FullName}/images/{newIcon}.png");
wpfImage.Source = new BitmapImage(uri);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
lblCoinsInserted.Content = 0;
lblCoinBalance.Content = 0;
lblCoinsWon.Content = 0;
UpdateImage(imgLeft, SlotMachineIcon.Cherry);
UpdateImage(imgMiddle, SlotMachineIcon.Banana);
UpdateImage(imgRight, SlotMachineIcon.Seven);
}
private void btnInsertCoins_Click(object sender, RoutedEventArgs e)
{
int.TryParse(txtInsertCoins.Text, out int InsertCoins);
if (InsertCoins > 0)
{
CoinInsert += int.Parse(txtInsertCoins.Text.ToString());
lblCoinBalance.Content = (int)lblCoinBalance.Content + Convert.ToInt32(txtInsertCoins.Text);
lblCoinsInserted.Content = CoinInsert;
txtInsertCoins.Clear();
}
else
{
MessageBox.Show("Gelieve strikt positieve getallen in te vullen", "Ongeldig aantal munten", MessageBoxButton.OK, MessageBoxImage.Warning);
txtInsertCoins.Clear();
}
}
private void btnSpin_Click(object sender, RoutedEventArgs e)
{
int InsertedCoins = Convert.ToInt32(lblCoinsInserted.Content);
int CoinsBalance = Convert.ToInt32(lblCoinBalance.Content);
/*var v = Enum.GetValues(typeof(SlotMachineIcon));
int number = random.Next(10);*/
if (InsertedCoins == 0 | CoinsBalance == 0)
{
MessageBox.Show("Gelieve eerst munten in te werpen", "Geen munten ingeworpen", MessageBoxButton.OK, MessageBoxImage.Warning);
}
else
{
lblCoinBalance.Content = CoinsBalance - 1;
UpdateImage(imgLeft, SlotMachineIcon.Strawberry);
UpdateImage(imgMiddle, SlotMachineIcon.Watermelon);
UpdateImage(imgRight, SlotMachineIcon.Watermelon);
}
}
}
}
Edit: moved out random declaration as #EmondErno pointed it out.
This method returns a random icon every time you call it:
private Random random = new();
private SlotMachineIcon GetRandomIcon()
{
return (SlotMachineIcon)random.Next(10); //don't forget to update this number if you add or remove icons
}
Then call it in every UpdateImage method like:
UpdateImage(imgLeft, GetRandomIcon());
UpdateImage(imgMiddle, GetRandomIcon());
UpdateImage(imgRight, GetRandomIcon());
You're trying to do everything in the code behind, which is a terrible mistake for many reasons, among which your program will get hard to maintain read and update at some point and you are tight coupling the view and the logic of your program. You want to follow the MVVM pattern and put only in the code behind only the logic of the view (no data).
Also in your code, you're reinventing the updating system that already exists in WPF, you want to use the databinding and WPF updating system and get rid of all "update icon" logic in your program.
This is a ViewModel that you could use (.net 5.0):
public class SlotViewModel: ISlotViewModel, INotifyPropertyChanged
{
private Random _r = new();
private int _slotChoicesCount;
private SlotSet _currentSlotSet;
private ICommand _spinCommand;
public SlotViewModel()
{
_slotChoicesCount = Enum.GetNames(typeof(SlotMachineIcon)).Length;
}
private SlotSet GetNewSet() => new(Enumerable.Range(0,3).Select(o => (SlotMachineIcon)_r.Next(_slotChoicesCount)).ToList());
public SlotSet CurrentSlotSet
{
get => _currentSlotSet;
set
{
if (Equals(value, _currentSlotSet)) return;
_currentSlotSet = value;
OnPropertyChanged();
}
}
public ICommand SpinCommand => _spinCommand ??= new DelegateCommand(s => { CurrentSlotSet = GetNewSet(); }, s => true);
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
The most important part is that your ViewModel implements INotifyPropertyChanged. When you uses SpinCommand, it updates the property CurrentSlotSet, and that's all you need to worry about. All the rest is taken care of by the WPF databinding system.
SlotSet is a convenient way to present an immutable result:
public class SlotSet
{
public SlotMachineIcon Left { get; }
public SlotMachineIcon Middle { get; }
public SlotMachineIcon Right { get; }
public SlotSet(IList<SlotMachineIcon> triad)
{
Left = triad[0];
Middle = triad[1];
Right = triad[2];
}
public bool IsWinner => Left == Middle && Middle == Right; // just an example
}
ISlotViewModel is the interface (contract) that your ViewModel satisfies.
public interface ISlotViewModel
{
ICommand SpinCommand { get; }
SlotSet CurrentSlotSet { get; set; }
}
The helper class DelegateCommand:
public class DelegateCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<object> execute, Predicate<object> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
In your View, XAML part, your only need something as simple as this:
<Button Command="{Binding SpinCommand}">spin</Button>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding CurrentSlotSet.Left}"/>
<Image Source="{Binding CurrentSlotSet.Middle}"/>
<Image Source="{Binding CurrentSlotSet.Right}"/>
</StackPanel>
And in the Windows markup has this:
xmlns:local="clr-namespace:SlotMachine"
d:DataContext="{d:DesignInstance Type=local:SlotViewModel, IsDesignTimeCreatable=True}"
The code behind is as simple as this:
public ISlotViewModel ViewModel
{
get { return (ISlotViewModel)DataContext; }
set { DataContext = value; }
}
public SlotView() // or MainWindow
{
InitializeComponent();
ViewModel = new SlotViewModel();
}
The only thing missing here is to add a converter in each of your <Image, which will convert a SlotMachineIcon value into the image path.
PS: if you don't have resharper, you may need this class too:
[AttributeUsage(AttributeTargets.Method)]
public sealed class NotifyPropertyChangedInvocatorAttribute : Attribute
{
public NotifyPropertyChangedInvocatorAttribute() { }
public NotifyPropertyChangedInvocatorAttribute([NotNull] string parameterName)
{
ParameterName = parameterName;
}
[CanBeNull] public string ParameterName { get; }
}
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;
}
}
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;
}
}
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.