CurrentViewModel Property Change Not Reflected in ContentControl

110 Views Asked by At

I am currently building an application where the user can select different pages via a collection of radio buttons. When the page is active I want the radio button to be checked as true. When the button is pressed my command is called and the onpropertychanged event is called but the ContentControl in my MainWindow will not show the next view. I am new to WPF and Xaml and really trying to figure this out.

I have attached a link to the sample application on my Github.

Github repository

    public class ApplicationViewModel : ObservableObject
    {
        private ICommand _changeViewCommand;

        private IViewModel _CurrentViewModel;
        private List<IViewModel> _viewModels;
        private bool _isActive;

        public ApplicationViewModel()
        {
            ViewModels.Add(new HomeViewModel());
            ViewModels.Add(new AccountViewModel());
            
            CurrentViewModel = ViewModels.Find(r => r.Name == "Home");
            CurrentViewModel.IsActive = true;
        }

        public List<IViewModel> ViewModels
        {
            get
            {
                if (_viewModels == null)
                    _viewModels = new List<IViewModel>();

                return _viewModels;
            }
        }

        public IViewModel CurrentViewModel
        {
            get
            {
                return _CurrentViewModel;
            }
            set
            {
                if (_CurrentViewModel != value)
                {
                    _CurrentViewModel = value;
                    OnPropertyChanged();
                }
            }
        }

        public ICommand ChangePageCommand
        {
            get
            {
                if (_changeViewCommand == null)
                {
                    _changeViewCommand = new RelayCommand(
                        p => ChangeViewModel((IViewModel)p),
                        p => p is IViewModel);
                }

                return _changeViewCommand;
            }
        }
       

        private void ChangeViewModel(IViewModel viewModel)
        {
            CurrentViewModel = ViewModels.Find(r => r.Name == viewModel.Name);
        }

        public bool IsActive
        {
            get
            {
                return _isActive;
            }
            set
            {
                _isActive = value;
                OnPropertyChanged("IsActive");
            }
        }
    }


    <UserControl.DataContext>
        <viewModels:ApplicationViewModel/>
    </UserControl.DataContext>
    <UserControl.Resources>
        <DataTemplate DataType="{x:Type viewModels:ApplicationViewModel}"/>
        <DataTemplate DataType="{x:Type viewModels:HomeViewModel}">
            <views:HomeView/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type viewModels:AccountViewModel}">
            <views:AccountView/>
        </DataTemplate>
    </UserControl.Resources>
    <StackPanel Orientation="Vertical">
        <RadioButton Content="Home" IsChecked="{Binding IsActive, Mode=TwoWay}" Command="{Binding    DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
                         CommandParameter="{Binding }">
            <RadioButton.DataContext>
                <viewModels:HomeViewModel/>
            </RadioButton.DataContext>
        </RadioButton>
        <RadioButton Content="Account" IsChecked="{Binding IsActive, Mode=TwoWay}" Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"
                         CommandParameter="{Binding }">
            <RadioButton.DataContext>
                <viewModels:AccountViewModel/>
            </RadioButton.DataContext>
        </RadioButton>
    </StackPanel>
2

There are 2 best solutions below

1
ASh On

you should connect RadioButtons to the ViewModels which you have in the list. don't create new view models in xaml.

and CurrentViewModel can be displayed via ContentControl with one of templates decalred in Resources

<UserControl.DataContext>
    <viewModels:ApplicationViewModel/>
</UserControl.DataContext>
<UserControl.Resources>
    <DataTemplate DataType="{x:Type viewModels:HomeViewModel}">
        <views:HomeView/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type viewModels:AccountViewModel}">
        <views:AccountView/>
    </DataTemplate>
</UserControl.Resources>

<StackPanel Orientation="Vertical">
    <ItemsControl ItemsSource="{Binding ViewModels}">
      <ItemsControl.ItemTemplate>
         <DataTemplate>
            <RadioButton Content="{Binding Name}" 
                 IsChecked="{Binding IsActive}" 
                 Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"
                 CommandParameter="{Binding }">
          </RadioButton>
        </DataTemplate>
      </ItemsControl.ItemTemplate>
    </ItemsControl>

    <ContentControl Content="{Binding CurrentViewModel}"/>
</StackPanel>

after that you should probably change StackPanel to Grid to allow ContentControl to take all available screen space

0
Hack.Sign On

Looks like if I assign the AccountViewModel to the button DataContext and set the RelativeSource AncestorType to x:Type Window the button on the HomeView will switch the view to the AccountView.

    <Button Height="40" Content="Account" Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
                     CommandParameter="{Binding }">
        <Button.DataContext>
            <viewModels:AccountViewModel/>
        </Button.DataContext>
    </Button>