I need tips from you guys, I hope someone can help me.
I want to make a WPF application which has a navigation header.
By navigation header I mean: I want to have a grid on top that contains buttons and when you click on the buttons, the bottom grid should show a completely different view. These views can also contain buttons and when clicking on these buttons only the lower grid should be updated and the top should remain as it is.
Also i want to use MVVM in my application.
below in the code you could better understand what I mean
`
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Red"> <!--this should be the header for the application-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="View 1" Margin="4"/>
<Button Grid.Column="1" Content="View 2" Margin="4"/>
</Grid>
<Grid Grid.Row="1" Background="LightBlue">
<Label Content="View 1/ View 2 Content" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
</Window>
`
CodePudding user response:
Here is a begining :
Encapsulate each view in a Grid
and manage their visibility in the View Model. A simple solution if you are starting with MVVM.
THE MAIN VIEW
<Window x:Class="NavigationHeader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:NavigationHeader"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConv" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Red">
<!--this should be the header for the application-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="View 1" Margin="4" Command="{Binding View1Command}"/>
<Button Grid.Column="1" Content="View 2" Margin="4" Command="{Binding View2Command}"/>
</Grid>
<Grid Grid.Row="1" Background="LightCoral" Visibility="{Binding View1Visibility, Converter={StaticResource BoolToVisConv}}">
<StackPanel>
<Label Content="View 1" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBox Text="my content" Width="100" Margin="10"/>
<Button Content="Ok" Width="50" Margin="10"/>
</StackPanel>
</Grid>
<Grid Grid.Row="1" Background="LightBlue" Visibility="{Binding View2Visibility, Converter={StaticResource BoolToVisConv}}">
<Label Content="View 2" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
</Window>
THE MAIN VM
For the View Model you need to install the Nuget's Package CommunityToolkit.Mvvm
as the Main VM needs these namespaces:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
public class MainVM : ObservableObject
{
private bool myView1Visibility;
private bool myView2Visibility;
public MainVM()
{
myView1Visibility = false;
myView2Visibility = false;
}
public bool View1Visibility
{
get { return myView1Visibility; }
set
{
if (value == myView1Visibility) return;
myView1Visibility = value;
OnPropertyChanged(nameof(View1Visibility));
}
}
public bool View2Visibility
{
get { return myView2Visibility; }
set
{
if (value == myView2Visibility) return;
myView2Visibility = value;
OnPropertyChanged(nameof(View2Visibility));
}
}
RelayCommand myView1Command;
RelayCommand myView2Command;
public RelayCommand View1Command
{
get
{
if (myView1Command == null)
myView1Command = new RelayCommand(View1CommandAction);
return myView1Command;
}
}
public RelayCommand View2Command
{
get
{
if (myView2Command == null)
myView2Command = new RelayCommand(View2CommandAction);
return myView2Command;
}
}
private void View1CommandAction()
{
View2Visibility = false;
View1Visibility = true;
}
private void View2CommandAction()
{
View1Visibility = false;
View2Visibility = true;
}
}
Instanciate the VM in the Main's View code behind:
public partial class MainWindow : Window
{
private readonly MainVM myMainVM;
public MainWindow()
{
InitializeComponent();
myMainVM = new MainVM();
DataContext = myMainVM;
}
}
CodePudding user response:
In addition to what Yannick pointed out for the visibility converter, I would do the following.
Create two additional "UserControl" classes (similar xaml markup as your window, but have each user control draw just what IT is to represent. This way, if you need to move the stuff around, you fix that one control. It still resides within your outer main window. For example.
<Window x:Class="NavigationHeader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:NavigationHeader"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConv" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Red">
<!--this should be the header for the application-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="View 1" Margin="4" Command="{Binding View1Command}"/>
<Button Grid.Column="1" Content="View 2" Margin="4" Command="{Binding View2Command}"/>
</Grid>
<local:MyFirstControl
Grid.Row="1"
Background="LightCoral"
Visibility="{Binding View1Visibility,
Converter={StaticResource BoolToVisConv}}" />
<local:MySecondControl
Grid.Row="1"
Background="LightBlue"
Visibility="{Binding View2Visibility,
Converter={StaticResource BoolToVisConv}}" />
</Grid>
</Window>
<UserControl x:Class="NavigationHeader.MyFirstControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:NavigationHeader"
mc:Ignorable="d" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0"
Content="View 1" FontSize="24"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1"
Text="my content" Width="100" Margin="10"/>
<Button Grid.Row="2" Grid.Column="2"
Content="Ok" Width="50" />
</Grid>
</UserControl>
<UserControl x:Class="NavigationHeader.MySecondControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:NavigationHeader" >
<StackPanel>
<Label Content="View 1"
FontSize="24"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBox Text="my content" Width="100" Margin="10"/>
<Button Content="Ok" Width="50" Margin="10"/>
</StackPanel>
</UserControl>
Notice the main window is referencing two more classes you would create as a user control MyFirstControl
and MySecondControl
. This can help keep your clutter in each respective control vs bloating the main control up and worrying about different formats such as one using a grid, and the other using a stack panel, docking panel, or whatever other type control you want to display.