wpfdynamic-ui

WPF: Dynamic views based on button clicks


I am a newbie to WPF and while I have read lots of theory and articles, I am unable to put it all together in a working solution.

Presently, I wish to implement dynamic multiple views in a window which could be selected by the user using buttons. The target is very much like one given in the question, WPF : dynamic view/content

Can somebody please share with me a working code, of simplest implementation of the above. Just a window which contains two grids - one grid has two buttons - second grid changes background color depending on which button is clicked. From there on , I can take things further.

Thank you very much.


Solution

  • Use MVVM

    It's a design approach. Basically you treat your Window as shell, and it's responsible for swapping views.

    To simplify this snippet, I've referenced MvvmLight .

    The Window contains ContentControl which dynamically displays the relevant view

    Each dynamic view can communicate with the shell Window (using MvvmLight's Messenger) and tell it to change the view to something else.


    MainWindow.xaml

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
            Title="MainWindow" Height="350" Width="525">
        <Window.DataContext>
            <local:MainWindowViewModel></local:MainWindowViewModel>
        </Window.DataContext>
        <Grid>
    
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            
            <Grid.RowDefinitions>
                <RowDefinition Height="20"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Button Grid.Row="0" Grid.Column="0" Command="{Binding ChangeFirstViewCommand}">Change View #1</Button>
            <Button Grid.Row="0" Grid.Column="1" Command="{Binding ChangeSecondViewCommand}">Change View #2</Button>
            <ContentControl  Grid.Row="1" Grid.ColumnSpan="2" Content="{Binding ContentControlView}"></ContentControl>
        </Grid>
    </Window>
    

    MainWindowViewModel.cs

    using GalaSoft.MvvmLight;
    using GalaSoft.MvvmLight.Command;
    using GalaSoft.MvvmLight.Messaging;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfApplication1
    {
        public class MainWindowViewModel : ViewModelBase
        {
            private FrameworkElement _contentControlView;
            public FrameworkElement ContentControlView
            {
                get { return _contentControlView; }
                set
                {
                    _contentControlView = value;
                    RaisePropertyChanged("ContentControlView");
                }
            }
    
            public MainWindowViewModel()
            {
                Messenger.Default.Register<SwitchViewMessage>(this, (switchViewMessage) =>
                {
                    SwitchView(switchViewMessage.ViewName);
                });
            }
    
            public ICommand ChangeFirstViewCommand
            {
                get
                {
                    return new RelayCommand(() =>
                    {
                        SwitchView("FirstView");
    
                    });
                }
            }
    
    
            public ICommand ChangeSecondViewCommand
            {
                get
                {
                    return new RelayCommand(() =>
                    {
                        SwitchView("SecondView");
                    });
                }
            }
    
            public void SwitchView(string viewName)
            {
                switch (viewName)
                {
                    case "FirstView":
                        ContentControlView = new FirstView();
                        ContentControlView.DataContext = new FirstViewModel() { Text = "This is the first View" };
                        break;
    
                    default:
                        ContentControlView = new SecondView();
                        ContentControlView.DataContext = new SecondViewModel() { Text = "This is the second View" };
                        break;
                }
            }
        }
    }
    

    FirstView.xaml

    <UserControl x:Class="WpfApplication1.FirstView"
                 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="300" d:DesignWidth="300">
        <StackPanel>
            <Label>This is the second view</Label>
            <Label Content="{Binding Text}" />
            <Button Command="{Binding ChangeToSecondViewCommand}">Change to Second View</Button>
        </StackPanel>
    </UserControl>
    

    FirstViewModel.cs

    using GalaSoft.MvvmLight;
    using GalaSoft.MvvmLight.Command;
    using GalaSoft.MvvmLight.Messaging;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Input;
    
    namespace WpfApplication1
    {
        public class FirstViewModel : ViewModelBase
        {
    
            private string _text;
            public string Text
            {
                get { return _text; }
                set
                {
                    _text = value;
                    RaisePropertyChanged("Text");
                }
            }
    
            public ICommand ChangeToSecondViewCommand
            {
                get
                {
                    return new RelayCommand(() =>
                    {
                        Messenger.Default.Send<SwitchViewMessage>(new SwitchViewMessage { ViewName = "SecondView" });
                    });
                }
            }
        }
    }
    

    SecondView.xaml

    <UserControl x:Class="WpfApplication1.SecondView"
                 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="300" d:DesignWidth="300">
        <StackPanel>
            <Label>This is the second view</Label>
            <Label Content="{Binding Text}" />
            <Button Command="{Binding ChangeToFirstViewCommand}">Change to First View</Button>
        </StackPanel>
    </UserControl>
    

    SecondViewModel.cs

    using GalaSoft.MvvmLight;
    using GalaSoft.MvvmLight.Command;
    using GalaSoft.MvvmLight.Messaging;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Input;
    
    namespace WpfApplication1
    {
        public class SecondViewModel : ViewModelBase
        {
    
            private string _text;
            public string Text
            {
                get { return _text; }
                set
                {
                    _text = value;
                    RaisePropertyChanged("Text");
                }
            }
    
            public ICommand ChangeToFirstViewCommand
            {
                get
                {
                    return new RelayCommand(() =>
                    {
                        Messenger.Default.Send<SwitchViewMessage>(new SwitchViewMessage { ViewName = "FirstView" });
                    });
                }
            }
        }
    }
    

    SwitchViewMessage.cs

    namespace WpfApplication1
    {
        public class SwitchViewMessage
        {
            public string ViewName { get; set; }
        }
    }