Lina
Lina

Reputation: 163

diplay panel on button click with zero code behind using mvvm and wpf

I am new in MVVM and wpf...

Question in summerized form- How to control visibility of controls using wpf and MVVM. Also it should with zero code behind.

Actual Scenario-I have multiple User control panels ...Say UCPanel1, UCPanel2, UCPnale3... Till 6 - I am importing these user controls in one single Main User Control... say UCMain which is having stackpanel with the buttons at top... like menu. - now the requirement is very simple... on button1 click- i should be able to see UCPanel1 and remaining panels hidden, Button2 click- i should be able to see UCPanel2 and remaining panels hidden... so on - This i acheieved successfully using code behind. But the requirement is to implement such a way that there should be as minimal code as possible in code behind. so how my XAML and view model look like?
I can not access the extended objects of UCPanel1 in viewmodel..

In MainPanel XAML...

<Button 
    Style="{StaticResource StackPanelButtonStyle}" 
    Command="{Binding openMessageCommand}" >
    <!--Click="BtnMessege_OnClick" >-->
    <TextBlock 
        Text="Messaging" 
        Style="{StaticResource StackPanelButtonTextStyle}">
    </TextBlock>
</Button>
<Button 
    Style="{StaticResource StackPanelButtonStyle}"
    Command="{Binding openProductsCommand}">
    <!--Click="BtnProducts_OnClick">-->
    <TextBlock 
        Text="Products" 
        Style="{StaticResource StackPanelButtonTextStyle}" ></TextBlock>
</Button>

<local:StackPanelMessaging 
    Grid.Row="2" 
    Visibility="{Binding Panel1Visiblity}"></local:StackPanelMessaging>
<local:WrapPanelProducts 
    Grid.Row="2" 
    Visibility="{Binding Panel2Visiblity}" ></local:WrapPanelProducts>

In Main View Model...

 private Visibility _panel1Visiblity= Visibility.Visible;
        private Visibility _panel2Visiblity= Visibility.Hidden;


  public Visibility Panel1Visiblity
        {
            get { return _panel1Visiblity; }
            set
            {
                if (_panel1Visiblity != value)
                {
                    _panel1Visiblity = value;
                    OnPropertyChanged("Panel1Visiblity");
                }
            }
        }
        public Visibility Panel2Visiblity
        {
            get { return _panel2Visiblity; }
            set
            {
                if (_panel2Visiblity != value)
                {
                    _panel2Visiblity = value;
                    OnPropertyChanged("Panel2Visiblity");
                }
            }
        }

 private void OpenStackMessagePanel()
        {
            Panel1Visiblity = Visibility.Visible;
            Panel2Visiblity = Visibility.Hidden;
        }

        private bool canExecuteMethod1()
        {
            return true;
        }

        private void OpenWrapProductsPanel()
        {
            Panel2Visiblity = Visibility.Visible;
            Panel1Visiblity = Visibility.Hidden;
        }

        private bool canExecuteMethod2()
        {
            return true;
        }
  public ICommand openMessageCommand
        {
            get
            {
                if (_openMessageCommand == null)
                {
                    _openMessageCommand = new DelegateCommand(OpenStackMessagePanel, canExecuteMethod1, true);
                }
                return _openMessageCommand;
            }
        }


        public ICommand openProductsCommand
        {
            get
            {
                if (_openProductsCommand == null)
                {
                    _openProductsCommand = new DelegateCommand(OpenWrapProductsPanel, canExecuteMethod2, true);
                }
                return _openProductsCommand;
            }
        }

Also i am feeling writting so much code for is really worth it? or should i prefere to go for code behind which is just 10 lines ....

Upvotes: 0

Views: 1409

Answers (2)

Lance
Lance

Reputation: 2913

By using commands and visibility you can achieve what you want. Here's a simple example. I didn't use a user control like you were doing but with this example you should get the idea. Just replace the grid with your user control.

First thing that I will do is create a BooleanToVisibilityConverter class. This is a converter that will convert boolean values to visibility. We don't want to put Visibility properties in our ViewModel because we want to separate the UI from the logic. So what we want in our ViewModel is simple a boolean value that will tell if the panel is visible or not.

      public class BooleanToVisibilityConverter : IValueConverter
      {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
          bool? boolValue = value as bool?;
          return boolValue.HasValue && boolValue.Value ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
          Visibility? visibilityValue = value as Visibility?;
          return visibilityValue.HasValue && visibilityValue.Value == Visibility.Visible;
        }
      }


Now in your MainViewModel class, you will have six boolean properties that will tell if your panel is visible or not. And then you will have 6 command properties that will set those boolean properties to true. 

  public class MainViewModel : BindableBase
  {
    private bool _IsPanel1Visible;

    public bool IsPanel1Visible
    {
      get { return _IsPanel1Visible; }
      set { SetProperty(ref _IsPanel1Visible, value); }
    }

    private bool _IsPanel2Visible;

    public bool IsPanel2Visible
    {
      get { return _IsPanel2Visible; }
      set { SetProperty(ref _IsPanel2Visible, value); }
    }

    private bool _IsPanel3Visible;

    public bool IsPanel3Visible
    {
      get { return _IsPanel3Visible; }
      set { SetProperty(ref _IsPanel3Visible, value); }
    }

    private bool _IsPanel4Visible;

    public bool IsPanel4Visible
    {
      get { return _IsPanel4Visible; }
      set { SetProperty(ref _IsPanel4Visible, value); }
    }

    private bool _IsPanel5Visible;

    public bool IsPanel5Visible
    {
      get { return _IsPanel5Visible; }
      set { SetProperty(ref _IsPanel5Visible, value); }
    }

    private bool _IsPanel6Visible;

    public bool IsPanel6Visible
    {
      get { return _IsPanel6Visible; }
      set { SetProperty(ref _IsPanel6Visible, value); }
    }

    public ICommand ShowPanel1Command { get { return new DelegateCommand(() => { HidePanels(); IsPanel1Visible = true; }); } }
    public ICommand ShowPanel2Command { get { return new DelegateCommand(() => { HidePanels(); IsPanel2Visible = true; }); } }
    public ICommand ShowPanel3Command { get { return new DelegateCommand(() => { HidePanels(); IsPanel3Visible = true; }); } }
    public ICommand ShowPanel4Command { get { return new DelegateCommand(() => { HidePanels(); IsPanel4Visible = true; }); } }
    public ICommand ShowPanel5Command { get { return new DelegateCommand(() => { HidePanels(); IsPanel5Visible = true; }); } }
    public ICommand ShowPanel6Command { get { return new DelegateCommand(() => { HidePanels(); IsPanel6Visible = true; }); } }

    private void HidePanels()
    {
      IsPanel1Visible = false;
      IsPanel2Visible = false;
      IsPanel3Visible = false;
      IsPanel4Visible = false;
      IsPanel5Visible = false;
      IsPanel6Visible = false;
    }
  }

Now in your xaml, you just need to bind the boolean properties to the panel's visibility and use the BooleanToVisibilityConverter to convert the boolean value to visibility. And you also need to bind the buttons to the command.

  <Grid>
    <Grid.DataContext>
      <local:MainViewModel />
    </Grid.DataContext>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.Resources>
      <local:BooleanToVisibilityConverter x:Key="booleanToVisibilityConverter" />
    </Grid.Resources>
    <StackPanel Orientation="Horizontal">
      <Button Content="Show Panel 1" Command="{Binding ShowPanel1Command}" />
      <Button Content="Show Panel 2" Command="{Binding ShowPanel2Command}" />
      <Button Content="Show Panel 3" Command="{Binding ShowPanel3Command}" />
      <Button Content="Show Panel 4" Command="{Binding ShowPanel4Command}" />
      <Button Content="Show Panel 5" Command="{Binding ShowPanel5Command}" />
      <Button Content="Show Panel 6" Command="{Binding ShowPanel6Command}" />
    </StackPanel>
    <StackPanel Grid.Row="1">
      <Grid Visibility="{Binding IsPanel1Visible, UpdateSourcetrigger PropertyChanged, Converter={StaticResource booleanToVisibilityConverter}}">
        <TextBlock Text="Panel 1" />
      </Grid>
      <Grid Visibility="{Binding IsPanel2Visible, UpdateSourcetrigger PropertyChanged, Converter={StaticResource booleanToVisibilityConverter}}">
        <TextBlock Text="Panel 2" />
      </Grid>
      <Grid Visibility="{Binding IsPanel3Visible, UpdateSourcetrigger PropertyChanged, Converter={StaticResource booleanToVisibilityConverter}}">
        <TextBlock Text="Panel 3" />
      </Grid>
      <Grid Visibility="{Binding IsPanel4Visible, UpdateSourcetrigger PropertyChanged, Converter={StaticResource booleanToVisibilityConverter}}">
        <TextBlock Text="Panel 4" />
      </Grid>
      <Grid Visibility="{Binding IsPanel5Visible, UpdateSourcetrigger PropertyChanged, Converter={StaticResource booleanToVisibilityConverter}}">
        <TextBlock Text="Panel 5" />
      </Grid>
      <Grid Visibility="{Binding IsPanel6Visible, UpdateSourcetrigger PropertyChanged, Converter={StaticResource booleanToVisibilityConverter}}">
        <TextBlock Text="Panel 6" />
      </Grid>
    </StackPanel>
  </Grid>

Updated: Hides all panel before showing another one.

You can try to put a breakpoint here for testing: enter image description here enter image description here

Upvotes: 1

Lina
Lina

Reputation: 163

<!--Button1-->
            <Button Style="{StaticResource StackPanelButtonStyle}" Command="{Binding openPanelCommd}" CommandParameter="{Binding ElementName=WrapPanel1}" >
                <TextBlock Text="1"  Style="{StaticResource StackPanelButtonTextStyle}">
                </TextBlock>               
            </Button>
            <!--Button2-->
            <Button Style="{StaticResource StackPanelButtonStyle}"  Command="{Binding openPanelCommd}"  CommandParameter="{Binding ElementName=WrapPanel2}"  >
                <TextBlock Text="2" Style="{StaticResource StackPanelButtonTextStyle}"></TextBlock>
               </Button>
            <!--Button3-->
            <Button  Style="{StaticResource StackPanelButtonStyle}"  Command="{Binding openPanelCommd}"  CommandParameter="{Binding ElementName=WrapPanel3}"  >
                <TextBlock Text="3"  Style="{StaticResource StackPanelButtonTextStyle}" ></TextBlock>
            </Button>
            <!--Button4-->
            <Button Style="{StaticResource StackPanelButtonStyle}"  Command="{Binding openPanelCommd}"  CommandParameter="{Binding ElementName=WrapPanel4}" >
                <TextBlock Text="4" Style="{StaticResource StackPanelButtonTextStyle}" ></TextBlock>
               </Button>
            <!--Button5-->
            <Button  Style="{StaticResource StackPanelButtonStyle}"  Command="{Binding openPanelCommd}"  CommandParameter="{Binding ElementName=WrapPanel5}" >
                <TextBlock Text="5" Style="{StaticResource StackPanelButtonTextStyle}"></TextBlock>
              </Button>
    <!--Panels-->
        <local:WrapPanelProducts x:Name="WrapPanel1" Grid.Row="2"  
                Visibility="Collapsed"/>
    <local:WrapPanelProducts x:Name="WrapPanel2" Grid.Row="2"  
            Visibility="Collapsed"/>
    <local:WrapPanelProducts x:Name="WrapPanel3" Grid.Row="2"  
            Visibility="Collapsed"/>
    <local:WrapPanelProducts x:Name="WrapPanel4" Grid.Row="2"  
            Visibility="Collapsed"/>
    <local:WrapPanelProducts x:Name="WrapPanel5" Grid.Row="2"  
            Visibility="Collapsed"/>

Code Behind is

  public StackPanelMain()
        {

            InitializeComponent();            
            StackPanelMainViewModel StackPanelMainViewModel1 = new StackPanelMainViewModel();
            this.DataContext = StackPanelMainViewModel1;

        }

and View model code is as follows...

 public RelayCommand openPanelCommd { get; set; }

    //Constructor
        public StackPanelMainViewModel()
        {
            openPanelCommd = new RelayCommand(OpenPanel);
        }


     private void OpenPanel(object parameter)
{
    var args = (object) parameter;

    var elementname = (UIElement) args;

     elementname.Visibility = Visibility.Visible;

 }

Upvotes: 0

Related Questions