1、左侧导航设计要点
清晰的信息架构
确保导航结构层次分明,主分类与子分类逻辑清晰,避免过度嵌套。使用分组、缩进或分隔线区分不同层级,保持视觉可读性。
直观的图标与标签
为每个导航项搭配简洁的图标,强化视觉识别。标签文字需简短明确,避免专业术语,保证用户快速理解功能或内容。
响应式交互设计
悬停状态应有视觉反馈(如颜色变化、背景高亮)。当前选中项需突出显示(如底色、边框或文字加粗),帮助用户定位。可折叠菜单需支持平滑展开/收起动画。
视觉层次与留白
通过字体大小、颜色深浅或间距区分主次内容。保留充足留白,避免信息拥挤。暗色背景或分割线可提升导航区与主内容的区分度。
性能优化
动态加载子菜单减少初始加载时间。对于大型导航,提供搜索或快捷操作功能。确保导航在移动端可通过汉堡菜单调用,并适配触控操作。
无障碍适配
支持键盘导航(Tab键切换),提供ARIA标签说明。颜色对比度符合WCAG标准,图标需附带文字说明以兼容屏幕阅读器。
2、主窗体布局设计
主窗体布局设计需要考虑用户交互的便捷性和视觉舒适度。采用清晰的区域划分,确保功能模块易于访问。常见的布局方式包括单窗口、多文档界面(MDI)或标签式布局,具体选择取决于应用类型和功能复杂度。
保持一致的间距和对齐方式,避免元素拥挤或分散。使用网格系统辅助控件排列,确保界面整洁。重要功能或高频操作应放置在显眼位置,例如顶部工具栏或侧边栏。
常见布局模式
顶部导航+侧边栏+内容区
顶部放置应用标题和全局导航,左侧设置功能菜单或工具面板,中央区域作为主要内容展示区。这种模式适合功能较多的桌面应用,如设计软件或开发工具。
全屏内容+浮动面板
主窗口以内容展示为核心,辅助功能以可折叠面板形式出现。适合媒体编辑类软件,如视频剪辑或图像处理工具,能最大化工作区利用率。
卡片式平铺布局
将功能模块以等比例卡片形式平铺在主窗口,通过视觉层次区分优先级。适用于数据仪表盘或控制中心类应用,信息呈现直观清晰。
响应式设计要点
考虑窗口大小变化时的布局适应性。定义最小窗口尺寸限制,防止内容挤压变形。使用锚定(Anchoring)和停靠(Docking)技术确保控件随窗口缩放时保持相对位置。
为高分辨率屏幕提供多套尺寸方案,确保图标和文字在不同DPI设置下清晰可见。重要按钮和交互元素应设置在鼠标热区范围内,减少操作疲劳。
视觉层次构建
通过颜色对比、阴影效果或间距区分不同功能区块。主操作按钮使用强调色突出显示,次级功能采用中性色调。保持字体类型不超过三种,通过字号差异建立信息层级。
状态栏和提示信息使用低饱和度色彩,避免分散注意力。动态元素如进度条或通知标志需设计醒目但不过度干扰。
辅助功能考虑
为视力障碍用户提供高对比度模式选项,支持键盘快捷键操作所有功能。控件间Tab顺序需符合逻辑流,焦点状态应有明显视觉反馈。界面文字应支持动态缩放,避免固定像素单位。
布局设计如图:
左侧里面又定义了3行,每行放不同的内容,分别是图标,菜单,按钮,其中菜单通过TreeView控件实现,当点击不同treeitem时,呈现不同的内容显示在右侧,treeview控件点击事件由TvMenu_SelectionChanged事件来处理,样式由TreeView.ItemTemplate模板来定义,前面提到过国内优秀的WPF开源控件库,Panuon.UI.Silver,它能提供很好的样式,如图所示:
完整代码如下:
<pu:WindowX
x:Class="HQ.fResApp.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:local="clr-namespace:HQ.fResApp"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:pu="clr-namespace:Panuon.UI.Silver;assembly=Panuon.UI.Silver"
Width="1000"
Height="500"
pu:WindowXCaption.HideBasicButtons="True"
BorderThickness="0"
WindowStartupLocation="CenterScreen"
WindowState="Maximized"
xmlns:vm="clr-namespace:HQ.fResApp.ViewModel"
mc:Ignorable="d">
<Window.DataContext>
<vm:MainVModel/>
</Window.DataContext>
<Grid>
<Grid x:Name="HasDataBlock">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- 左侧菜单栏 -->
<Grid
Grid.Column="0"
Margin="0,-35,0,0"
Background="#394050">
<Grid.RowDefinitions>
<RowDefinition Height="80" />
<RowDefinition />
<RowDefinition Height="80" />
</Grid.RowDefinitions>
<!-- 系统Logo -->
<TextBlock
Grid.Row="0"
Padding="50,30,50,30"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="#282e3a"
FontFamily="Segoe UI"
FontSize="23"
FontWeight="Bold"
Foreground="White">
<Run>蜀 味</Run>
<Run Foreground="#FF67DA82">正 道</Run>
<TextBlock.Effect>
<DropShadowEffect
BlurRadius="10"
Opacity="0.5"
ShadowDepth="0"
Color="White" />
</TextBlock.Effect>
</TextBlock>
<!-- 菜单列表 -->
<TreeView
x:Name="trMenu"
Grid.Row="1"
pu:TreeViewHelper.ItemHeight="100"
pu:TreeViewHelper.SelectedBackground="#AA3366"
pu:TreeViewHelper.SelectedForeground="#ffffff"
pu:TreeViewHelper.TreeViewStyle="Classic"
Background="Transparent"
BorderBrush="White"
Foreground="#efefef"
ItemsSource="{Binding MenuItems}"
SelectedItemChanged="TvMenu_SelectionChanged">
<TreeView.ItemContainerStyle>
<Style BasedOn="{StaticResource {x:Type TreeViewItem}}" TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelect}" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=TreeViewItemModel}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Image
Margin="-15,-5,0,0"
Source="{Binding Path=Icon}"
Stretch="None" />
<TextBlock
Grid.Row="1"
Margin="-15,10,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="16"
FontWeight="Bold"
Text="{Binding Path=Header}" />
</Grid>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<!-- 退出系统 -->
<StackPanel
Grid.Row="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Cursor="Hand"
Orientation="Horizontal"
ToolTip="退出系统前,请确保当前操作已经无误!">
<Button
HorizontalAlignment="Center"
VerticalAlignment="Center"
pu:ButtonHelper.ButtonStyle="Link"
pu:ButtonHelper.HoverBrush="White"
pu:ButtonHelper.Icon="/HQ.fResApp;component/Resources/icon/out.png"
pu:IconHelper.Width="45"
Click="WindowX_Closing"
Content="退出"
FontFamily="Segoe UI"
FontSize="17"
FontWeight="ExtraBold"
Foreground="White" />
</StackPanel>
</Grid>
<!-- 右侧内容栏 -->
<Grid Grid.Column="1" Margin="0,-35,0,0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel VerticalAlignment="Center" Orientation="Horizontal">
<TextBlock
x:Name="txtStoreName1"
Margin="20,0,0,0"
FontFamily="Champagne & Limousines"
FontSize="23"
FontWeight="Bold"
Foreground="#5f5f5f"
Text="牛牪犇火锅店"
Visibility="Collapsed" />
</StackPanel>
<StackPanel
Grid.Column="1"
Margin="0,0,20,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Orientation="Horizontal">
<pu:DropDown
HorizontalAlignment="Left"
VerticalAlignment="Top"
Cursor="Hand">
<StackPanel VerticalAlignment="Center" Orientation="Horizontal">
<TextBlock
x:Name="txtStoreName"
Margin="0,10,5,0"
VerticalAlignment="Center"
FontSize="16"
FontWeight="DemiBold"
Foreground="#909399"
Text="牛牪犇火锅(安南旗舰店)" />
<Border
x:Name="uheadimg"
Width="45"
Height="45"
Margin="0,5,20,0"
BorderBrush="#F0F0F0"
BorderThickness="1"
CornerRadius="30">
<Border.Background>
<ImageBrush ImageSource="/HQ.fResApp;component/Resources/icon/logo.png" />
</Border.Background>
</Border>
</StackPanel>
<pu:DropDown.Child>
<Grid Width="100">
<Grid.RowDefinitions>
<RowDefinition Height="55" />
<RowDefinition Height="55" />
</Grid.RowDefinitions>
<Grid Margin="15,0" Cursor="Hand">
<Button
Height="30"
VerticalAlignment="Center"
pu:ButtonHelper.HoverBrush="Transparent"
Background="Transparent"
Click="ToUInfo_Click"
Content="个人中心"
FontFamily="/Panuon.UI.Silver;component/Resources/#fontawesome"
Foreground="#909399" />
</Grid>
<Border
Width="80"
VerticalAlignment="Bottom"
BorderBrush="#EEEEEE"
BorderThickness="0,0,0,1" />
<Grid
Grid.Row="1"
Margin="15,0"
Cursor="Hand">
<Button
Height="30"
VerticalAlignment="Center"
pu:ButtonHelper.HoverBrush="Transparent"
Background="Transparent"
Click="WindowX_Closing"
Content="退出登录"
FontFamily="/Panuon.UI.Silver;component/Resources/#fontawesome"
Foreground="#909399" />
</Grid>
</Grid>
</pu:DropDown.Child>
</pu:DropDown>
</StackPanel>
</Grid>
<ContentControl x:Name="ContentControl" Grid.Row="1" />
</Grid>
</Grid>
</Grid>
</Grid>
</pu:WindowX>
3、主窗体业务逻辑
这块业务是指当登录成功后,必须将用户拥有的菜单显示出来,所以涉及到后台的用户,角色,菜单多个表的关联,因此必须从dal到bll的代码。
4、主窗体视图模型
后台逻辑代码
using HQ.COMM;
using HQ.fResApp.BaseModel;
using HQ.fResApp.ViewModel;
using Panuon.UI.Silver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace HQ.fResApp
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : WindowX
{
private static IDictionary<string, Type> _partialViewDic;
static MainWindow()
{
_partialViewDic = new Dictionary<string, Type>();
var assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.FullName.StartsWith("HQ.fResApp"));
assembly.GetTypes().Where(x => x.Namespace.StartsWith("HQ.fResApp.UControls") && x.IsSubclassOf(typeof(UserControl))).ToList().ForEach(x => _partialViewDic.Add(x.Name, x));
}
public MainWindow()
{
InitializeComponent();
}
#region EventHandler
private void TvMenu_SelectionChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
try
{
//系统首次加载
if (!IsLoaded)
{
var _tag = _partialViewDic["CanTaiGuanLi"];
ContentControl.Content = Activator.CreateInstance(_tag);
}
//选择不同菜单项
var selectedItem = trMenu.SelectedItem as TreeViewItemModel;
var curTag = selectedItem.Tag;
if (curTag.IsNullOrEmpty()) return;
if (_partialViewDic.ContainsKey(curTag))
{
var _tag = _partialViewDic[curTag];
ContentControl.Content = Activator.CreateInstance(_tag);
}
else
{
ContentControl.Content = null;
}
}
catch (Exception ex)
{
ContentControl.Content = null;
Logger.Default.Error("切换系统菜单异常", ex);
}
}
private void WindowX_Closing(object sender, RoutedEventArgs e)
{
var result = MessageBoxX.Show("退出系统前,请确认当前操作处理完结?", "提示", this, MessageBoxButton.OKCancel);
if (result == MessageBoxResult.OK)
{
Application.Current.Shutdown();
}
}
private void ToUInfo_Click(object sender, RoutedEventArgs e)
{
}
#endregion
}
}
5、测试效果
点击左侧不同菜单呈现不同内容
原创不易,打字截图不易,走过路过,不要错过,欢迎点赞,收藏,转载,复制,抄袭,留言,动动你的金手指,早日实现财务自由!