Search code examples
c#wpf

C# WPF - Button Command not executing on static viewmodel


I got a issue with my code, I'm trying to execute a command on a button but nothing is happening.

I'm guessing it's because my viewmodel is static but maybe you guys can help me how to make it work.

This is a snip of the XAML, I removed all the non essential code.

<UserControl x:Class="Dossier_Registratie.Views.OverledeneView"
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" 
   xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" 
   xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
   xmlns:local="clr-namespace:Dossier_Registratie.ViewModels"
   mc:Ignorable = "d" 
   d:DesignHeight="696.96" d:DesignWidth="1190.257"
   DataContext="{x:Static local:OverledeneViewModel.Instance}">
<Button x:Name="lbl_SaveOverledene" Command="{Binding Path=SaveCommand}" Content="Volgende" Margin="1035,16,15,0" VerticalAlignment="Top" Height="31" Width="138.257" TabIndex="29" FontFamily="Arial" />

This is part of the viewmodel

    public class OverledeneViewModel : ViewModelBase
    {
        //->Commands
        public ICommand SaveCommand { get; }
        
        //Builder
        private OverledeneViewModel()
        {
            overledeneRepository = new OverledeneRepository();
            UitvaartLeider = new OverledeneUitvaartleiderModel();
            PersoonsGegevens = new OverledenePersoonsGegevensModel();
            OverlijdenInfo = new OverledeneOverlijdenInfoModel();
            SaveCommand = new ViewModelCommand(ExecuteSaveCommand, CanExecuteSaveCommand);
        }

        public static OverledeneViewModel Instance { get; } = new();

        private bool CanExecuteSaveCommand(object obj)
        {
            bool validData;
            if(string.IsNullOrWhiteSpace(AchternaamOverledene) 
                || string.IsNullOrWhiteSpace(VoornaamOverledene) 
                || string.IsNullOrWhiteSpace(GeboortedatumOverledene))
            {
                validData = false;
            }
            else
            {
                validData = true;
            }
            return validData;
        }

        private void ExecuteSaveCommand(object obj)
        {
            var AddUitvaartleider = overledeneRepository.AddUitvaartleider;
            var AddPersoonsGegevens = overledeneRepository.AddPersoonsGegevens;
            var AddOverlijdenInfo = overledeneRepository.AddOverlijdenInfo;

            if (AddUitvaartleider.ToString() != "InsertUitvaartleiderSucces")
                throw new Exception("Uitvaarleider insert has failed");

            if (AddPersoonsGegevens.ToString() != "InsertPersoonsGegevensSucces")
                throw new Exception("Persoonsgegevens insert has failed");

            if (AddOverlijdenInfo.ToString() != "InsertOverlijdenInfoSucces")
                throw new Exception("OverlijdenInfo insert has failed");
        }
    }

ViewModelCommand

    public class ViewModelCommand : ICommand
    {
        //fields
        private readonly Action<object> _executeAction;
        private readonly Predicate<object> _canExecuteAction;

        //Constructor
        public ViewModelCommand(Action<object> executeAction)
        {
            _executeAction = executeAction;
            _canExecuteAction = null;
        }

        public ViewModelCommand(Action<object> executeAction, Predicate<object> canExecuteAction)
        {
            _executeAction = executeAction;
            _canExecuteAction = canExecuteAction;
        }

        //Events
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value;  }
            remove {  CommandManager.RequerySuggested -= value;}
        }

        //Methods
        public bool CanExecute(object parameter)
        {
            return _canExecuteAction == null ? true : _canExecuteAction(parameter);
        }

        public void Execute(object parameter)
        {
            _executeAction(parameter);
        }
    }

I'm missing something here but I can find what, If I put a messagebox inside the canexecute it show directly when openening the application but not when i'm clicking the button.

Any help would be greatly appreciated.

Kind regards, Patrick


Solution

  • You return a new Command instance anytime someone calls your property SaveCommand. You just need to create the command instance once. So a change from

            //->Commands
            public ICommand SaveCommand { get { return new ViewModelCommand(ExecuteSaveCommand, CanExecuteSaveCommand); }}
            
            //Builder
            private OverledeneViewModel()
            {
                overledeneRepository = new OverledeneRepository();
                UitvaartLeider = new OverledeneUitvaartleiderModel();
                PersoonsGegevens = new OverledenePersoonsGegevensModel();
                OverlijdenInfo = new OverledeneOverlijdenInfoModel();
            }
    

    to

        // ->Commands
        public ICommand SaveCommand { get; }
        
        //Builder
        private OverledeneViewModel()
        {
            overledeneRepository = new OverledeneRepository();
            UitvaartLeider = new OverledeneUitvaartleiderModel();
            PersoonsGegevens = new OverledenePersoonsGegevensModel();
            OverlijdenInfo = new OverledeneOverlijdenInfoModel();
        
            SaveCommand = new ViewModelCommand(ExecuteSaveCommand, CanExecuteSaveCommand); }
        }
    

    will maybe/likely fix it.

    Also you need to raise the ICommand.CanExecuteChanged event anytime one of the properties evaluated in the CanExecute callback (which are AchternaamOverledene, VoornaamOverledene, GeboortedatumOverledene) changes. Else the command may rest disabled if CanExecuteSaveCommand returned false in its first invocation.