WPF CommandManager.RequerySuggested add remove
//xaml <Window x:Class="WpfApp110.MainWindow" 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:WpfApp110" mc:Ignorable="d" WindowState="Maximized" Title="MainWindow" Height="450" Width="800"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="50"/> <RowDefinition /> </Grid.RowDefinitions> <StackPanel Grid.Row="0" Orientation="Horizontal"> <Button Command="{Binding OpenImageFileCommand}" Content="Open" Margin="6" /> <Button Command="{Binding ZoomCommand}" CommandParameter="ZoomIn" Content="Zoom In" Margin="6"/> <Button Command="{Binding ZoomCommand}" CommandParameter="ZoomOut" Content="Zoom Out" Margin="6"/> <Button Command="{Binding ZoomCommand}" CommandParameter="ZoomNormal" Content="Normal" Margin="6"/> </StackPanel> <Image Grid.Row="1" Source="{Binding ImagePath,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"> <Image.RenderTransform> <ScaleTransform ScaleX="{Binding Zoom,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" ScaleY="{Binding Zoom,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/> </Image.RenderTransform> </Image> </Grid> </Window> //App.xaml.cs using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Linq; using System.Threading.Tasks; using System.Windows; namespace WpfApp110 { /// <summary> /// Interaction logic for App.xaml /// </summary> public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); var mainWin=new MainWindow(); mainWin.DataContext = new ImageData(); mainWin.Show(); } } } //vm using Microsoft.Win32; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input; namespace WpfApp110 { class ImageData : INotifyPropertyChanged { ICommand _openImageFileCmd, _zoomCmd; public ImageData() { _openImageFileCmd=new OpenImageFileCommand(this); _zoomCmd=new ZoomCommand(this); } public ICommand OpenImageFileCommand { get { return _openImageFileCmd; } } public ICommand ZoomCommand { get { return _zoomCmd; } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propName) { var handler= PropertyChanged; if(handler!=null) { handler?.Invoke(this, new PropertyChangedEventArgs(propName)); } } string _imagePath; double _zoom = 1.0; public double Zoom { get { return _zoom; } set { _zoom = value; OnPropertyChanged(nameof(Zoom)); } } public string ImagePath { get { return _imagePath; } set { _imagePath = value; OnPropertyChanged(nameof(ImagePath)); } } } enum ZoomType { ZoomIn, ZoomOut, ZoomNormal } class ZoomCommand : ICommand { private ImageData _imgData; public ZoomCommand(ImageData imgDataValue) { _imgData = imgDataValue; } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public bool CanExecute(object parameter) { return !string.IsNullOrWhiteSpace(_imgData.ImagePath) && System.IO.File.Exists(_imgData.ImagePath); } public void Execute(object parameter) { var zoomType = (ZoomType)Enum.Parse(typeof(ZoomType), (string)parameter, true); switch (zoomType) { case ZoomType.ZoomIn: _imgData.Zoom *= 1.2; break; case ZoomType.ZoomOut: _imgData.Zoom /= 1.2; break; case ZoomType.ZoomNormal: _imgData.Zoom = 1; break; } } } class OpenImageFileCommand : ICommand { ImageData _imgData; public OpenImageFileCommand(ImageData imgDataValue) { _imgData = imgDataValue; } public event EventHandler CanExecuteChanged; public bool CanExecute(object parameter) { return true; } public void Execute(object parameter) { var dlg = new OpenFileDialog() { Filter = "Image Files|*.jpg;*.png;*.bmp;*.gif" }; if (dlg.ShowDialog() == true) { _imgData.ImagePath = dlg.FileName; } } } }