Reputation: 6606
I am new to WPF, just got thrown on a project. There is already an existing LoginWindow, and currently there is a forgot password button which opens a new dialog window. The manager wants that changed to use the same window, instead of opening a new one on top of it. I haven't seen a really solid example of how to accomplish this, as there seems to be a lot of different ways to do things in WPF. My initial though was maybe to use a Panel like a div and show and hide them in the same window like I DIV in HTML but not sure.
The current login someone already built looks like this:
<Controls:MetroWindow x:Class="Omega.LoginView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:Omega.Properties"
xmlns:tools="clr-namespace:Omega.modules.Features"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
Title="USER LOGIN" Icon="resources/icons/OmegaApp.ico"
TextOptions.TextFormattingMode="Display"
ShowInTaskbar="True" Topmost="False"
WindowStartupLocation="CenterScreen" ResizeMode="NoResize"
GlowBrush="{DynamicResource AccentColorBrush}" BorderThickness="1" EnableDWMDropShadow="True" WindowTransitionsEnabled="False" Closed="LoginWindow_Close" Height="446" Width="808" Visibility="Visible">
<Controls:MetroWindow.Background>
<ImageBrush ImageSource="resources\images\Omega-BGScreen.jpg"/>
</Controls:MetroWindow.Background>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/resources/Resource_Dictionary.xaml"/>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/FlatButton.xaml" />
<ResourceDictionary Source="/resources/Icons.xaml" />
</ResourceDictionary.MergedDictionaries>
<x:Array x:Key="WindowCommandsOverlayBehaviorArray"
Type="Controls:WindowCommandsOverlayBehavior">
<Controls:WindowCommandsOverlayBehavior>Always</Controls:WindowCommandsOverlayBehavior>
<Controls:WindowCommandsOverlayBehavior>Flyouts</Controls:WindowCommandsOverlayBehavior>
<Controls:WindowCommandsOverlayBehavior>HiddenTitleBar</Controls:WindowCommandsOverlayBehavior>
<Controls:WindowCommandsOverlayBehavior>Never</Controls:WindowCommandsOverlayBehavior>
</x:Array>
</ResourceDictionary>
</Window.Resources>
<Grid >
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image Grid.ColumnSpan="3" Source="resources/images/Omega_Logo.png" HorizontalAlignment="Left" Height="100" Margin="58,48,0,0" VerticalAlignment="Top" Width="186" Grid.RowSpan="2"/>
<TextBox Name="UserID_Text" Grid.ColumnSpan="2" Grid.Column="2" HorizontalAlignment="Left" Height="30" Grid.Row="2" TextWrapping="Wrap" Text="Omega" VerticalAlignment="Top" Width="190" VerticalContentAlignment="Center" Margin="0,30,0,0" TabIndex="0" IsTabStop="True"/>
<Button Style="{StaticResource StandardButton}" Content="{x:Static properties:Resources.Login_Label}" IsDefault="True" HorizontalAlignment="Left" Grid.Row="3" VerticalAlignment="Top" Width="400" Grid.ColumnSpan="4" Height="30" Grid.Column="2" Click="Login_Button_Click" TabIndex="2" />
<TextBox HorizontalAlignment="Left" Height="23" Margin="0,33,0,0" Grid.Row="5" TextWrapping="Wrap" Text="v 2.0" VerticalAlignment="Top" Width="52" RenderTransformOrigin="0.392,0.346" BorderThickness="0" Foreground="LightGray" Focusable="False"/>
<PasswordBox Name="Pass_Text" Password="nopassword" Grid.Column="4" HorizontalAlignment="Left" Margin="10,30,0,0" Grid.Row="2" VerticalAlignment="Top" Height="30" Grid.ColumnSpan="2" Width="190" VerticalContentAlignment="Center" TabIndex="1"/>
<Label Content="User Login" Grid.Column="2" HorizontalAlignment="Left" Grid.Row="2" VerticalAlignment="Top" Width="100"/>
<Button Style="{StaticResource LinkButton}" Content="{x:Static properties:Resources.ForgotPass_label}" Grid.Column="2" HorizontalAlignment="Left" Grid.Row="3" VerticalAlignment="Top" Click="ForgotPassword_Click" Width="Auto" Grid.ColumnSpan="2" Margin="0,35,0,0" Focusable="False"/>
<TextBlock Grid.Column="3" HorizontalAlignment="Left" Margin="18,36,0,0" Grid.Row="3" TextWrapping="Wrap" Text=" | " VerticalAlignment="Top" Width="Auto" Height="17" RenderTransformOrigin="2,0.529"/>
<Button Style="{StaticResource LinkButton}" Content="{x:Static properties:Resources.Help_label}" Grid.Column="3" HorizontalAlignment="Left" Margin="36,36,0,0" Grid.Row="3" VerticalAlignment="Top" Width="34" Height="17" Click="Help_Click" RenderTransformOrigin="0.559,1.824" Focusable="False"/>
</Grid>
</Controls:MetroWindow>
Upvotes: 0
Views: 373
Reputation: 4259
I'm sorry this is such a crude example but I hope it shows you how you could solve your problem. Below is a simple example on how to swap two user controls using a button...
You have a shell view:
<Window x:Class="LogonApplication.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:LogonApplication"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:ChangePasswordViewModel}">
<local:ChangePasswordView />
</DataTemplate>
<DataTemplate DataType="{x:Type local:EnterPasswordViewModel}">
<local:EnterPasswordView />
</DataTemplate>
</Window.Resources>
<DockPanel LastChildFill="False">
<ContentPresenter Content="{Binding ActiveView}"
DockPanel.Dock="Top"/>
<StackPanel DockPanel.Dock="Bottom">
<Button Content="Change View" Command="{Binding ChangeViewCommand}"/>
</StackPanel>
</DockPanel>
</Window>
Bound to a view model like this:
public class MainWindowViewModel : ViewModelBase
{
ViewModelBase _activeView;
public MainWindowViewModel()
{
_activeView = new EnterPasswordViewModel();
ChangeViewCommand = new ChangeViewCommand(this);
}
public ViewModelBase ActiveView
{
get { return _activeView; }
set
{
_activeView = value;
OnPropertyChanged("ActiveView");
}
}
public ICommand ChangeViewCommand { get; set; }
}
Then all you need to do is change the viewmodel being displayed by your content presenter. This could be achieved by wiring up a command to toggle your user controls/view models.
class ChangeViewCommand : ICommand
{
private MainWindowViewModel _mainWindowViewModel;
public event EventHandler CanExecuteChanged;
public ChangeViewCommand(MainWindowViewModel mainWindowViewModel)
{
_mainWindowViewModel = mainWindowViewModel;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
if (_mainWindowViewModel.ActiveView.GetType() == typeof(EnterPasswordViewModel))
{
_mainWindowViewModel.ActiveView = new ChangePasswordViewModel();
}
else
{
_mainWindowViewModel.ActiveView = new EnterPasswordViewModel();
}
}
}
Heres the base class for completeness:
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
I havent shown the other two views and view models but the views are just WPF User controls and the view models are classes that implement viewmodelbase. Let me know if you need more information.
Upvotes: 2