I've a listbox that contains some "Application" objects. An "Application" object can be started or stopped.
For each element in my Listbox I've 2 buttons, the first to start application and the second to stop the application.
But, when I click on Start button, the CanExecute of command "Stop" isn't reevaluated until I click inside the application, despite the "CommandManager.InvalidateRequerySuggested();"
<ListBox Grid.Row="1" ItemsSource="{Binding Applications}" Grid.ColumnSpan="3" BorderThickness="0" Background="#FFE8E8E8" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Margin="5,0" Content = "Start"
Command="{Binding StartCommand}"
Visibility="{Binding IsRunning, Converter={Converters:InvertedBoolToVisibilityConverter}}"/>
<Button Margin="5,0" Content = "Stop"
Command="{Binding StopCommand}"
Visibility="{Binding IsRunning, Converter={Converters:BoolToVisibilityConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
On ApplicationViewModel :
public bool IsRunning
{
get
{
return this.m_IsRunning;
}
set
{
this.m_IsRunning = value;
this.OnPropertyChanged("IsRunning");
CommandManager.InvalidateRequerySuggested();
}
}
public ICommand StartCommand
{
get
{
if (this.m_StartCommand == null)
{
this.m_StartCommand = new RelayCommand(p => !this.IsRunning, p => this.Start());
}
return this.m_StartCommand;
}
}
public ICommand StopCommand
{
get
{
if (this.m_StopCommand == null)
{
this.m_StopCommand = new RelayCommand(p => this.IsRunning, p => this.Stop());
}
return this.m_StopCommand;
}
}
My RelayCommand Class :
public class RelayCommand : ICommand
{
#region Member Fields
/// <summary>
/// Contains the list of actions.
/// </summary>
private readonly Action<object> _execute;
/// <summary>
/// Contains the predicate _canExecute.
/// </summary>
private readonly Predicate<object> _canExecute;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="RelayCommand"/> class.
/// </summary>
/// <param name="execute">The execute.</param>
public RelayCommand(Action<object> execute)
: this(null, execute)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RelayCommand"/> class.
/// </summary>
/// <param name="canExecute">The can execute.</param>
/// <param name="execute">The execute.</param>
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
this._execute = execute;
this._canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
/// <summary>
/// Occurs when changes occur that affect whether or not the command should execute.
/// </summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
/// <summary>
/// Defines the method that determines whether the command can execute in its current state.
/// </summary>
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
/// <returns>
/// true if this command can be executed; otherwise, false.
/// </returns>
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return this._canExecute == null ? true : this._canExecute(parameter);
}
/// <summary>
/// Defines the method to be called when the command is invoked.
/// </summary>
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
public void Execute(object parameter)
{
this._execute(parameter);
}
#endregion
}
Try RaiseCanExecuteChanged() of your StopCommand directly in your handler of StartCommand.
If you have implemented the your Command yourself, then you can add RaiseCanExecuteChanged to it like. It will call CanExecuteChanged event
public void RaiseCanExecuteChanged()
{
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
Related
I have a form where users set parameters for a numerical process. Each parameter object has a default value.
public double DefaultValue
{
get => _defaultValue;
set
{
_defaultValue = value;
OnPropertyChanged("DefaultValue");
}
}
Although the property is a double, it might represent a Boolean, or an integer. For most parameters validation is not required, but I have two parameters, Min and Max, which are limited. I must not have Min > Max or Max < Min. I have implemented validation in XAML, which visually warns the user if the data is not valid. The data template for the Min parameter is as follows.
<DataTemplate x:Key="MinParameterDataTemplateThin">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="120"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding DisplayName, StringFormat='{}{0}:'}" Grid.Column="0" Margin="10,5,5,10" VerticalAlignment="Top" TextWrapping="Wrap"
Visibility="{Binding Visibility}" ToolTipService.ShowDuration="20000">
<TextBlock.ToolTip>
<ToolTip DataContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={x:Static RelativeSource.Self}}">
<TextBlock Text="{Binding Description}"/>
</ToolTip>
</TextBlock.ToolTip>
</TextBlock>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<TextBox Name ="MinTextBox" Margin="5" Width="50" VerticalAlignment="Top"
Visibility="{Binding Visibility}" IsEnabled="{Binding IsEnabled}">
<TextBox.Resources>
<validations:BindingProxy x:Key="proxy" Data="{Binding}"/>
</TextBox.Resources>
<TextBox.Text>
<Binding Path="DefaultValue" StringFormat="N2" Mode="TwoWay"
UpdateSourceTrigger="LostFocus"
ValidatesOnExceptions="True"
NotifyOnValidationError="True"
ValidatesOnNotifyDataErrors="True">
<Binding.ValidationRules>
<validations:MaximumValueValidation ValidatesOnTargetUpdated="True">
<validations:MaximumValueValidation.MaxValueWrapper>
<validations:MaxValueWrapper MaxValue="{Binding Data.MaxValue, Source={StaticResource proxy}}"/>
</validations:MaximumValueValidation.MaxValueWrapper>
</validations:MaximumValueValidation>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<TextBlock Text="{Binding UnitSymbol}" Margin="5" VerticalAlignment="Top" Visibility="{Binding Visibility}"/>
</StackPanel>
<Label Name="ValidationLabel" Content="{Binding ElementName=MinTextBox, Path=(Validation.Errors)[0].ErrorContent}" Foreground="Red" Grid.Row="1" VerticalAlignment="Top"/>
</Grid>
</Grid>
</DataTemplate>
There is a similar template for the Max parameter. In addition to the visual warning, I need to prevent the user from saving the data. I would like to have a Boolean IsValid property in the parameter object to test when the user tries to save. How would I bind from the XAML to this IsValid property?
When you see an error appear with a red border, there is a routed error event raised which will bubble up through the visual tree.
When you fix an error then you get the same event raised tells you that the error is fixed.
You can therefore add up errors occur and subtract errors fixed. If you have more than zero you have something needs fixing.
This is the Validation.ErrorEvent
https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.validation.error?view=windowsdesktop-7.0
You can then pass the result to the viewmodel or call a command to pass the event result and your viewmodel does that addition.
Here's some markup and code.
In a parent of all the controls which may error:
<i:Interaction.Triggers>
<UIlib:RoutedEventTrigger RoutedEvent="{x:Static Validation.ErrorEvent}">
<e2c:EventToCommand
Command="{Binding ConversionErrorCommand, Mode=OneWay}"
EventArgsConverter="{StaticResource BindingErrorEventArgsConverter}"
PassEventArgsToCommand="True" />
</UIlib:RoutedEventTrigger>
Not sure this will still be copy paste friendly since it's a bit old now.
public RelayCommand<PropertyError> ConversionErrorCommand
{
get
{
return conversionErrorCommand
?? (conversionErrorCommand = new RelayCommand<PropertyError>
(PropertyError =>
{
if (PropertyError.Added)
{
AddError(PropertyError.PropertyName, PropertyError.Error, ErrorSource.Conversion);
}
FlattenErrorList();
}));
}
}
Converter
public class BindingErrorEventArgsConverter : IEventArgsConverter
{
public object Convert(object value, object parameter)
{
ValidationErrorEventArgs e = (ValidationErrorEventArgs)value;
PropertyError err = new PropertyError();
err.PropertyName = ((System.Windows.Data.BindingExpression)(e.Error.BindingInError)).ResolvedSourcePropertyName;
err.Error = e.Error.ErrorContent.ToString();
// Validation.ErrorEvent fires both when an error is added AND removed
if (e.Action == ValidationErrorEventAction.Added)
{
err.Added = true;
}
else
{
err.Added = false;
}
return err;
}
}
Routedeventtrigger
// This is necessary in order to grab the bubbling routed source changed and conversion errors
public class RoutedEventTrigger : EventTriggerBase<DependencyObject>
{
RoutedEvent routedEvent;
public RoutedEvent RoutedEvent
{
get
{
return routedEvent;
}
set
{
routedEvent = value;
}
}
public RoutedEventTrigger()
{
}
protected override void OnAttached()
{
Behavior behavior = base.AssociatedObject as Behavior;
FrameworkElement associatedElement = base.AssociatedObject as FrameworkElement;
if (behavior != null)
{
associatedElement = ((IAttachedObject)behavior).AssociatedObject as FrameworkElement;
}
if (associatedElement == null)
{
throw new ArgumentException("This only works with framework elements");
}
if (RoutedEvent != null)
{
associatedElement.AddHandler(RoutedEvent, new RoutedEventHandler(this.OnRoutedEvent));
}
}
void OnRoutedEvent(object sender, RoutedEventArgs args)
{
base.OnEvent(args);
args.Handled = true;
}
protected override string GetEventName()
{
return RoutedEvent.Name;
}
}
Event to command is from mvvm light. Which is now deprecated but the code still works.
You might like
MVVM Passing EventArgs As Command Parameter
I think this explains a prism approach:
https://weblogs.asp.net/alexeyzakharov/silverlight-commands-hacks-passing-eventargs-as-commandparameter-to-delegatecommand-triggered-by-eventtrigger
But I think mvvmlight is open source, here's the code for eventtocommand:
// ****************************************************************************
// <copyright file="EventToCommand.cs" company="GalaSoft Laurent Bugnion">
// Copyright © GalaSoft Laurent Bugnion 2009-2016
// </copyright>
// ****************************************************************************
// <author>Laurent Bugnion</author>
// <email>laurent#galasoft.ch</email>
// <date>3.11.2009</date>
// <project>GalaSoft.MvvmLight.Extras</project>
// <web>http://www.mvvmlight.net</web>
// <license>
// See license.txt in this solution or http://www.galasoft.ch/license_MIT.txt
// </license>
// ****************************************************************************
using Microsoft.Xaml.Behaviors;
using System;
using System.Windows;
using System.Windows.Input;
////using GalaSoft.Utilities.Attributes;
namespace GalaSoft.MvvmLight.CommandWpf
{
/// <summary>
/// This <see cref="T:System.Windows.Interactivity.TriggerAction`1" /> can be
/// used to bind any event on any FrameworkElement to an <see cref="ICommand" />.
/// Typically, this element is used in XAML to connect the attached element
/// to a command located in a ViewModel. This trigger can only be attached
/// to a FrameworkElement or a class deriving from FrameworkElement.
/// <para>To access the EventArgs of the fired event, use a RelayCommand<EventArgs>
/// and leave the CommandParameter and CommandParameterValue empty!</para>
/// </summary>
////[ClassInfo(typeof(EventToCommand),
//// VersionString = "5.2.8",
//// DateString = "201504252130",
//// Description = "A Trigger used to bind any event to an ICommand.",
//// UrlContacts = "http://www.galasoft.ch/contact_en.html",
//// Email = "laurent#galasoft.ch")]
public class EventToCommand : TriggerAction<DependencyObject>
{
/// <summary>
/// Identifies the <see cref="CommandParameter" /> dependency property
/// </summary>
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
"CommandParameter",
typeof(object),
typeof(EventToCommand),
new PropertyMetadata(
null,
(s, e) =>
{
var sender = s as EventToCommand;
if (sender == null)
{
return;
}
if (sender.AssociatedObject == null)
{
return;
}
sender.EnableDisableElement();
}));
/// <summary>
/// Identifies the <see cref="Command" /> dependency property
/// </summary>
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(EventToCommand),
new PropertyMetadata(
null,
(s, e) => OnCommandChanged(s as EventToCommand, e)));
/// <summary>
/// Identifies the <see cref="MustToggleIsEnabled" /> dependency property
/// </summary>
public static readonly DependencyProperty MustToggleIsEnabledProperty = DependencyProperty.Register(
"MustToggleIsEnabled",
typeof(bool),
typeof(EventToCommand),
new PropertyMetadata(
false,
(s, e) =>
{
var sender = s as EventToCommand;
if (sender == null)
{
return;
}
if (sender.AssociatedObject == null)
{
return;
}
sender.EnableDisableElement();
}));
private object _commandParameterValue;
private bool? _mustToggleValue;
/// <summary>
/// Gets or sets the ICommand that this trigger is bound to. This
/// is a DependencyProperty.
/// </summary>
public ICommand Command
{
get
{
return (ICommand) GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
/// <summary>
/// Gets or sets an object that will be passed to the <see cref="Command" />
/// attached to this trigger. This is a DependencyProperty.
/// </summary>
public object CommandParameter
{
get
{
return GetValue(CommandParameterProperty);
}
set
{
SetValue(CommandParameterProperty, value);
}
}
/// <summary>
/// Gets or sets an object that will be passed to the <see cref="Command" />
/// attached to this trigger. This property is here for compatibility
/// with the Silverlight version. This is NOT a DependencyProperty.
/// For databinding, use the <see cref="CommandParameter" /> property.
/// </summary>
public object CommandParameterValue
{
get
{
return _commandParameterValue ?? CommandParameter;
}
set
{
_commandParameterValue = value;
EnableDisableElement();
}
}
/// <summary>
/// Gets or sets a value indicating whether the attached element must be
/// disabled when the <see cref="Command" /> property's CanExecuteChanged
/// event fires. If this property is true, and the command's CanExecute
/// method returns false, the element will be disabled. If this property
/// is false, the element will not be disabled when the command's
/// CanExecute method changes. This is a DependencyProperty.
/// </summary>
public bool MustToggleIsEnabled
{
get
{
return (bool) GetValue(MustToggleIsEnabledProperty);
}
set
{
SetValue(MustToggleIsEnabledProperty, value);
}
}
/// <summary>
/// Gets or sets a value indicating whether the attached element must be
/// disabled when the <see cref="Command" /> property's CanExecuteChanged
/// event fires. If this property is true, and the command's CanExecute
/// method returns false, the element will be disabled. This property is here for
/// compatibility with the Silverlight version. This is NOT a DependencyProperty.
/// For databinding, use the <see cref="MustToggleIsEnabled" /> property.
/// </summary>
public bool MustToggleIsEnabledValue
{
get
{
return _mustToggleValue == null
? MustToggleIsEnabled
: _mustToggleValue.Value;
}
set
{
_mustToggleValue = value;
EnableDisableElement();
}
}
/// <summary>
/// Called when this trigger is attached to a FrameworkElement.
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
EnableDisableElement();
}
#if SILVERLIGHT
private Control GetAssociatedObject()
{
return AssociatedObject as Control;
}
#else
/// <summary>
/// This method is here for compatibility
/// with the Silverlight version.
/// </summary>
/// <returns>The FrameworkElement to which this trigger
/// is attached.</returns>
private FrameworkElement GetAssociatedObject()
{
return AssociatedObject as FrameworkElement;
}
#endif
/// <summary>
/// This method is here for compatibility
/// with the Silverlight 3 version.
/// </summary>
/// <returns>The command that must be executed when
/// this trigger is invoked.</returns>
private ICommand GetCommand()
{
return Command;
}
/// <summary>
/// Specifies whether the EventArgs of the event that triggered this
/// action should be passed to the bound RelayCommand. If this is true,
/// the command should accept arguments of the corresponding
/// type (for example RelayCommand<MouseButtonEventArgs>).
/// </summary>
public bool PassEventArgsToCommand
{
get;
set;
}
/// <summary>
/// Gets or sets a converter used to convert the EventArgs when using
/// <see cref="PassEventArgsToCommand"/>. If PassEventArgsToCommand is false,
/// this property is never used.
/// </summary>
public IEventArgsConverter EventArgsConverter
{
get;
set;
}
/// <summary>
/// The <see cref="EventArgsConverterParameter" /> dependency property's name.
/// </summary>
public const string EventArgsConverterParameterPropertyName = "EventArgsConverterParameter";
/// <summary>
/// Gets or sets a parameters for the converter used to convert the EventArgs when using
/// <see cref="PassEventArgsToCommand"/>. If PassEventArgsToCommand is false,
/// this property is never used. This is a dependency property.
/// </summary>
public object EventArgsConverterParameter
{
get
{
return GetValue(EventArgsConverterParameterProperty);
}
set
{
SetValue(EventArgsConverterParameterProperty, value);
}
}
/// <summary>
/// Identifies the <see cref="EventArgsConverterParameter" /> dependency property.
/// </summary>
public static readonly DependencyProperty EventArgsConverterParameterProperty = DependencyProperty.Register(
EventArgsConverterParameterPropertyName,
typeof(object),
typeof(EventToCommand),
new PropertyMetadata(null));
/// <summary>
/// The <see cref="AlwaysInvokeCommand" /> dependency property's name.
/// </summary>
public const string AlwaysInvokeCommandPropertyName = "AlwaysInvokeCommand";
/// <summary>
/// Gets or sets a value indicating if the command should be invoked even
/// if the attached control is disabled. This is a dependency property.
/// </summary>
public bool AlwaysInvokeCommand
{
get
{
return (bool)GetValue(AlwaysInvokeCommandProperty);
}
set
{
SetValue(AlwaysInvokeCommandProperty, value);
}
}
/// <summary>
/// Identifies the <see cref="AlwaysInvokeCommand" /> dependency property.
/// </summary>
public static readonly DependencyProperty AlwaysInvokeCommandProperty = DependencyProperty.Register(
AlwaysInvokeCommandPropertyName,
typeof(bool),
typeof(EventToCommand),
new PropertyMetadata(false));
/// <summary>
/// Provides a simple way to invoke this trigger programatically
/// without any EventArgs.
/// </summary>
public void Invoke()
{
Invoke(null);
}
/// <summary>
/// Executes the trigger.
/// <para>To access the EventArgs of the fired event, use a RelayCommand<EventArgs>
/// and leave the CommandParameter and CommandParameterValue empty!</para>
/// </summary>
/// <param name="parameter">The EventArgs of the fired event.</param>
protected override void Invoke(object parameter)
{
if (AssociatedElementIsDisabled()
&& !AlwaysInvokeCommand)
{
return;
}
var command = GetCommand();
var commandParameter = CommandParameterValue;
if (commandParameter == null
&& PassEventArgsToCommand)
{
commandParameter = EventArgsConverter == null
? parameter
: EventArgsConverter.Convert(parameter, EventArgsConverterParameter);
}
if (command != null
&& command.CanExecute(commandParameter))
{
command.Execute(commandParameter);
}
}
private static void OnCommandChanged(
EventToCommand element,
DependencyPropertyChangedEventArgs e)
{
if (element == null)
{
return;
}
if (e.OldValue != null)
{
((ICommand) e.OldValue).CanExecuteChanged -= element.OnCommandCanExecuteChanged;
}
var command = (ICommand) e.NewValue;
if (command != null)
{
command.CanExecuteChanged += element.OnCommandCanExecuteChanged;
}
element.EnableDisableElement();
}
private bool AssociatedElementIsDisabled()
{
var element = GetAssociatedObject();
return AssociatedObject == null
|| (element != null
&& !element.IsEnabled);
}
private void EnableDisableElement()
{
var element = GetAssociatedObject();
if (element == null)
{
return;
}
var command = GetCommand();
if (MustToggleIsEnabledValue
&& command != null)
{
element.IsEnabled = command.CanExecute(CommandParameterValue);
}
}
private void OnCommandCanExecuteChanged(object sender, EventArgs e)
{
EnableDisableElement();
}
}
}
I think you may need ieventargsconverter
namespace GalaSoft.MvvmLight.CommandWpf
{
/// <summary>
/// The definition of the converter used to convert an EventArgs
/// in the <see cref="EventToCommand"/> class, if the
/// <see cref="EventToCommand.PassEventArgsToCommand"/> property is true.
/// Set an instance of this class to the <see cref="EventToCommand.EventArgsConverter"/>
/// property of the EventToCommand instance.
/// </summary>
////[ClassInfo(typeof(EventToCommand))]
public interface IEventArgsConverter
{
/// <summary>
/// The method used to convert the EventArgs instance.
/// </summary>
/// <param name="value">An instance of EventArgs passed by the
/// event that the EventToCommand instance is handling.</param>
/// <param name="parameter">An optional parameter used for the conversion. Use
/// the <see cref="EventToCommand.EventArgsConverterParameter"/> property
/// to set this value. This may be null.</param>
/// <returns>The converted value.</returns>
object Convert(object value, object parameter);
}
}
This question already has an answer here:
Binding to properties in both the ViewModel and CodeBehind
(1 answer)
Closed 2 years ago.
I want to pass the ViewModel parameter(class variable) when I click the buttons in the View. When specifying a string, everything comes true, but I need to pass a non-string value from the View class(function AddNewField).
Main.xaml:
...
<Button
x:Name="ButtonAddingField"
CommandParameter="{Binding Path=Myprop}"
Command="{Binding Path=Myprop, RelativeSource={RelativeSource AncestorType=UserControl}}" />
...
Main.cs:
...
private Color myprop;
public Color Myprop
{
get => myprop;
}
...
this.DataContext = new FieldCollectionViewModel(fields); // fields - List<*my Model*>
...
FieldCollectionViewModel.cs:
...
private DelegateCommand<object> addFieldCommand;
public ICommand AddFieldCommand {
get {
if (addFieldCommand == null) addFieldCommand = new DelegateCommand<object>(AddNewField);
return addFieldCommand;
}
}
private void AddNewField(object parameter)
{
// !!! parameter = ALWAYS NULL
}
...
and my DelegateCommand.cs:
...
public class DelegateCommand<T> : ICommand
{
#region Constructors
/// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action<T> executeMethod)
: this(executeMethod, null, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
: this(executeMethod, canExecuteMethod, false)
{
}
/// <summary>
/// Constructor
/// </summary>
public DelegateCommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod, bool isAutomaticRequeryDisabled)
{
if (executeMethod == null) throw new ArgumentNullException("executeMethod");
_executeMethod = executeMethod;
_canExecuteMethod = canExecuteMethod;
_isAutomaticRequeryDisabled = isAutomaticRequeryDisabled;
}
#endregion Constructors
#region Public Methods
/// <summary>
/// Method to determine if the command can be executed
/// </summary>
public bool CanExecute(T parameter)
{
if (_canExecuteMethod != null) return _canExecuteMethod(parameter);
return true;
}
/// <summary>
/// Execution of the command
/// </summary>
public void Execute(T parameter)
{
if (_executeMethod != null) _executeMethod(parameter);
}
/// <summary>
/// Raises the CanExecuteChaged event
/// </summary>
public void RaiseCanExecuteChanged()
{
OnCanExecuteChanged();
}
/// <summary>
/// Protected virtual method to raise CanExecuteChanged event
/// </summary>
protected virtual void OnCanExecuteChanged()
{
CommandManagerHelper.CallWeakReferenceHandlers(_canExecuteChangedHandlers);
}
/// <summary>
/// Property to enable or disable CommandManager's automatic requery on this command
/// </summary>
public bool IsAutomaticRequeryDisabled {
get => _isAutomaticRequeryDisabled;
set {
if (_isAutomaticRequeryDisabled != value)
{
if (value)
CommandManagerHelper.RemoveHandlersFromRequerySuggested(_canExecuteChangedHandlers);
else
CommandManagerHelper.AddHandlersToRequerySuggested(_canExecuteChangedHandlers);
_isAutomaticRequeryDisabled = value;
}
}
}
#endregion Public Methods
#region ICommand Members
/// <summary>
/// ICommand.CanExecuteChanged implementation
/// </summary>
public event EventHandler CanExecuteChanged {
add {
if (!_isAutomaticRequeryDisabled) CommandManager.RequerySuggested += value;
CommandManagerHelper.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2);
}
remove {
if (!_isAutomaticRequeryDisabled) CommandManager.RequerySuggested -= value;
CommandManagerHelper.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value);
}
}
bool ICommand.CanExecute(object parameter)
{
// if T is of value type and the parameter is not
// set yet, then return false if CanExecute delegate
// exists, else return true
if (parameter == null &&
typeof(T).IsValueType)
return _canExecuteMethod == null;
return CanExecute((T)parameter);
}
void ICommand.Execute(object parameter)
{
Execute((T)parameter);
}
#endregion ICommand Members
#region Data
private readonly Action<T> _executeMethod;
private readonly Func<T, bool> _canExecuteMethod;
private bool _isAutomaticRequeryDisabled;
private List<WeakReference> _canExecuteChangedHandlers;
#endregion Data
}
...
How can I solve my problem?
UPDATE.
I changed my code, now it is working
Thanks to #mm8
Myprop must be a public property of the DataContext of the Button for your current binding to work.
If it's a property of the parent UserControl, you could bind to it using a RelativeSource:
CommandParameter="{Binding Path=Myprop, RelativeSource={RelativeSource AncestorType=UserControl}}"
Note that you can only bind to public properties. You cannot bind to fields.
My program is consists of a userControl and a class in C# winform environment. when I click on a button in userControl, an instance of my class is created and the main process starts. I want to interact with my class with userControl through the program is running. for example, I want to show some massages from class to a textBox property in the designed userControl. I can not instantiate from my userControl in my class because it is wrong and can not access running userControl properties. So, How can I do it? Is it a good solution to set userControl a singleton class? Do u recommend a better solution?
Edit: For more clarification:
I want to call a method from the class and pass an argument (string) into it. Then textBox in the userControl should show the passed argument! This procedure would be repeated whenever it has an output in the class!
Update: here is code sample:
In the class definition:
class MyClass
{
public MyClass()
{
//do sth
if (a condition)
{
//It is wrong to create an instance but I want to explain my purpose. It is what I need!
searchPanel sp = new searchPanel();
sp.showMessage("...");
}
}
}
And here is userControl:
public partial class searchPanel : UserControl
{
public searchPanel()
{
InitializeComponent();
}
public void showMessage(string message)
{
textBox.AppendText(message);
textBox.AppendText(Environment.NewLine);
}
}
So, How can I do it?
You could do this by implementing events. This way you can signal every class that is subscribing to your "class" events when whatever you want happens. Imagine your "class" just completes to sum up 10 integer numbers; you fire a event informing this operation just happened. Your "userControl" class is subscribing to this event and will be able to execute a function to change whatever control in the form you want. By using events you keep class isolation, avoiding things like global state in your code.
Is it a good solution to set userControl a singleton class?
No, you should avoid using singleton as a pattern in your code. Above all using singleton as global state to expose your "class" to "userControl" is probably evidence of code smell
This is usually done using the WPF Command Pattern and binding (Data Binding Overview). This is the recommended approach.
MainWindow.xaml
<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<SearchPanel />
</Window>
SearchPanel.xaml
<UserControl>
<UserControl.DataContext>
<ViewModel />
</UserControl.DataContext>
<StackPanel>
<Button Command="{Binding ShowMessageCommand}" />
<TextBlock Text="{Binding Message}" />
<StackPanel>
</UserControl>
SearchPanel.xaml.cs
public partial class SearchPanel : UserControl
{
public SearchPanel()
{
InitializeComponent();
}
}
ViewModel.cs
class ViewModel : INotifyPropertyChanged
{
private string message;
public string Message
{
get => this.message;
set
{
this.message = value;
OnPropertyChanged();
}
}
ICommand ShowMessageCommand => new RelayCommand(CreateMessage);
// Command callback
private void CreateMessage()
{
this.Message = "This is a message for display in the UI";
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
The helper class to create a reusable command:
RelayCommand.cs
/// <summary>
/// An implementation independent ICommand implementation.
/// Enables instant creation of an ICommand without implementing the ICommand interface for each command.
/// The individual Execute() an CanExecute() members are supplied via delegates.
/// <seealso cref="System.Windows.Input.ICommand"/>
/// </summary>
/// <remarks>The type of <c>RelayCommand</c> actually is a <see cref="System.Windows.Input.ICommand"/></remarks>
public class RelayCommand : ICommand
{
protected readonly Func<Task> executeAsyncNoParam;
protected readonly Action executeNoParam;
protected readonly Func<bool> canExecuteNoParam;
private readonly Func<object, Task> executeAsync;
private readonly Action<object> execute;
private readonly Predicate<object> canExecute;
/// <summary>
/// Raised when RaiseCanExecuteChanged is called.
/// </summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action<object> execute)
: this(execute, (param) => true)
{
}
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="executeNoParam">The execution logic.</param>
public RelayCommand(Action executeNoParam)
: this(executeNoParam, () => true)
{
}
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="executeAsync">The awaitable execution logic.</param>
public RelayCommand(Func<object, Task> executeAsync)
: this(executeAsync, (param) => true)
{
}
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="executeAsyncNoParam">The awaitable execution logic.</param>
public RelayCommand(Func<Task> executeAsyncNoParam)
: this(executeAsyncNoParam, () => true)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="executeNoParam">The execution logic.</param>
/// <param name="canExecuteNoParam">The execution status logic.</param>
public RelayCommand(Action executeNoParam, Func<bool> canExecuteNoParam)
{
this.executeNoParam = executeNoParam ?? throw new ArgumentNullException(nameof(executeNoParam));
this.canExecuteNoParam = canExecuteNoParam;
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
this.execute = execute ?? throw new ArgumentNullException(nameof(execute));
this.canExecute = canExecute;
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="executeAsyncNoParam">The awaitable execution logic.</param>
/// <param name="canExecuteNoParam">The execution status logic.</param>
public RelayCommand(Func<Task> executeAsyncNoParam, Func<bool> canExecuteNoParam)
{
this.executeAsyncNoParam = executeAsyncNoParam ?? throw new ArgumentNullException(nameof(executeAsyncNoParam));
this.canExecuteNoParam = canExecuteNoParam;
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="executeAsync">The awaitable execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Func<object, Task> executeAsync, Predicate<object> canExecute)
{
this.executeAsync = executeAsync ?? throw new ArgumentNullException(nameof(executeAsync));
this.canExecute = canExecute;
}
/// <summary>
/// Determines whether this RelayCommand can execute in its current state.
/// </summary>
/// <returns>true if this command can be executed; otherwise, false.</returns>
public bool CanExecute()
{
return this.canExecuteNoParam == null || this.canExecuteNoParam();
}
/// <summary>
/// Executes the RelayCommand on the current command target.
/// </summary>
public async void Execute()
{
if (this.executeAsyncNoParam != null)
{
await ExecuteAsync();
return;
}
this.executeNoParam();
}
/// <summary>
/// Executes the RelayCommand on the current command target.
/// </summary>
public async Task ExecuteAsync()
{
if (this.executeAsyncNoParam != null)
{
await this.executeAsyncNoParam();
return;
}
await Task.Run(() => this.executeNoParam());
}
/// <summary>
/// Determines whether this RelayCommand can execute in its current state.
/// </summary>
/// <param name="parameter">
/// Data used by the command. If the command does not require data to be passed,
/// this object can be set to null.
/// </param>
/// <returns>true if this command can be executed; otherwise, false.</returns>
public bool CanExecute(object parameter)
{
return this.canExecute == null || this.canExecute(parameter);
}
/// <summary>
/// Executes the RelayCommand on the current command target.
/// </summary>
/// <param name="parameter">
/// Data used by the command. If the command does not require data to be passed,
/// this object can be set to null.
/// </param>
public async void Execute(object parameter)
{
if (parameter == null)
{
Execute();
return;
}
if (this.executeAsync != null)
{
await ExecuteAsync(parameter);
return;
}
this.execute(parameter);
}
/// <summary>
/// Executes the RelayCommand on the current command target.
/// </summary>
/// <param name="parameter">
/// Data used by the command. If the command does not require data to be passed,
/// this object can be set to null.
/// </param>
public async Task ExecuteAsync(object parameter)
{
if (this.executeAsync != null)
{
await this.executeAsync(parameter);
return;
}
await Task.Run(() => this.execute(parameter));
}
}
I recommend some reading on MVVM and Commanding e.g. Basic MVVM and ICommand Usage Example or Commanding Overview
Alternative approach using a simple Button.Click event handler:
SearchPanel.xaml
<UserControl>
<UserControl.DataContext>
<ViewModel />
</UserControl.DataContext>
<StackPanel>
<Button Click="ShowMessage_OnButtonClick" />
<TextBlock x:Name="MessageTextBlock" />
<StackPanel>
</UserControl>
SearchPanel.xaml.cs
public partial class SearchPanel : UserControl
{
public SearchPanel()
{
InitializeComponent();
}
private void ShowMessage_OnButtonClick(object sender, RoutedEventArgs e)
{
this.MessageTextBlock = "This is a message for display in the UI";
}
}
Events and XAML code-behind
there are many buttons on the Main window of my WPF-App.
The commands of those buttons should have the same implementation/function but depending on which button has been pressed, the file/path on which the function accesses changes.
How to detect which button was clicked from ViewModel without using button click event handler (Windows forms)?
Here is the implementation of class RelayCommand:
public class RelayCommand : ICommand
{
readonly Func<Boolean> _canExecute;
readonly Action _execute;
public RelayCommand(Action execute)
: this(execute, null)
{
}
public RelayCommand(Action execute, Func<Boolean> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (_canExecute != null)
CommandManager.RequerySuggested -= value;
}
}
public Boolean CanExecute(Object parameter)
{
return _canExecute == null ? true : _canExecute();
}
public void Execute(Object parameter)
{
_execute();
}
}
Here is the code of the command in ViewModel:
void DoThisWorkExecute()
{
// if Button1 is clicked...do this
// if Button2 is clicked...do this
}
bool CanDoThisWorkExecute()
{
return true;
}
public ICommand ButtonCommand { get { return new RelayCommand(DoThisWorkExecute, CanDoThisWorkExecute); } }
You can use the CommandParameter. Something like that:
<Button Content="Open" Command="{Binding Path=ButtonCommand}" CommandParameter="Open"/>
<Button Content="Save" Command="{Binding Path=ButtonCommand}" CommandParameter="Save"/>
For this you need a slightly different implementation of the RelayCommand
/// <summary>
/// https://gist.github.com/schuster-rainer/2648922
/// Implementation from Josh Smith of the RelayCommand
/// </summary>
public class RelayCommand : ICommand
{
#region Fields
readonly Predicate<object> _canExecute;
readonly Action<object> _execute;
#endregion // Fields
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="RelayCommand"/> class.
/// </summary>
/// <param name="execute">The execute.</param>
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="RelayCommand"/> class.
/// </summary>
/// <param name="execute">The execute.</param>
/// <param name="canExecute">The can execute.</param>
/// <exception cref="System.ArgumentNullException">execute</exception>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
/// <summary>
/// Occurs when changes occur that affect whether or not the command should execute.
/// </summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
/// <summary>
/// Defines the method that determines whether the command can execute in its current state.
/// </summary>
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
/// <returns>true if this command can be executed; otherwise, false.</returns>
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
/// <summary>
/// Defines the method to be called when the command is invoked.
/// </summary>
/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
However: Instead of asking which button was clicked, I would make a Command for each separate action (e.g. open, save, exit). You will have much less troubles when reusing your commands (context menu, KeyBindings, toolbar, etc.). You would always have to provide the ui element. This really breaks the MVVM pattern. You really have to get rid of the old winforms approach, in order to use the full power of the RelayCommand.
I wrote myself a code snippet so I don't have to write all the code.
<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<CodeSnippet Format="1.0.0">
<Header>
<Title>RelayCommand</Title>
<Shortcut>RelayCommand</Shortcut>
<Description>Code snippet for usage of the Relay Command pattern</Description>
<Author>Mat</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>name</ID>
<ToolTip>Name of the command</ToolTip>
<Default>Save</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[ private RelayCommand _$name$Command;
public ICommand $name$Command
{
get
{
if (_$name$Command == null)
{
_$name$Command = new RelayCommand(param => this.$name$(param),
param => this.Can$name$(param));
}
return _$name$Command;
}
}
private bool Can$name$(object param)
{
return true;
}
private void $name$(object param)
{
MessageServiceHelper.RegisterMessage(new NotImplementedException());
}]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
see also https://msdn.microsoft.com/en-us/library/z41h7fat.aspx
I need help on 2 things.
sending parameters (which is a static Enum) from a view to the viewmodel (I know I must use the CommandParameter on my button).
How to delcare my DelegateCommand class so that it can accept the parameter.
Enumeration :
public static class Helpers
{
public enum Operations
{
ONE,
TWO
}
}
ViewModel
public class SettingViewModel : ViewModelBase
{
private DelegateCommand _UpdateCommand;
public ICommand UpdateOperationValue
{
get
{
if (_UpdateCommand== null)
_UpdateCommand= new DelegateCommand(Of Helpers.Operations)(param => UpdatePaint()); // Gives me erreur
return _UpdateCommand;
}
}
}
View:
<Button Height="100" Width="100" Content="PEINTURE"
Background="{Binding PaintColorBrush}"
Command="{Binding UpdateOperationValue}"
CommandParameter="[... What do I do here ? ...]"/>
I've been searching on the web for solutions and came accross this :
<Button CommandParameter="{x:Static local:SearchPageType.First}" .../>
sadly in Universal Windows app I don't have the x:Static
My DelegateCommand class :
using System;
using System.Windows.Input;
public class DelegateCommand : ICommand
{
/// <summary>
/// Action to be performed when this command is executed
/// </summary>
private Action<object> _executionAction;
/// <summary>
/// Predicate to determine if the command is valid for execution
/// </summary>
private Predicate<object> _canExecutePredicate;
/// <summary>
/// CanExecuteChanged event handler
/// </summary>
public event EventHandler CanExecuteChanged;
/// <summary>
/// Initialize a new instance of the clDelegateCommand class
/// The command will always be valid for execution
/// </summary>
/// <param name="execute">The delegate to call on execution</param>
public DelegateCommand(Action<object> execute)
: this(execute, null)
{ }
/// <summary>
/// Initializes a new instance of the clDelegateCommand class
/// </summary>
/// <param name="execute">The delegate to call on execution</param>
/// <param name="canExecute">The predicate to determine if the command is valid for execution</param>
public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
this._executionAction = execute;
this._canExecutePredicate = canExecute;
}
/// <summary>
/// Raised when CanExecute is changed
/// </summary>
public void RaiseCanExecuteChanged()
{
var handler = CanExecuteChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
/// <summary>
/// Execute the delegate backing this DelegateCommand
/// </summary>
/// <param name="parameter"></param>
/// <returns>True if command is valid for execution</returns>
public bool CanExecute(object parameter)
{
return this._canExecutePredicate == null ? true : this._canExecutePredicate(parameter);
}
/// <summary>
/// Execute the delegate backing this DelegateCommand
/// </summary>
/// <param name="parameter">parameter to pass to delegate</param>
/// <exception cref="InvalidOperationException">Thrown if CanExecute returns false</exception>
public void Execute(object parameter)
{
if (!CanExecute(parameter))
{
throw new InvalidOperationException("The command is not valid for execution, check the CanExecute method before attempting to execute.");
}
this._executionAction(parameter);
}
}
How can I send a enum parameter from my view to my view model
How can I instanciate a new DelegateCommand and receiving a enum as parameters.
How to delcare my DelegateCommand class so that it can accept the parameter.
You can use below class to accept parameters,
public class DelegateCommand: ICommand
{
#region Constructors
public DelegateCommand(Action<object> execute)
: this(execute, null) { }
public DelegateCommand(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;
}
In ViewModel ICommand Property example below,
public ICommand ExitCommand
{
get
{
if (exitCommand == null)
{
exitCommand = new DelegateCommand((obj)=>CloseApplication());
}
return exitCommand;
}
}
How can I send a enum parameter from my view to my view model
Commandparameter accept object. Bind your enum to CommandParameter and cast it in your ViewModel