Reputation: 163
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
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:
Upvotes: 1
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