What I want: If I do a Left DoubleClick on a ListViewItem I want to invoke a Method.
What I have:
Xaml:
<ListView ScrollViewer.HorizontalScrollBarVisibility="Hidden"
Name="StructListView"
Margin="15"
Grid.Row="2"
BorderThickness="0"
SelectedItem="{Binding SelectedStructObject}"
ItemsSource="{Binding StructObjects, Mode=TwoWay}"
HorizontalAlignment="Left"
HorizontalContentAlignment="Left">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction
Command="{Binding Command}"
CommandParameter="{Binding ElementName=StructListView, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
...
MainViewModel:
public class MainViewModel : BaseViewModel
{
private StructElement _selectedStructObject;
public StructElement SelectedStructObject
{
get { return _selectedStructObject; }
set
{
if (_selectedStructObject != value)
{
_selectedStructObject = value;
OnPropertyChanged();
}
}
}
public RelayCommand Command { get; set; }
public ObservableCollection<StructElement> StructObjects { get; set; }
private StructElement _structElement;
public StructElement StructObject
{
get { return _structElement; }
set
{
if (_structElement != value)
{
_structElement = value;
OnPropertyChanged();
}
}
}
public MainViewModel()
{
Command = new RelayCommand(o => { //Method; });
StructObjects = new ObservableCollection<StructElement>();
}
}
RelayCommand:
public class RelayCommand : ICommand
{
private readonly Action<object> execute;
private 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");
}
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;
}
return canExecute(parameter);
}
public void Execute(object parameter)
{
execute(parameter);
}
}
I know that if I work with a Event I could use something like:
void OnMouseDoubleClick(Object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
// Method
}
}
But since I am working with a RelayCommand, I dont have a Event like MouseButtonEventArgs?
I thought about "triggering" the OnMouseDoubleClick with the RelayCommand?
I am quite knew to Programming and WPF, so if you have further Information on Things I should read into to understand the solution, I would be thankful for everything.
Thanks.
I came across a different Solution from the Link.
In my XAML I use "EventToCommand" from MVVMLight:
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<cmd:EventToCommand Command="{Binding LightCommand}"
PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
I made my RelayCommand generic so I can pass an Event (I hope I got the Description right):
public class RelayCommand : ICommand
{
private readonly Action<object> execute;
private 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");
}
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;
}
return canExecute(parameter);
}
public void Execute(object parameter)
{
execute(parameter);
}
}
In my MainViewModel I declare a RelayCommand with a MouseButtonEventArgs and Pass a Method that checks If the MouseButton was a Leftclick and does something:
public RelayCommand<MouseButtonEventArgs> LightCommand { get; set; }
public void dosomething(MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
MessageBox.Show(e.OriginalSource.GetType().ToString());
}
}
public MainViewModel()
{
LightCommand = new RelayCommand<MouseButtonEventArgs>(dosomething);
}
Related
I have problem with my application, especially with Bindings in WPF MVVM.
I created Model, ViewModel and View, this is part of my code (only this connected with my problem) When I click the button nemed : PointUp i want to see the amount of Team1 points. Can anyone tell me what i'm doing wrong?
View
<Window x:Class="Tabu.Game
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Tabu"
xmlns:vm="clr-namespace:Tabu.ViewModel"
mc:Ignorable="d"
Title="Game" Height="600" Width="900" Background="Beige">
<Window.DataContext>
<vm:TeamStatistic />
</Window.DataContext>
<Grid>
<Button x:Name="PointUp" Command="{Binding AddPoints }" Content="+"/>
<Label x:Name="PointsTeam1_label" Content="{Binding Team1.TeamPoints, UpdateSourceTrigger=PropertyChanged }"/>
</Grid>
Model
'namespace Tabu.Model
{
public class Team
{
public bool IsTeamActive { get; set; }
public int TeamMiss { get; set; }
public int TeamPoints { get; set; }
public int TeamMistake { get; set; }
}
}'
ViewModel
namespace Tabu.ViewModel
{
class TeamStatistic : INotifyPropertyChanged
{
public Team Team1 = new Team();
public int TeamPoints
{
get { return TeamPoints; }
set { TeamPoints = value; OnPropertyChanged("TeamPoints"); }
}
public ICommand AddPoints
{
get { return new RelayCommand(() => Add_Points()); }
}
public void Add_Points()
{
Team1.TeamPoints++;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(params string[] propsName)
{
if (PropertyChanged!=null)
{
foreach(string propName in propsName)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
public class RelayCommand : ICommand
{
private readonly Func<bool> canExecute;
private readonly Action execute;
public RelayCommand(Action execute)
: this(execute, null) { }
public RelayCommand(Action execute, Func<bool> canExecute)
{
if (execute == null) throw new ArgumentNullException("execute");
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add { if (this.canExecute != null) CommandManager.RequerySuggested += value; }
remove { if (this.canExecute != null) CommandManager.RequerySuggested -= value; }
}
public Boolean CanExecute(object parameter) { return this.canExecute == null ? true : this.canExecute(); }
public void Execute(object parameter) { this.execute(); }
}
}
The problem is here:
public int TeamPoints
{
get { return TeamPoints; } //should be Team1.TeamPoints
set { TeamPoints = value; OnPropertyChanged("TeamPoints"); } //should be Team1.TeamPoints
}
Inside your TeamPoints property in ViewModel you return and set the same property TeamPoints from ViewModel but you should set from Model (Team1). You should return and set Team1.TeamPoints.
public int TeamPoints
{
get { return Team1.TeamPoints; }
set { Team1.TeamPoints = value; OnPropertyChanged("TeamPoints"); }
}
And Add_Points():
public void Add_Points()
{
Team1.TeamPoints++;
OnPropertyChanged("TeamPoints");
}
You have to update your Binding like this.
<Label x:Name="PointsTeam1_label" Content="{Binding TeamPoints, UpdateSourceTrigger=PropertyChanged }"/>
When you bind to Team1.TeamPoints you will not get the Notification from OnPropertyChanged which is inside your TeamPoints property.
I reckon it is because of AddPoints (the command binding). Since this command is binded & you are creating an instance of RelayCommand & returning each time it might be breaking the binding.
A better alternative with CommandBindings are to declare the property and initialize them in the Constructor of the view model.
Ex:
namespace Tabu.ViewModel
{
class TeamStatistic : INotifyPropertyChanged
{
public Team Team1 = new Team();
public int TeamPoints
{
get { return Team1.TeamPoints; }
set { Team1.TeamPoints = value; OnPropertyChanged("TeamPoints"); }
}
private ICommand _AddPoints;
public ICommand AddPoints
{
get { return _AddPoints; }
set { _AddPoints = value; }
}
public void Add_Points()
{
Team1.TeamPoints++;
}
public TeamStatistic ()
{
_AddPoinss = new RelayCommand(Add_Points);
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(params string[] propsName)
{
if (PropertyChanged!=null)
{
foreach(string propName in propsName)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
I have a TreeView. There are two parameters treeView_Expanded(object sender, RoutedEventArgs e) when event TreeViewItem.Expanded is handled using code-behind approach:
XAML:
<TreeView Name="treeView" TreeViewItem.Expanded="treeView_Expanded"/>
Code-behind:
private void treeView_Expanded(object sender, RoutedEventArgs e)
{
//***I take THE SECOND PARAMETER to work ***
TreeViewItem item = e.Source as TreeViewItem;
}
However, when I am handling TreeViewItem.Expanded event using MVVM rules, I always take the first parameter object sender. But I would like to take the second parameter RoutedEventArgs e:
XAML:
<TreeView ItemsSource="{Binding Person}">
<i:Interaction.Triggers>
<helper:RoutedEventTrigger RoutedEvent="TreeViewItem.Expanded">
<prism:InvokeCommandAction Command="{Binding GetNewTreeViewItemCommand}"/>
</helper:RoutedEventTrigger>
</i:Interaction.Triggers>
</TreeView>
ViewModel:
public DelegateCommand<RoutedEventArgs> GetNewTreeViewItemCommand { get; set; }
public MainWindowViewModel()
{
GetNewTreeViewItemCommand = new DelegateCommand<RoutedEventArgs>(LoadNewTreeViewITem);
}
private void LoadNewTreeViewITem(RoutedEventArgs e)
{
//e is "object sender"(the FIRST parameter), but I want to take
//RoutedEventArgs e(the SECOND parameter)
}
How can I send the second parameter when handling event in MVVM?
You may use another TriggerAction to invoke command in your VM, that will pass args as well:
<TreeView ItemsSource="{Binding Person}">
<i:Interaction.Triggers>
<helper:RoutedEventTrigger RoutedEvent="TreeViewItem.Expanded">
<local:CustomCommandAction Command="{Binding GetNewTreeViewItemCommand}"/>
</helper:RoutedEventTrigger>
</i:Interaction.Triggers>
CustomCommandAction
public sealed class CustomCommandAction : TriggerAction<DependencyObject>
{
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(CustomCommandAction), null);
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
"Command", typeof(ICommand), typeof(CustomCommandAction), null);
public ICommand Command
{
get
{
return (ICommand)this.GetValue(CommandProperty);
}
set
{
this.SetValue(CommandProperty, value);
}
}
public object CommandParameter
{
get
{
return this.GetValue(CommandParameterProperty);
}
set
{
this.SetValue(CommandParameterProperty, value);
}
}
protected override void Invoke(object parameter)
{
if (this.AssociatedObject != null)
{
ICommand command = this.Command;
if (command != null)
{
if (this.CommandParameter != null)
{
if (command.CanExecute(this.CommandParameter))
{
command.Execute(this.CommandParameter);
}
}
else
{
if (command.CanExecute(parameter))
{
command.Execute(parameter);
}
}
}
}
}
}
UPDATE
XAML
<TreeView ItemsSource="{Binding Person}" Grid.Row="1" >
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Description}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<i:Interaction.Triggers>
<local:RoutedEventTrigger RoutedEvent="TreeViewItem.Expanded">
<local:CustomCommandAction Command="{Binding GetNewTreeViewItemCommand}"/>
</local:RoutedEventTrigger>
</i:Interaction.Triggers>
</TreeView>
VM
private ObservableCollection<Person> _people = new ObservableCollection<Person>();
public ObservableCollection<Person> Person
{
get { return _people; }
}
private DelegateCommand _getNewTreeViewItemCommand = null;
public ICommand GetNewTreeViewItemCommand { get { return _getNewTreeViewItemCommand; } }
private void LoadNewTreeViewITem(object param)
{
var tuple = (Tuple<object, object>)param;
object sender = tuple.Item1;
RoutedEventArgs e = tuple.Item2 as RoutedEventArgs;
System.Diagnostics.Debug.WriteLine(sender);
System.Diagnostics.Debug.WriteLine(e.RoutedEvent);
}
public MainWindowViewModel()
{
_getNewTreeViewItemCommand = new DelegateCommand(LoadNewTreeViewITem, (o) => true);
for (int i = 0; i < 10; i++)
{
var newPerson = new Person() { Description = i.ToString() };
for (int j = 0; j < 10; j++)
{
newCode.Children.Add(new Person() { Description = i.ToString() + j.ToString() });
}
_people.Add(newCode);
}
}
Person
public class Person
{
public string Description { get; set; }
public ObservableCollection<Person> Children { get; set; } = new ObservableCollection<Person>();
}
Command
public class DelegateCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
RoutedEventTrigger
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("Routed Event trigger can only be associated to framework elements");
}
if (RoutedEvent != null)
{
associatedElement.AddHandler(RoutedEvent, new RoutedEventHandler(this.OnRoutedEvent));
}
}
void OnRoutedEvent(object sender, RoutedEventArgs args)
{
base.OnEvent(args);
}
protected override string GetEventName()
{
return RoutedEvent.Name;
}
}
CustomCommandAction
public sealed class CustomCommandAction : TriggerAction<DependencyObject>
{
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(CustomCommandAction), null);
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
"Command", typeof(ICommand), typeof(CustomCommandAction), null);
public ICommand Command
{
get
{
return (ICommand)this.GetValue(CommandProperty);
}
set
{
this.SetValue(CommandProperty, value);
}
}
public object CommandParameter
{
get
{
return this.GetValue(CommandParameterProperty);
}
set
{
this.SetValue(CommandParameterProperty, value);
}
}
protected override void Invoke(object parameter)
{
if (this.AssociatedObject != null)
{
ICommand command = this.Command;
if (command != null)
{
if (this.CommandParameter != null)
{
if (command.CanExecute(this.CommandParameter))
{
command.Execute(this.CommandParameter);
}
}
else
{
if (command.CanExecute(parameter))
{
command.Execute(new Tuple<object, object>(this.AssociatedObject, parameter));
}
}
}
}
}
}
I have trouble sending a parameter from my view to my viewmodel.
View.xaml:
In my view, I have the following:
<TextBox
MinWidth="70"
Name="InputId"/>
<Button
Command="{Binding ButtonCommand}"
CommandParameter="{Binding ElementName=InputId}"
Content="Add"/>
View.xaml.cs:
public MyView()
{
InitializeComponent();
}
public MyView(MyViewModel viewModel) : this()
{
DataContext = viewModel;
}
MyViewModel.cs:
public class MyViewModel : BindableBase
{
public ICommand ButtonCommand { get; private set; }
public MyViewModel()
{
ButtonCommand = new DelegateCommand(ButtonClick);
}
private void ButtonClick()
{
//Read 'InputId' somehow.
//But DelegateCommand does not allow the method to contain parameters.
}
}
Any suggestions to, how I can pass the InputId when I click the button to my viewmodel?
You need to add <object> to your delegate command like this :
public ICommand ButtonCommand { get; private set; }
public MyViewModel()
{
ButtonCommand = new DelegateCommand<object>(ButtonClick);
}
private void ButtonClick(object yourParameter)
{
//Read 'InputId' somehow.
//But DelegateCommand does not allow the method to contain parameters.
}
Do you want to get the text of textbox change your xaml to :
CommandParameter="{Binding Text,ElementName=InputId}"
For proper implementation of ICommand/RelayCommand have a look at this MSDN page.
Summary:
public class RelayCommand : ICommand
{
readonly Action<object> _execute;
readonly Func<bool> _canExecute;
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Func<bool> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute.Invoke();
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
public MyViewModel()
{
ButtonCommand = new RelayCommand(ButtonClick);
}
private void ButtonClick(object obj)
{
//obj is the object you send as parameter.
}
XAML Button:
<Button Content="Test Connection" Name="btnTestConnection" Command="{Binding Path=TestCommand}" CommandParameter="{Binding ElementName=someObject}"/>
View Model:
public ICommand TestCommand
{
get;
internal set;
}
private bool CanExecuteTestCommand()
{
return !String.IsNullOrEmpty(txtControl);
}
private void CreateTestCommand()
{
TestCommand = new TestCommand(TestExecute);
}
public void TestExecute(object parameter)
{
//do stuff with parameter
obj.TestConnection(parameter);
}
I would like to point out that CreateTestCommand() is called in my VM constructor.
And finally, my implementation of TestCommand:
class TestCommand : ICommand
{
private Action<object> execute;
private Predicate<object> canExecute;
private event EventHandler CanExecuteChangedInternal;
public TestCommand(Action<object> execute)
: this(execute, DefaultCanExecute)
{
}
public TestCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}
if (canExecute == null)
{
throw new ArgumentNullException("canExecute");
}
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
this.CanExecuteChangedInternal += value;
}
remove
{
CommandManager.RequerySuggested -= value;
this.CanExecuteChangedInternal -= value;
}
}
public bool CanExecute(object parameter)
{
return this.canExecute != null && this.canExecute(parameter);
}
public void Execute(object parameter)
{
this.execute(parameter);
}
public void OnCanExecuteChanged()
{
EventHandler handler = this.CanExecuteChangedInternal;
if (handler != null)
{
handler.Invoke(this, EventArgs.Empty);
}
}
public void Destroy()
{
this.canExecute = _ => false;
this.execute = _ => { return; };
}
private static bool DefaultCanExecute(object parameter)
{
return true;
}
}
I set a breakpoint in CreateTestCommand and it looks like it's configured properly:
But when I click on btnTestConnection, nothing happens. TestExecute in my View Model isn't called (which calls TestConnection on the actual model). I must be missing something, but I can't for the life of me figure out what...
EDIT Including the rest of my view model;
class FormProcessorViewModel
{
FormProcessorModel obj;
public FormProcessorViewModel()
{
obj = new FormProcessorModel();
CreateTestCommand();
}
public FormProcessorViewModel(string server, string database, string username, bool specifyDateRange, DateTime startDate, DateTime endDate, string operation, string preprocessed, string processed, string failed) :this()
{
txtServer = server;
txtDatabase = database;
txtUsername = username;
chkSpecifyDateRange = specifyDateRange;
dpStartDate = startDate;
dpEndDate = endDate;
txtOperation = operation;
txtPreprocessed = preprocessed;
txtProcessed = processed;
txtFailed = failed;
}
public ICommand TestCmd
{
get;
internal set;
}
private bool CanExecuteTestCommand()
{
return !String.IsNullOrEmpty(txtUsername);
}
private void CreateTestCommand()
{
TestCmd = new TestCommand(TestExecute);
}
private void TestExecute(object parameter)
{
var passwordBox = parameter as PasswordBox;
var password = passwordBox.Password;
obj.TestConnection(password);
}
}
I left out all the properties that get set in the second constructor just because they don't really do anything but refer to the corresponding values on the model object.
EDIT
View Model
class ViewModel : INotifyPropertyChanged
{
private string _test;
public string TestValue
{
get { return _test; }
set { _test = value; RaisePropertyChanged("TestValue"); }
}
public ICommand MyCommand { get; internal set; }
public ViewModel()
{
TestValue = "Test";
CreateTestCommand();
}
private void CreateTestCommand()
{
MyCommand = new TestCommand(ExecuteButton);
}
private void ExecuteButton(object obj)
{
TestValue = "Cool";
}
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string propName)
{
var pc = PropertyChanged;
if (pc != null)
{
pc(this, new PropertyChangedEventArgs(propName));
}
}
}
Xaml
<Button Content="{Binding TestValue}" Command="{Binding Path=MyCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}"/>
Xaml Code behind.
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
How does one use the CanExecute Method from the ICommand interface?
In my example i have a SaveCommand which i only what to be enable when the object is saveable. The XAML Code of my Savebutton looks like this:
<Button Content="Save" Command="{Binding SaveCommand, Mode=TwoWay}" />
This is the code of my save class:
class Save : ICommand
{
public MainWindowViewModel viewModel { get; set; }
public Save(MainWindowViewModel viewModel)
{
this.viewModel = viewModel;
}
public bool CanExecute(object parameter)
{
if (viewModel.IsSaveable == false)
return false;
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
viewModel.Save();
}
}
The save property in the ViewModel looks like this:
public ICommand SaveCommand
{
get
{
saveCommand = new Save(this);
return saveCommand;
}
set
{
saveCommand = value;
}
}
This construct didn't work. The button does not enable its self when isSaveable is true.
Instead of defining your own implementation of ICommand, use a RelayCommand.
In the below sample code, the save Button is enabled when the user types something in the TextBox.
XAML:
<Window x:Class="RelayCommandDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel HorizontalAlignment="Center">
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" Margin="5" Width="120"/>
<Button Content="Save" Command="{Binding SaveCommand}" Margin="3"/>
</StackPanel>
</Window>
Code behind:
using System;
using System.Windows;
using System.Windows.Input;
namespace RelayCommandDemo
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new VM();
}
}
public class VM
{
public String Name { get; set; }
private ICommand _SaveCommand;
public ICommand SaveCommand
{
get { return _SaveCommand; }
}
public VM()
{
_SaveCommand = new RelayCommand(SaveCommand_Execute, SaveCommand_CanExecute);
}
public void SaveCommand_Execute()
{
MessageBox.Show("Save Called");
}
public bool SaveCommand_CanExecute()
{
if (string.IsNullOrEmpty(Name))
return false;
else
return true;
}
}
public class RelayCommand : ICommand
{
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
private Action methodToExecute;
private Func<bool> canExecuteEvaluator;
public RelayCommand(Action methodToExecute, Func<bool> canExecuteEvaluator)
{
this.methodToExecute = methodToExecute;
this.canExecuteEvaluator = canExecuteEvaluator;
}
public RelayCommand(Action methodToExecute)
: this(methodToExecute, null)
{
}
public bool CanExecute(object parameter)
{
if (this.canExecuteEvaluator == null)
{
return true;
}
else
{
bool result = this.canExecuteEvaluator.Invoke();
return result;
}
}
public void Execute(object parameter)
{
this.methodToExecute.Invoke();
}
}
}