使用 WPF 和 MySQL 搭建小型人资管理系统——登录页与主界面

终于开始写第二篇了... 加油加油,我要坚持写完这个系列...
从这一篇开始,我会从项目的流程和结构角度来介绍,中间穿插介绍遇到的问题和坑。

开始!


(本篇主要介绍登录页和主界面的框架布局)

项目情况说明

主要功能:对员工信息进行增删改查,生成特定格式的评估表单并打印,用户管理(可能有多个使用者通过不同的用户名和密码登录,需要管理)
用户:高管以及人资部门的员工。前者通过程序查看员工的详细信息不进行其他操作,后者通过程序来编辑和管理员工的信息。
部署方式:我们把程序部署在公司人资部的几台电脑上,把员工信息数据库部署在公司服务器上。(不宜把这样的数据库放在个人电脑上,一是不安全,二是不能满足绝大多数时间都能提供服务的要求)

程序和界面逻辑

首先需要登录,登录成功后,可进入“人事管理”、“用户管理”、“数据备份”、“帮助页面”。重点说一下人事管理页面,在此页面中可看到员工的信息表,并可查看每个员工的详细信息,以及进行添加、修改和删除操作。

登录界面

WPF 的界面通过拖拽就可以生成,我的做法是先拖拽出一个大致的界面,再通过 visual studio 侧边的属性栏或者修改 XAML 代码来进行更精细的调节,比如控制字号、颜色或对齐方式等。经过一顿折腾,做出来了如下的界面:(图标来自 Iconfont,阿里的矢量图标库)

登录界面.png

开发过程中,遇到了许多大大小小的问题,依据回忆依次记录如下...

  • 如何引用这些图标?

百度这个问题,可以有好几种解决方式,这里给出两种比较简单的,一是使用绝对路径,也就是在 image 标签中加上 Source="C:\Users\admin\Desktop\icon\password.png"这样的路径说明就可以。但是这样的话相当于写死了代码,不是很推荐。我最终使用的是第二种方式,即相对路径。先在项目目录下新建一个文件夹并右键添加现有项,然后用如图所示的方式来进行引用即可。

相对路径的使用.png

  • 用户名使用的是 WPF 自带的 TextBox 控件,如何显示灰字提示?

在 XAML 的TextBox中加上如下代码:

                <TextBox.Resources>
                    <VisualBrush x:Key="HelpBrush"
                                 Opacity="0.4"
                                 Stretch="None"
                                 AlignmentX="Left">
                        <VisualBrush.Visual>
                            <TextBlock  Text="请输入用户名"
                                        FontSize="16" />
                        </VisualBrush.Visual>
                    </VisualBrush>
                </TextBox.Resources>
                <TextBox.Style>
                    <Style TargetType="TextBox">
                        <Style.Triggers>
                            <Trigger Property="Text"
                                     Value="">
                                <Setter Property="Background"
                                        Value="{StaticResource HelpBrush}" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </TextBox.Style>
  • 密码框使用的是 WPF 自带的 PasswordBox 控件,但是由于提供给我们的属性有限,它并不能像 TextBox 那样设置提示信息,怎么办?

答案是只能自己实现一个...好在 Stackoverflow 上已经有人解决了这个问题,首先我们需要在 XAML 对应的 .cs 文件中的类后面加上下面的类和方法:

public class PasswordBoxMonitor : 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(PasswordBoxMonitor), new UIPropertyMetadata(false, OnIsMonitoringChanged));

        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(PasswordBoxMonitor), new UIPropertyMetadata(0));

        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;
            }
        }

        static void PasswordChanged(object sender, RoutedEventArgs e)
        {
            var pb = sender as PasswordBox;
            if (pb == null)
            {
                return;
            }
            SetPasswordLength(pb, pb.Password.Length);
        }
    }

接下来返回到 XAML 文件中,在开头的地方(我们定义的第一个控件之前)加上下面一段定义 PasswordBox 属性的代码:

<Window.Resources>
        <Style x:Key="{x:Type PasswordBox}"
               TargetType="{x:Type PasswordBox}">
            <Setter Property="DatabaseProject:PasswordBoxMonitor.IsMonitoring"
                    Value="True" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type PasswordBox}">
                        <Border Name="Bd"
                                Background="{TemplateBinding Background}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                SnapsToDevicePixels="true">
                            <Grid>
                                <ScrollViewer x:Name="PART_ContentHost"
                                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                                <TextBlock Text="请输入密码"
                                           Margin="4, 6, 0, 0"
                                           Foreground="#999999"
                                           FontSize="16"
                                           Visibility="Collapsed"
                                           Name="txtPrompt" />
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsEnabled"
                                     Value="false">
                                <Setter TargetName="Bd"
                                        Property="Background"
                                        Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
                                <Setter Property="Foreground"
                                        Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                            </Trigger>
                            <Trigger Property="DatabaseProject:PasswordBoxMonitor.PasswordLength"
                                     Value="0">
                                <Setter Property="Visibility"
                                        TargetName="txtPrompt"
                                        Value="Visible" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

虽然看着多,但是思路还是很清楚的,相当于先写个类,再定义属性,就可以在属性中设置灰色的提示文字了。

除了这些问题,登录时还需要与数据库内容进行比较,从而验证用户名和密码是否正确匹配。这部分内容现在先不写,准备放到后面和其他数据库操作一起讲 : )

主界面

主界面大致长这样:(不要嫌弃它太空,这是个演示...)


主界面.png

可以将它作为一个欢迎页面,在里面加上提示性文字或注意事项。

  • 如何写这样的界面?如何实现点击不同的菜单栏就跳转到不同的页面?

页面布局使用了 DockPanel,这是一种可以使元素停靠在页面特定方向的布局。此处先定义了顶部和底部的元素(即菜单和状态栏),然后再定义 Frame,这样 Frame 就会位于中间。Frame 的作用是嵌入某个 Page 到 Window 中,此处将显示欢迎信息和注意事项的 WelcomePage 放在了主界面中,并禁用了导航栏。当点击菜单项时,Frame 可以显示其他 Page 的内容。简化后的页面元素如下所示:

<Viewbox>
        <!--通过Viewbox可以实现缩放页面时其中的元素也跟着缩放的效果,用于屏幕适配-->
        <Canvas Height="1000"
                Width="1920">
            <DockPanel Background="#F9F9F9"
                       LastChildFill="False"
                       Height="1000"
                       Width="1920">
                <Menu DockPanel.Dock="Top">
                    <!--给四个菜单项添加监听事件-->
                    <MenuItem Header="人事管理"
                              Click="RenShi_Click"/>
                    <MenuItem Header="用户管理"
                              Click="YongHu_Click"/>
                    <MenuItem Header="数据备份"
                              Click="BeiFen_Click"/>
                    <MenuItem Header="帮助"
                              Click="BangZhu_Click"/>
                </Menu>
                <StatusBar DockPanel.Dock="Bottom"/>
                <Frame x:Name="mainframe"
                       Source="WelcomePage.xaml"
                       NavigationUIVisibility="Hidden"></Frame>
            </DockPanel>
        </Canvas>
    </Viewbox>

在 .cs 文件中,以人事管理菜单项的点击事件为例,通过public static Page1 p1;定义静态变量 p1,其中 Page1 是另一个新建的 Page 如下所示:

private void RenShi_Click(object sender, RoutedEventArgs e)
        {
            if (p1 == null)
            {
                p1 = new Page1(page1_para);
            }
            //通过Navigate方法可以让Frame显示p1的内容,从而实现跳转
            mainframe.Navigate(p1);
        }

这样就可以点击实现菜单栏跳转的功能了。

OK,这篇就写到这里,下一篇会阐述不同页面之间的关系,以及每个页面中比较难实现的部分,下次见~~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,951评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,606评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,601评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,478评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,565评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,587评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,590评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,337评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,785评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,096评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,273评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,935评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,578评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,199评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,440评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,163评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,133评论 2 352

推荐阅读更多精彩内容

  • 前言 本人是某211的计算机系大四学生,虽然菜但是热爱学习,希望能在各方面提高自己。九月刚开学不久,经同学介绍,接...
    Alpenbelieve阅读 767评论 0 5
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,087评论 4 62
  • 我有一个名字叫晶晶。毕业了两年了,换了三分工作,第一份工作,做的是一个妇产科医助,当时觉得自己的收入还可以,但是...
    不思不想不理阅读 149评论 0 0
  • 区块链(Blockchain)是由节点参与的分布式数据库系统{{1}},它的特点是不可更改,不可伪造,也可以将其理...
    炸酱乌冬面阅读 11,151评论 0 0
  • 有没有这样的一个人存在,她是你的故友,因为种种原因你们已经不大联系,但每每看到她的一些消息,你就会感到很开心?我有...
    车小刀阅读 150评论 0 0