Navigation command works when called by button but not when called programmatically

55 Views Asked by At

I have a WPF app which has two User Controls. On one user control, I have a list of buttons which are all binded to a command that changes the ViewModel from that user control to the other, with a command parameter of the button's content. This works just fine. If I click any of the buttons, the command successfully runs and the ViewModel changes to the other user control with the button's content being passed through. However, if I try and execute the command in the ViewModel's constructor (after the command has been instantiated), it does not work. When I set a breakpoint and follow it, it appears to change the ViewModel, but the view does not appear to change in the window. I cannot figure out what the difference is between executing the command programmatically compared to with a button.

I am new to MVVM, so please let me know if I am doing something incorrectly or if you need more info.

ViewModel 1 (where I create the buttons and try to execute command programmatically):

public class SelectProgramViewModel : ViewModelBase
    {
        public List<string> ProgramNames { get; set; }
        public ObservableCollection<Button> ProgramButtons { get; set; }
        public SettingsObject SettingsObject { get; set; }
        public PersonalSettings PersonalSettings { get; set; }

        public ICommand SelectProgramCommand { get; }

        public SelectProgramViewModel(MappingStore mappingStore, NavigationStore navigationStore)
        {
            NavigationService<ParsingViewModel> navigationService = new NavigationService<ParsingViewModel>(
                navigationStore,
                () => new ParsingViewModel(mappingStore, navigationStore));

            SelectProgramCommand = new SelectProgramCommand(this, mappingStore, navigationService);

            // Retrieve settings information
            const string settingsObjectPath = "I:\\Next Phase\\Logistics\\Applications\\WM Parser\\Resources\\SettingsObject.json";
            SettingsObject = JsonConvert.DeserializeObject<SettingsObject>(File.ReadAllText(settingsObjectPath));
            PersonalSettings = JsonConvert.DeserializeObject<PersonalSettings>(File.ReadAllText(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "WM Parser", "PersonalSettings.json")));

            // Create program buttons
            ProgramNames = SettingsObject.ProgramMappings.OrderBy(x => x.Name).Select(x => x.Name).ToList();
            ProgramButtons = new ObservableCollection<Button>();
            foreach (var programName in ProgramNames)
            {
                ProgramButtons.Add(
                    new Button()
                    {
                        Content = programName,
                        Command = SelectProgramCommand,
                        CommandParameter = programName,

                        Margin = new Thickness(5, 5, 5, 5)
                    });
            }

            // Check if last used program exists
            if (PersonalSettings.LastUsedProgramName != null &&
                SettingsObject.ProgramMappings.Select(x => x.Name).Contains(PersonalSettings.LastUsedProgramName))
            {
                SelectProgramCommand.Execute(PersonalSettings.LastUsedProgramName);
            }
        }
    }

SelectProgramCommand:

public class SelectProgramCommand : CommandBase
    {
        private readonly SelectProgramViewModel _viewModel;
        private readonly MappingStore _programStore;
        private readonly NavigationService<ParsingViewModel> _navigationService;

        public SelectProgramCommand(SelectProgramViewModel viewModel, MappingStore programStore, NavigationService<ParsingViewModel> navigationService)
        {
            _viewModel = viewModel;
            _programStore = programStore;
            _navigationService = navigationService;
        }

        public override void Execute(object parameter)
        {
            _programStore.NovaMapping = _viewModel.SettingsObject.NovaMapping;
            _programStore.ParsingMapping = _viewModel.SettingsObject.ParsingMapping;
            _programStore.SelectedProgram = _viewModel.SettingsObject.ProgramMappings.First(x => x.Name == parameter.ToString());

            _navigationService.Navigate();
        }
    }

CommandBase (which SelectProgramCommand inherits):

public abstract class CommandBase : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public virtual bool CanExecute(object parameter) => true;

        public abstract void Execute(object parameter);

        protected void OnCanExecuteChanged()
        {
            CanExecuteChanged?.Invoke(this, new EventArgs());
        }
    }

NavigationService:

public class NavigationService<TViewModel>
        where TViewModel : ViewModelBase
    {
        private readonly NavigationStore _navigationStore;
        private readonly Func<TViewModel> _createViewModel;

        public NavigationService(NavigationStore navigationStore, Func<TViewModel> createViewModel)
        {
            _navigationStore = navigationStore;
            _createViewModel = createViewModel;
        }

        public void Navigate()
        {
            _navigationStore.CurrentViewModel = _createViewModel();
        }
    }

NavigationStore:

public class NavigationStore
    {
        public event Action CurrentViewModelChanged;

        private ViewModelBase _currentViewModel;
        public ViewModelBase CurrentViewModel
        {
            get => _currentViewModel;
            set
            {
                _currentViewModel = value;
                OnCurrentViewModelChanged();
            }
        }

        private void OnCurrentViewModelChanged()
        {
            CurrentViewModelChanged?.Invoke();
        }
    }
0

There are 0 best solutions below