先上界面效果圖:
該項目包含了根據背景圖片等比放置控件、登錄頁面、登錄跳轉、以及後續菜單的頁面跳轉功能
MainWindow:
<Window x:Class="LogInDemo.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:LogInDemo"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="800" WindowStartupLocation="CenterScreen" WindowStyle="None" ResizeMode="NoResize">
<Window.DataContext>
<local:MainWindowViewModel></local:MainWindowViewModel>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Height="30">
<Grid.Background>
<SolidColorBrush Color="Orange"></SolidColorBrush>
</Grid.Background>
<Button Width="50" Height="25" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0" Content="首頁" Background="CadetBlue" Foreground="Red" Command="{Binding HomePageCmd}"></Button>
<Button Width="25" Height="25" HorizontalAlignment="Right" Margin="10,0" Background="Orange" BorderThickness="0" Content="X" Cursor="Hand" Click="Button_Click"></Button>
</Grid>
<ContentControl x:Name="ViewControl" Content="{Binding ViewControl}" Grid.Row="1"/>
</Grid>
</Window>
MainWindowViewModel:
using LogInDemo.Model;
using LogInDemo.View;
using LogInDemo.ViewModel;
using System.Windows.Controls;
using System.Windows.Input;
namespace LogInDemo
{
public class MainWindowViewModel : ViewModelBase
{
LogInControl logInView;
MenuPage menuView;
ViewA viewA;
ViewB viewB;
ViewC viewC;
ViewD viewD;
public MainWindowViewModel()
{
//初始化主窗體,當前運行的顯示頁爲登錄頁面
logInView = new LogInControl();
menuView = new MenuPage();
viewA = new ViewA();
viewB = new ViewB();
viewC = new ViewC();
viewD = new ViewD();
ViewControl = new Frame()
{
Content = logInView
};
MessageAggregator<object>.Instance.Subscribe("PageChanged", ToggleHandler);
HomePageCmd = new RelayCommand(ViewToHomePage);
}
public ICommand HomePageCmd { get; }
private void ToggleHandler(object sender, MessageArgs<object> args)
{
string getPageName = (string)args.Item;
switch (getPageName)
{
case "MenuPage":
ViewControl = new Frame()
{
Content = menuView
};
break;
case "ViewA":
ViewControl = new Frame()
{
Content = viewA
};
break;
case "ViewB":
ViewControl = new Frame()
{
Content = viewB
};
break;
case "ViewC":
ViewControl = new Frame()
{
Content = viewC
};
break;
case "ViewD":
ViewControl = new Frame()
{
Content = viewD
};
break;
}
}
private object _contentControl;
public object ViewControl
{
get
{ return _contentControl; }
set
{
_contentControl = value;
RaisePropertyChanged("ViewControl");
}
}
private void ViewToHomePage()
{
ViewControl = new Frame()
{
Content = menuView
};
}
}
}
LogInControl:
根據背景圖片等比放置控件,根據背景圖片的實際情況進行行列的距離等比定義
<UserControl x:Class="LogInDemo.LogInControl"
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:LogInDemo"
xmlns:Core="clr-namespace:LogInDemo"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="800">
<UserControl.Background>
<ImageBrush ImageSource="/Resource/LogIn.jpg"></ImageBrush>
</UserControl.Background>
<UserControl.DataContext>
<local:LogInControlViewModel/>
</UserControl.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="130*"/>
<RowDefinition Height="340*"/>
<RowDefinition Height="130*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="220*"/>
<ColumnDefinition Width="350*"/>
<ColumnDefinition Width="230*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30*"/>
<ColumnDefinition Width="290*"/>
<ColumnDefinition Width="30*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="105*"/>
<RowDefinition Height="55*"/>
<RowDefinition Height="55*"/>
<RowDefinition Height="33*"/>
<RowDefinition Height="60*"/>
<RowDefinition Height="32*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="1">
<TextBox x:Name="IDTextBox" Text="{Binding AccountNumber, UpdateSourceTrigger=PropertyChanged}"
Background="Transparent" BorderThickness="0"
Foreground="OrangeRed"
CaretBrush="OrangeRed"
VerticalAlignment="Center"
VerticalContentAlignment="Stretch" Margin="20,0,0,0"/>
<TextBlock IsHitTestVisible="False"
Text="請輸入賬號"
Foreground="DarkGray"
Background="Transparent"
VerticalAlignment="Center" HorizontalAlignment="Left" Margin="20,0,0,0">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=IDTextBox}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
<Grid Grid.Row="2">
<PasswordBox Tag="請輸入密碼"
x:Name="PassWordTextBox"
Background="Transparent"
BorderThickness="0"
VerticalAlignment="Center"
HorizontalAlignment="Left"
VerticalContentAlignment="Stretch"
Core:PasswordBoxHelper.Password="{Binding Path=PassWordValue,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Margin="20,0,0,0">
<PasswordBox.Style>
<Style TargetType="PasswordBox">
<Setter Property="Foreground" Value="OrangeRed"/>
<Setter Property="Core:PasswordBoxHelper.IsMonitoring" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type PasswordBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<Grid>
<ScrollViewer x:Name="PART_ContentHost" Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
<TextBlock x:Name="WaterMark" Focusable="False" Visibility="Collapsed" Text="{TemplateBinding Tag}" VerticalAlignment="Center" HorizontalAlignment="Left"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Core:PasswordBoxHelper.PasswordLength" Value="0">
<Setter TargetName="WaterMark" Property="Visibility" Value="Visible"/>
<Setter TargetName="WaterMark" Property="Foreground" Value="DarkGray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</PasswordBox.Style>
</PasswordBox>
</Grid>
<Grid Grid.Row="4">
<Button x:Name="btn_Login" Command="{Binding LoginCmd}" Background="Orange" BorderThickness="0" IsDefault="True"
Content="登錄" Grid.Column="1" Template="{DynamicResource ButtonBaseControlTemplate1}" Foreground="White">
<Button.Resources>
<ControlTemplate x:Key="ButtonBaseControlTemplate1" TargetType="{x:Type ButtonBase}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<TextBlock x:Name="contentPresenter" FontSize="20px" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{TemplateBinding Content}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Button.IsDefaulted" Value="True">
<Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" TargetName="border" Value="#173060"/>
<Setter Property="BorderBrush" TargetName="border" Value="#FF3C7FB1"/>
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="True">
<Setter Property="Background" TargetName="border" Value="#FFBCDDEE"/>
<Setter Property="BorderBrush" TargetName="border" Value="#FF245A83"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" TargetName="border" Value="#E2E2E2" />
<Setter Property="Foreground" TargetName="contentPresenter" Value="#919191" />
<Setter Property="Text" TargetName="contentPresenter" Value="登錄中..." />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Resources>
</Button>
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
</UserControl>
LogInControlViewModel:
using LogInDemo.Model;
using LogInDemo.ViewModel;
using System.Threading.Tasks;
using System.Windows.Input;
namespace LogInDemo
{
public class LogInControlViewModel: ViewModelBase
{
public LogInControlViewModel()
{
LoginCmd = new RelayCommand(PressOK, () => !IsLoadding);
}
private string _accountNumber;
public string AccountNumber
{
get
{ return _accountNumber; }
set
{
_accountNumber = value;
RaisePropertyChanged("AccountNumber");
}
}
private string _passWordValue;
public string PassWordValue
{
get
{ return _passWordValue; }
set
{
_passWordValue = value;
RaisePropertyChanged("PassWordValue");
}
}
private bool _isLoadding;
public bool IsLoadding
{
get
{ return _isLoadding; }
set
{
_isLoadding = value;
RaisePropertyChanged("IsLoadding");
}
}
public ICommand LoginCmd { get; }
private bool CanPreess()
{
return IsLoadding;
}
private async void PressOK()
{
IsLoadding = true;
await Init(); //登陸延時,在此處初始化登陸時的耗時操作
MessageAggregator<object>.Instance.Publish("PageChanged", this, new MessageArgs<object>("MenuPage"));
IsLoadding = false;
}
private Task Init()
{
return Task.Factory.StartNew(DoInit);
}
private void DoInit()
{
System.Threading.Thread.Sleep(1000);
}
}
}
PasswordBoxHelper:
Password水印效果和綁定值的輔助類
using System.Windows;
using System.Windows.Controls;
namespace LogInDemo
{
/// <summary>
/// PasswordBox添加水印輔助類
/// </summary>
public class PasswordBoxHelper : DependencyObject
{
public static bool GetIsMonitoring(DependencyObject obj)
{
return (bool)obj.GetValue(IsMonitoringProperty);
}
public static void SetIsMonitoring(DependencyObject obj, bool value)
{
obj.SetValue(IsMonitoringProperty, value);
}
public static readonly DependencyProperty IsMonitoringProperty =
DependencyProperty.RegisterAttached("IsMonitoring", typeof(bool), typeof(PasswordBoxHelper), new UIPropertyMetadata(false, OnIsMonitoringChanged));
public static readonly DependencyProperty PasswordProperty =
DependencyProperty.RegisterAttached("Password",
typeof(string), typeof(PasswordBoxHelper),
new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged));
public static int GetPasswordLength(DependencyObject obj)
{
return (int)obj.GetValue(PasswordLengthProperty);
}
public static void SetPasswordLength(DependencyObject obj, int value)
{
obj.SetValue(PasswordLengthProperty, value);
}
public static readonly DependencyProperty PasswordLengthProperty =
DependencyProperty.RegisterAttached("PasswordLength", typeof(int), typeof(PasswordBoxHelper), new UIPropertyMetadata(0));
private static readonly DependencyProperty IsUpdatingProperty =
DependencyProperty.RegisterAttached("IsUpdating", typeof(bool),
typeof(PasswordBoxHelper));
public static readonly DependencyProperty AttachProperty =
DependencyProperty.RegisterAttached("Attach",
typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(false, Attach));
private static void OnIsMonitoringChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var pb = d as PasswordBox;
if (pb == null)
{
return;
}
if ((bool)e.NewValue)
{
pb.PasswordChanged += PasswordChanged;
}
else
{
pb.PasswordChanged -= PasswordChanged;
}
}
public static void SetAttach(DependencyObject dp, bool value)
{
dp.SetValue(AttachProperty, value);
}
public static bool GetAttach(DependencyObject dp)
{
return (bool)dp.GetValue(AttachProperty);
}
public static string GetPassword(DependencyObject dp)
{
return (string)dp.GetValue(PasswordProperty);
}
public static void SetPassword(DependencyObject dp, string value)
{
dp.SetValue(PasswordProperty, value);
}
private static bool GetIsUpdating(DependencyObject dp)
{
return (bool)dp.GetValue(IsUpdatingProperty);
}
private static void SetIsUpdating(DependencyObject dp, bool value)
{
dp.SetValue(IsUpdatingProperty, value);
}
private static void OnPasswordPropertyChanged(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
passwordBox.PasswordChanged -= PasswordChanged;
if (!(bool)GetIsUpdating(passwordBox))
{
passwordBox.Password = (string)e.NewValue;
}
passwordBox.PasswordChanged += PasswordChanged;
}
private static void Attach(DependencyObject sender,
DependencyPropertyChangedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
if (passwordBox == null)
return;
if ((bool)e.OldValue)
{
passwordBox.PasswordChanged -= PasswordChanged;
}
if ((bool)e.NewValue)
{
passwordBox.PasswordChanged += PasswordChanged;
}
}
private static void PasswordChanged(object sender, RoutedEventArgs e)
{
var passwordBox = sender as PasswordBox;
if (passwordBox == null)
{
return;
}
SetPasswordLength(passwordBox, passwordBox.Password.Length);
SetIsUpdating(passwordBox, true);
SetPassword(passwordBox, passwordBox.Password);
SetIsUpdating(passwordBox, false);
}
}
}
MenuPage:
登錄後的菜單頁面跳轉
<UserControl x:Class="LogInDemo.MenuPage"
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"
xmlns:local="clr-namespace:LogInDemo"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="500">
<UserControl.DataContext>
<local:MenuPageViewModel></local:MenuPageViewModel>
</UserControl.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Content="This is First Menu" Grid.Column="0" Grid.Row="0" Foreground="Red" Command="{Binding ChangeViewACmd}"></Button>
<Button Content="This is Second Menu" Grid.Column="1" Grid.Row="0" Foreground="Red" Command="{Binding ChangeViewBCmd}"></Button>
<Button Content="This is Third Menu" Grid.Column="0" Grid.Row="1" Foreground="Red" Command="{Binding ChangeViewCCmd}"></Button>
<Button Content="This is Fourth Menu" Grid.Column="1" Grid.Row="1" Foreground="Red" Command="{Binding ChangeViewDCmd}"></Button>
</Grid>
</UserControl>
MenuPageViewModel:
using LogInDemo.Model;
using LogInDemo.ViewModel;
using System.Threading.Tasks;
using System.Windows.Input;
namespace LogInDemo
{
public class MenuPageViewModel : ViewModelBase
{
public MenuPageViewModel()
{
ChangeViewACmd = new RelayCommand(ChangeViewA);
ChangeViewBCmd = new RelayCommand(ChangeViewB);
ChangeViewCCmd = new RelayCommand(ChangeViewC);
ChangeViewDCmd = new RelayCommand(ChangeViewD);
}
public ICommand ChangeViewACmd { get; }
public ICommand ChangeViewBCmd { get; }
public ICommand ChangeViewCCmd { get; }
public ICommand ChangeViewDCmd { get; }
private void ChangeViewA()
{
MessageAggregator<object>.Instance.Publish("PageChanged", this, new MessageArgs<object>("ViewA"));
}
private void ChangeViewB()
{
MessageAggregator<object>.Instance.Publish("PageChanged", this, new MessageArgs<object>("ViewB"));
}
private void ChangeViewC()
{
MessageAggregator<object>.Instance.Publish("PageChanged", this, new MessageArgs<object>("ViewC"));
}
private void ChangeViewD()
{
MessageAggregator<object>.Instance.Publish("PageChanged", this, new MessageArgs<object>("ViewD"));
}
}
}
用於頁面跳轉的消息通知類 MessageAggregator:
using System.Collections.Generic;
namespace LogInDemo.Model
{
public delegate void MessageHandler<T>(object sender, MessageArgs<T> args);
public class MessageAggregator<T>
{
private readonly Dictionary<string, MessageHandler<T>> _messages = new Dictionary<string, MessageHandler<T>>();
public static readonly MessageAggregator<T> Instance = new MessageAggregator<T>();
private MessageAggregator()
{
}
public void Subscribe(string name, MessageHandler<T> handler)
{
if (!_messages.ContainsKey(name))
{
_messages.Add(name, handler);
}
else
{
_messages[name] += handler;
}
}
public void Publish(string name, object sender, MessageArgs<T> args)
{
if (_messages.ContainsKey(name) && _messages[name] != null)
{
//轉發
_messages[name](sender, args);
}
}
}
public class MessageArgs<T>
{
public T Item { get; set; }
public MessageArgs(T item)
{
Item = item;
}
}
}
剩下四個頁面 ViewA、ViewB、ViewC、ViewD、爲四個只放了一個Textblock的空頁面就不上代碼了。
參考:https://www.cnblogs.com/su-yang/p/7009956.html
https://yq.aliyun.com/articles/389853
源碼:放在CSDN下載了 點擊此下載源碼