Dynamic User Management Change - WPF

I am developing an application in WPF and I need to change the contents of the ContentControl at runtime depending on the user selected on ComboBox .

I have two UserControls, and in my combo there are two itens, each of which corresponds to each.

First user control:

 <UserControl x:Class="Validator.RespView" 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" mc:Ignorable="d" d:DesignHeight="167" d:DesignWidth="366" Name="Resp"> <Grid> <CheckBox Content="CheckBox" Height="16" HorizontalAlignment="Left" Margin="12,12,0,0" Name="checkBox1" VerticalAlignment="Top" /> <ListBox Height="112" HorizontalAlignment="Left" Margin="12,43,0,0" Name="listBox1" VerticalAlignment="Top" Width="168" /> <Calendar Height="170" HorizontalAlignment="Left" Margin="186,0,0,0" Name="calendar1" VerticalAlignment="Top" Width="180" /> </Grid> 

Second user control:

 <UserControl x:Class="Validator.DownloadView" 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" mc:Ignorable="d" d:DesignHeight="76" d:DesignWidth="354" Name="Download"> <Grid> <Label Content="States" Height="28" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" /> <ComboBox Height="23" HorizontalAlignment="Left" Margin="12,35,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" /> <RadioButton Content="Last 48 hs" Height="16" HorizontalAlignment="Left" Margin="230,42,0,0" Name="rdbLast48" VerticalAlignment="Top" /> <Label Content="Kind:" Height="28" HorizontalAlignment="Left" Margin="164,12,0,0" Name="label2" VerticalAlignment="Top" /> <RadioButton Content="General" Height="16" HorizontalAlignment="Left" Margin="165,42,0,0" Name="rdbGeral" VerticalAlignment="Top" /> </Grid> 

In MainWindowView.xaml

  <Window x:Class="Validator.MainWindowView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:du="clr-namespace:Validator.Download" xmlns:resp="clr-namespace:Validator.Resp" Title="Validator" Height="452" Width="668" WindowStartupLocation="CenterScreen" ResizeMode="NoResize"> <Window.Resources> <DataTemplate DataType="{x:Type du:DownloadViewModel}"> <du:DownloadView/> </DataTemplate> <DataTemplate DataType="{x:Type resp:RespViewModel}"> <resp:RespView/> </DataTemplate> </Window.Resources> <Grid> <ComboBox ItemsSource="{Binding Path=PagesName}" SelectedValue="{Binding Path=CurrentPageName}" HorizontalAlignment="Left" Margin="251,93,0,0" Name="cmbType" Width="187" VerticalAlignment="Top" Height="22" SelectionChanged="cmbType_SelectionChanged_1" /> <ContentControl Content="{Binding CurrentPageViewModel}" Height="171" HorizontalAlignment="Left" Margin="251,121,0,0" Name="contentControl1" VerticalAlignment="Top" Width="383" /> </Grid> </Window> 

I assigned a DataContext MainView, viewmodel below:

 public class MainWindowViewModel : ObservableObject { #region Fields private ICommand _changePageCommand; private ViewModelBase _currentPageViewModel; private ObservableCollection<ViewModelBase> _pagesViewModel = new ObservableCollection<ViewModelBase>(); private readonly ObservableCollection<string> _pagesName = new ObservableCollection<string>(); private string _currentPageName = ""; #endregion public MainWindowViewModel() { this.LoadUserControls(); _pagesName.Add("Download"); _pagesName.Add("Resp"); } private void LoadUserControls() { Type type = this.GetType(); Assembly assembly = type.Assembly; UserControl reso = (UserControl)assembly.CreateInstance("Validator.RespView"); UserControl download = (UserControl)assembly.CreateInstance("Validator.DownloadView"); _pagesViewModel.Add(new DownloadViewModel()); _pagesViewModel.Add(new RespViewModel()); } #region Properties / Commands public ICommand ChangePageCommand { get { if (_changePageCommand == null) { _changePageCommand = new RelayCommand( p => ChangeViewModel((IPageViewModel)p), p => p is IPageViewModel); } return _changePageCommand; } } public ObservableCollection<string> PagesName { get { return _pagesName; } } public string CurrentPageName { get { return _currentPageName; } set { if (_currentPageName != value) { _currentPageName = value; OnPropertyChanged("CurrentPageName"); } } } public ViewModelBase CurrentPageViewModel { get { return _currentPageViewModel; } set { if (_currentPageViewModel != value) { _currentPageViewModel = value; OnPropertyChanged("CurrentPageViewModel"); } } } #endregion #region Methods private void ChangeViewModel(IPageViewModel viewModel) { int indexCurrentView = _pagesViewModel.IndexOf(CurrentPageViewModel); indexCurrentView = (indexCurrentView == (_pagesViewModel.Count - 1)) ? 0 : indexCurrentView + 1; CurrentPageViewModel = _pagesViewModel[indexCurrentView]; } #endregion } 

In MainWindowView.xaml.cs, I wrote this event for an effective change:

 private void cmbType_SelectionChanged_1(object sender, SelectionChangedEventArgs e) { MainWindowViewModel element = this.DataContext as MainWindowViewModel; if (element != null) { ICommand command = element.ChangePageCommand; command.Execute(null); } } 

The application works fine, and I looked at the application with WPFInspector and saw that the view changes when the internal field changes, but the ContentControl is still empty visually.

Sorry for the amount of code I posted and skipping knowledge, but I have been working with this for a long time and cannot solve this problem. Thanks

+4
source share
1 answer

Questions:

  • First, do not ever create a View related things in a ViewModel ( UserControl ). This is no longer MVVM when you do this.
  • Derive ViewModels from ViewModelBase , not ObservableObject , unless you have a good reason not to use ViewModelBase when using MVVMLight. Store ObservableObject inheritance for models. Serves as a nice separation between VM and M
  • Further you do not need to do all ObservableCollection<T> as your _pagesViewModel . You do not have anything connected with anything in your mind, so this is just a waste. Just save it as a private list or array. Check what the type actually does as opposed to the similar other.
  • Not sure about this, you may have pulled this piece of code as a demo, but you are not using the fields to separate the elements in the grid. Your layout is essentially only 1 grid cell, and the fields have elements that do not overlap. If you are not aware of this issue, check out the WPF Layout articles.
  • Please do not forget about the principles of OOP, encapsulation and sorting when writing a user interface application. If you have properties such as CurrentPageViewModel that you do not intend to switch to viewing, make the property setter private to provide this.
  • Do not resort to reverse code in a view too early. First of all, make sure that before you do this, check only . I am talking about your ComboBox SelectionChanged event handler. Your goal for this in this demo is to switch the Bound ViewModel, which is stored in a virtual machine. Therefore, this is not what the only answer is. So, find the approach associated with the virtual machine.

Decision

You can get a working example of your code with corrections above from Here and try it yourself.

Points 1 β†’ 5 are just simple simple changes.

For 6, I created the SelectedVMIndex property in MainViewModel, which is bound to the SelectedIndex ComboBox . Thus, when the selected index is flipped, the property setting tool updates the CurrentPageViewModel after updating CurrentPageViewModel , as well as

 public int SelectedVMIndex { get { return _selectedVMIndex; } set { if (_selectedVMIndex == value) { return; } _selectedVMIndex = value; RaisePropertyChanged(() => SelectedVMIndex); CurrentPageViewModel = _pagesViewModel[_selectedVMIndex]; } } 
+9
source

All Articles