C# WPF上位机开发(会员管理软件)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        好多同学都认为上位机只是纯软件开发,不涉及到硬件设备,比如听听音乐、看看电影、写写小的应用等等。如果是消费电子,确实可能是这种情况。但是除了消费电子、互联网领域之外,上位机还可能涉及到工业生产、医疗和军工领域,每一个细分市场都有很大的规模。这个时候,上位机就可能需要通过USB、can、232、485、网络等很多cabel形式和外部设备进行沟通,那么上位机的功能边际就会一下子拓展很多。此外,就算是同一个领域,不同的行业也都会有不同的know-how,很多的know-how就是以软件的形式固化在软件逻辑里面的,这就是上位机真正的竞争力。

        当然说了这么多,今天我们还是从简单的会员管理软件说起。通俗一点说,它就是简单的学生管理系统。所以的文件需要保存到一个文本里面,通常可以认为是json形式。软件启动后,界面可以完成增删改查的操作。当然,我们可以说增删改查不是那么高端,但它确实软件开发很基础的一个环节。

1、确定文件保存的形式,比如data.json

{
  "count": 6,
  "items": [
    {
      "ID": 1,
      "NAME": "aaa"
    },
    {
      "ID": 2,
      "NAME": "bbb"
    },
    {
      "ID": 3,
      "NAME": "ccc"
    },
    {
      "ID": 5,
      "NAME": "ddd"
    },
    {
      "ID": 6,
      "NAME": "eee"
    },
    {
      "ID": 4,
      "NAME": "fff"
    }
  ]
}

        目前如果不用数据库的话,比较方便数据读取和保存的方式就是json格式。如上图所示,这里包含了数据的基本信息,包括了数据的数量,每一组数据的ID和NAME等等。

2、使用Newtonsoft.Json库读写json文件

        前面我们决定用json格式读写文件,接下来需要面对的问题就是如何解析和保存这些数据。好在NuGet上面可以通过第三方库Newtonsoft.Json来直接解析json文件,这就变得非常方便了。

3、设计界面

        界面部分的设计不难。简单一点难说,可以分成两个部分。左边就是数据的增删改查工作,右边就是当前所有数据的显示部分。之所以要添加右边这部分显示内容,主要还是为了直观地去观察,我们当前的操作有没有问题。

        设计好界面之后,再转成xaml代码就不难了,

<Window x:Class="WpfApp.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:WpfApp"
        mc:Ignorable="d"
        Title="MemberInfo" Height="300" Width="800">
    <Grid>
        <RadioButton x:Name="radio_add" Checked="Add_Checked" Content="add" HorizontalAlignment="Left" Margin="51,44,0,0" VerticalAlignment="Top"/>
        <RadioButton x:Name="radio_del" Checked="Del_Checked" Content="del" HorizontalAlignment="Left" Margin="129,44,0,0" VerticalAlignment="Top"/>
        <RadioButton x:Name="radio_update" Checked="Update_Checked" Content="update" HorizontalAlignment="Left" Margin="194,44,0,0" VerticalAlignment="Top"/>
        <RadioButton x:Name="radio_search" Checked="Search_Checked" Content="search" HorizontalAlignment="Left" Margin="284,44,0,0" VerticalAlignment="Top"/>

        <Label Content="ID:" HorizontalAlignment="Left" Margin="75,97,0,0" VerticalAlignment="Top"/>
        <TextBox x:Name="id" HorizontalAlignment="Left" Height="23" Margin="193,97,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120"/>
        <Label Content="Name" HorizontalAlignment="Left" Margin="75,134,0,0" VerticalAlignment="Top"/>
        <TextBox x:Name="name" HorizontalAlignment="Left" Height="23" Margin="193,138,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" RenderTransformOrigin="0.498,2.609"/>

        <Button Content="OK" Click="OK_Click" HorizontalAlignment="Left" Margin="51,202,0,0" VerticalAlignment="Top" Width="75"/>
        <Button Content="Cancel" Click="Cancel_Click" HorizontalAlignment="Left" Margin="157,202,0,0" VerticalAlignment="Top" Width="75"/>
        <Button Content="Save" Click="Save_Click" HorizontalAlignment="Left" Margin="263,202,0,0" VerticalAlignment="Top" Width="75"/>

        <Label Content="Member Details" HorizontalAlignment="Left" Margin="435,38,0,0" VerticalAlignment="Top"/>
        <TextBox x:Name="all_data" HorizontalAlignment="Left" Height="146" Margin="435,75,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="315"/>
        <Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="235" Margin="395,10,0,0" VerticalAlignment="Top" Width="376"/>
        <Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="235" Margin="15,10,0,0" VerticalAlignment="Top" Width="360"/>
    </Grid>
</Window>

        软件部分的控件都是常见的控件,比如RadioButton、Label、TextBox、Button,同时为了进行左右区别,我们还额外添加了一个Boarder,这样稍微美观一点。

4、代码编写

        代码整体上难度不大,最重要的就是OK按钮的处理,因为它需要判断下当前是哪一种操作模式,是添加,还是其他的操作模式。每一种操作模式的处理逻辑也是不一样的。这部分内容大家可以直接查看OK_Click的函数内容。

        除了OK按钮的处理之外,另外比较重要的代码,就是json文件的加载和保存。加载是在软件启动的时候自动加载的,而保存则需要用户单击Save按钮才会自动保存。

        最后大家可以关注下update_data这个函数,只要是正常的操作,数据内容发生变化,都会调用这个函数更新Textbox里面的内容。

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.Navigation;
using System.Windows.Shapes;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace WpfApp
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private int select_option = 0;
        private int total = 0;
        private int[] id_array = new int[1000];
        private string[] name_array = new string[1000];

        public MainWindow() // construct function
        {
            InitializeComponent();

            // initialize data
            for(int i = 0; i < 1000;i++)
            {
                id_array[i] = 0;
                name_array[i] = "";
            }

            // load file defined here
            load_file();

            radio_add.IsChecked = true; // set as default value

            //display data here
            all_data.Text = "";
            all_data.IsEnabled = false;
            update_data();
        }

        private void load_file()
        {
            string jsonfile = "data.json";
            JObject jObject;
            JToken items;

            // parse script file
            using (System.IO.StreamReader file = System.IO.File.OpenText(jsonfile))
            {
                using (JsonTextReader reader = new JsonTextReader(file))
                {
                    jObject = (JObject)JToken.ReadFrom(reader);
                }
            }

            // fetch data from json script
            total = Convert.ToInt32(jObject["count"].ToString());
            if(total <= 0)
            {
                return;
            }

            items = jObject["items"];
            if(items == null)
            {
                return;
            }

            // fetch each data
            for (int i = 0; i < total; i ++)
            {
                int id = Convert.ToInt32(items[i]["ID"].ToString());
                string name = items[i]["NAME"].ToString();

                id_array[i] = id;
                name_array[i] = name;
            }
        }

        private void OK_Click(object sender, RoutedEventArgs e)
        {
            int id_val;
            string name_val = name.Text;
            int i = 0;
            int j = 0;

            if (id.Text == "")
            {
                MessageBox.Show("ID input should not be empty!");
                return;
            }

            id_val = Convert.ToInt32(id.Text);
            if(id_val >= 1000)
            {
                MessageBox.Show("ID should be smaller than 1000!");
                goto Final;
            }

            switch(select_option)
            {
                case 1: //add
                    if(name_val == "")
                    {
                        MessageBox.Show("Name can not be empty!");
                        goto Final;
                    }

                    if (total == 1000)
                    {
                        MessageBox.Show("Array is full!");
                        goto Final;
                    }

                    for (i = 0; i < total; i++)
                    {
                        if(id_array[i] == id_val)
                        {
                            MessageBox.Show("Find same id!");
                            goto Final;
                        }
                    }

                    id_array[total] = id_val;
                    name_array[total] = name_val;
                    total += 1;
                    MessageBox.Show("Add successfully!");
                    break;

                case 2://del
                    if (total == 0)
                    {
                        MessageBox.Show("Array is empty!");
                        goto Final;
                    }

                    for (i = 0; i < total; i++)
                    {
                        if (id_array[i] == id_val)
                        {
                            break;
                        }
                    }

                    if(i == total)
                    {
                        MessageBox.Show("Failed to find relevant id!");
                        goto Final;
                    }
                    
                    for(j = i+1; j < total; j++)
                    {
                        id_array[j - 1] = id_array[j];
                        name_array[j - 1] = name_array[j];
                    }
                    total -= 1;
                    MessageBox.Show("Del successfully!");
                    break;

                case 3://update
                    if (name_val == "")
                    {
                        MessageBox.Show("Name can not be empty!");
                        goto Final;
                    }

                    if (total == 0)
                    {
                        MessageBox.Show("Array is empty!");
                        goto Final;
                    }

                    for (i = 0; i < total; i++)
                    {
                        if (id_array[i] == id_val)
                        {
                            break;
                        }
                    }

                    if (i == total)
                    {
                        MessageBox.Show("Failed to find relevant id!");
                        goto Final;
                    }

                    name_array[i] = name_val;
                    MessageBox.Show("Update successfully!");
                    break;

                case 4://search
                    if (total == 0)
                    {
                        MessageBox.Show("Array is empty!");
                        goto Final;
                    }

                    for (i = 0; i < total; i++)
                    {
                        if (id_array[i] == id_val)
                        {
                            break;
                        }
                    }

                    if (i == total)
                    {
                        MessageBox.Show("Failed to find relevant id!");
                        goto Final;
                    }

                    MessageBox.Show("Name is " + name_array[i]);
                    break;

                default:
                    break;
            }

            // display data
            update_data();

        Final:
            id.Text = "";
            name.Text = "";
        }

        private void update_data()
        {
            string data_text = "";

            for(int i = 0; i < total;i++)
            {
                data_text += Convert.ToString(id_array[i]);
                data_text += " ";
                data_text += name_array[i];
                data_text += "\n";
            }

            all_data.Text = "";
            all_data.Text = data_text;
        }

        private void Cancel_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }

        private void Save_Click(object sender, RoutedEventArgs e) // important callback function
        {
            JArray items = new JArray();
            JObject header = new JObject();

            // save to array
            for(int i = 0; i < total; i++)
            {
                JObject jobj = new JObject();
                jobj["ID"] = id_array[i];
                jobj["NAME"] = name_array[i];
                items.Add(jobj);
            }

            // save to header
            header["count"] = total;
            header["items"] = items;

            // save data
            using (System.IO.StreamWriter file = new System.IO.StreamWriter("data.json"))
            {
                file.Write(header.ToString());
            }
            MessageBox.Show("Save successfully!");
        }

        private void Add_Checked(object sender, RoutedEventArgs e)
        {
            select_option = 1; //add
            name.IsEnabled = true;
        }

        private void Del_Checked(object sender, RoutedEventArgs e)
        {
            select_option = 2; //del
            name.Text = "";
            name.IsEnabled = false;
        }

        private void Update_Checked(object sender, RoutedEventArgs e)
        {
            select_option = 3; //update
            name.IsEnabled = true;
        }

        private void Search_Checked(object sender, RoutedEventArgs e)
        {
            select_option = 4; //search
            name.Text = "";
            name.IsEnabled = false;
        }
    }
}

        至于说代码中的入参处理、异常处理、使用习惯处理,这些部分只能靠大家自己去慢慢体会和了解了。有了这份代码做基础,以后的crud代码,也就是增删改查操作都逃不了这个范畴。而且我们的数据是真正保存在json文件中的,不存在丢失的风险,这也让开发的软件进一步拓展了实用性和可靠性。

5、运行测试

        运行测试就比较简单了,直接编译执行就好了,不出意外就可以看到这样的运行画面了,和之前设计稍微有点区别,

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/233173.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

人工智能从 DeepMind 到 ChatGPT ,从 2012 - 2024

本心、输入输出、结果 文章目录 人工智能从 DeepMind 到 ChatGPT &#xff0c;从 2012 - 2024前言2010年&#xff1a;DeepMind诞生2012&#xff5e;2013年&#xff1a;谷歌重视AI发展&#xff0c;“拿下”Hinton2013&#xff5e;2014年&#xff1a;谷歌收购DeepMind2013年&…

调用别人提供的接口无法通过try catch捕获异常(C#),见鬼了

前几天做CA签名这个需求时发现一个很诡异的事情&#xff0c;CA签名调用的接口是由另外一个开发部门的同事(比较难沟通的那种人)封装并提供到我们这边的。我们这边只需要把数据准备好&#xff0c;然后调他封装的接口即可完成签名操作。但在测试过程中&#xff0c;发现他提供的接…

2024年网络安全竞赛-数字取证调查attack817

​ 数字取证调查 (一)拓扑图 服务器场景:FTPServer20221010(关闭链接) 服务器场景操作系统:未知 FTP用户名:attack817密码:attack817 分析attack.pcapng数据包文件,通过分析数据包attack.pcapng找出恶意用户第一次访问HTTP服务的数据包是第几号,将该号数作为Flag值…

力扣刷题总结 字符串(2)【KMP】

&#x1f525;博客主页&#xff1a; A_SHOWY&#x1f3a5;系列专栏&#xff1a;力扣刷题总结录 数据结构 云计算 数字图像处理 28.找出字符串中第一个匹配项的下标mid经典KMP4593重复的子字符串mid可以使用滑动窗口或者KMP KMP章节难度较大&#xff0c;需要深入理解其中…

Uncaught SyntaxError: Unexpected end of input (at manage.html:1:21) 的一个解

关于Uncaught SyntaxError: Unexpected end of input (at manage.html:1:21)的一个解 问题复现 <button onclick"deleteItem(${order.id},hire,"Orders")" >delete</button>报错 原因 函数参数的双引号和外面的双引号混淆了&#xff0c;改成…

数据可视化|jupyter notebook运行pyecharts,无法正常显示“可视化图形”,怎么解决?

前言 本文是该专栏的第39篇,后面会持续分享python数据分析的干货知识,记得关注。 相信有些同学在本地使用jupyter notebook运行pyecharts的时候,在代码没有任何异常的情况下,无论是html还是notebook区域,都无法显示“可视化图形”,界面区域只有空白一片。遇到这种情况,…

精选Axure原型设计模板,RP原型组件库(PC端移动端元件库及Axure函数及运算符说明)

好的原型组件会大大的提高产品经理的工作效率&#xff0c;小7在陆续整理、精选Axure 8的原型设计模板&#xff0c;包含了原型设计的常用元素和AxureRP 8函数及运算符的说明文档&#xff0c;及各种设备模板框架。 本文也是基于小7另一篇文章的补充&#xff0c;更多更详细的资料…

ffprobe命令行超详细使用详解

本文做为阅读ffprobe源码的前课程。为了之后方便理解ffprobe的源码,咱们先从ffprobe的命令学习。 课程内容如下: 文章目录 一、ffprobe主要选项说明1、每次使用ffprobe都打印编译环境的信息,太烦了2、如何分析媒体文件中存在的流信息3、如何指定查询某路流信息4、查看输入文…

2020年第九届数学建模国际赛小美赛B题血氧饱和度的变异性解题全过程文档及程序

2020年第九届数学建模国际赛小美赛 B题 血氧饱和度的变异性 原题再现&#xff1a; 脉搏血氧饱和度是监测患者血氧饱和度的常规方法。在连续监测期间&#xff0c;我们希望能够使用模型描述血氧饱和度的模式。   我们有36名受试者的数据&#xff0c;每个受试者以1 Hz的频率连…

基于ssm人力资源管理系统论文

摘 要 随着企业员工人数的不断增多&#xff0c;企业在人力资源管理方面负担越来越重&#xff0c;因此&#xff0c;为提高企业人力资源管理效率&#xff0c;特开发了本人力资源管理系统。 本文重点阐述了人力资源管理系统的开发过程&#xff0c;以实际运用为开发背景&#xff0…

Qt开发 之 记一次安装 Qt5.12.12 安卓环境的失败案例

文章目录 1、安装Qt2、安卓开发的组合套件2.1、CSDN地址2.2、官网地址2.3、发现老方法不适用了 3、尝试用新方法解决3.1、先安装JDK&#xff0c;搞定JDK环境变量3.1.1、安装jdk3.1.2、确定jdk安装路径3.1.3、打开系统环境变量配置3.1.4、配置系统环境变量3.1.5、验证JDK环境变量…

OrangePi ZERO2 刷机与启动

镜像准备 用读卡器和Win32Diskimager刷写镜像到内存卡&#xff0c;镜像文件见下面百度云链接&#xff1a;https://pan.baidu.com/s/14aKTznc4Jvw4SoFF54JUTg 提取码&#xff1a;1815 刷写完毕后插回香橙派 串口登录 用MobaXterm和USB-TTL进行串口登录&#xff0c;MobaXterm软…

线程安全3--wait和notify

文章目录 wait and notify&#xff08;等待通知机制notify补充 wait and notify&#xff08;等待通知机制 引入wait notify就是为了能够从应用层面上&#xff0c;干预到多个不同线程代码的执行顺序&#xff0c;这里说的干预&#xff0c;不是影响系统的线程调度策略&#xff08…

持续集成交付CICD:Jenkins流水线实现Nexus制品晋级策略

目录 一、理论 1.开发测试运维环境 二、实验 1.Nexus制品晋级策略 一、理论 1.开发测试运维环境 &#xff08;1&#xff09;环境 1&#xff09;持续集成开发环境&#xff08;DEV: Development Environment&#xff09; 直接通过源代码编译打包&#xff0c;其会跑单元测试…

C# | 使用AutoResetEvent和ManualResetEvent进行线程同步和通信

使用AutoResetEvent和ManualResetEvent进行线程同步和通信 文章目录 使用AutoResetEvent和ManualResetEvent进行线程同步和通信介绍AutoResetEventManualResetEvent 异同点使用场景和代码示例AutoResetEvent 使用示例ManualResetEvent 使用示例阻塞多个线程并同时激活 介绍 在…

fl studio2024官方体验版如何破解?

fl studio2024全称Fruity Loops Studio2024&#xff0c;这款软件也被人们亲切的称之为水果&#xff0c;它是一款功能强大的音乐创作编辑软件&#xff0c;拥有全功能的录音室&#xff0c;大混音盘以及先进的音乐制作工具&#xff0c;用户通过使用该软件&#xff0c;就可以轻松制…

MySQL的锁机制

1.简介 MySQL的隔离性是由锁机制来保证的。锁是计算机协调多个进程或线程并发地访问某一资源你的机制。当多线程并发地访问某个数据时&#xff0c;尤其是在涉及金钱等安全敏感性数据的时候&#xff0c;需要保证数据在任意时刻最多只有一个线程可以对其进行修改&#xff0c;从而…

class070 子数组最大累加和问题与扩展-上【算法】

class070 子数组最大累加和问题与扩展-上【算法】 code1 53. 最大子数组和 // 累加和最大子数组和 // 给你一个整数数组 nums // 请你找出一个具有最大累加和的非空子数组 // 返回其最大累加和 // 测试链接 : https://leetcode.cn/problems/maximum-subarray/ dp[i]&#xff…

Aloha 机械臂的学习记录2——AWE:AWE + ACT

继续下一个阶段&#xff1a; Train policy python act/imitate_episodes.py \ --task_name [TASK] \ --ckpt_dir data/outputs/act_ckpt/[TASK]_waypoint \ --policy_class ACT --kl_weight 10 --chunk_size 50 --hidden_dim 512 --batch_size 8 --dim_feedforward 3200 \ --n…

如何轻松恢复 Windows 中删除的文件夹

我们都曾经历过这样的事&#xff0c;而且我们中的大多数人可能很快就会再次这样做。我们讨论的是在 Windows 中按“Delete”或“ShiftDelete”键意外删除重要文件夹的情况。 如果您刚刚按下删除键且未超过 30 天&#xff0c;或者尚未清空回收站&#xff0c;则可以恢复文件夹。…