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

news2024/11/27 20:56:07

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱: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、运行测试

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DAPP开发【06】nodejs安装与npm路径更换

windows系统在执行用户命令时顺序 windows系统在执行用户命令时&#xff0c;若用户未给出文件的绝对路径&#xff0c; 则 &#xff08;1&#xff09;首先在当前目录下寻找相应的可执行文件、批处理文件等&#xff1b; &#xff08;2&#xff09;若找不到&#xff0c;再依次在系…

深入理解 new 操作符:创建对象的秘密武器(下)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

【开源】基于Vue.js的就医保险管理系统

文末获取源码&#xff0c;项目编号&#xff1a; S 085 。 \color{red}{文末获取源码&#xff0c;项目编号&#xff1a;S085。} 文末获取源码&#xff0c;项目编号&#xff1a;S085。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 科室档案模块2.2 医生档案模块2.3 预…

pycharm中debug,py文件

1、先把需要的实参传入 2、在合适位置打上断点 3、在小三角旁边右键调用调试 4.步进/步出查看 5.选择单步执行&#xff0c;走的更慢

使用函数计算,数禾如何实现高效的数据处理?

作者&#xff5c;邱鑫鑫&#xff0c;王彬&#xff0c;牟柏旭 公司背景和业务 数禾科技以大数据和技术为驱动&#xff0c;为金融机构提供高效的智能零售金融解决方案&#xff0c;服务银行、信托、消费金融公司、保险、小贷公司等持牌金融机构&#xff0c;业务涵盖消费信贷、小…

用窗函数法设计fir

FIR滤波器的设计可以通过窗函数法进行。窗函数法是一种通过在一定长度的数据窗口内&#xff0c;对数据进行加窗处理&#xff0c;然后再根据窗内数据的特征进行滤波器设计的方法。 以下是一个基本的步骤&#xff1a; 确定所需的滤波器参数&#xff0c;例如滤波器的阶数、过渡带…

[足式机器人]Part2 Dr. CAN学习笔记-数学基础Ch0-4线性时不变系统中的冲激响应与卷积

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-数学基础Ch0-4线性时不变系统中的冲激响应与卷积 1. LIT System&#xff1a;Linear Time Invariant2. 卷积 Convolution3. 单位冲激 Unit Impulse——Dirac Delta 线性时不变系统 &#xff1a; L…

封装校验规则(以及复选框和整体校验)-----Vue3+ts项目

登录校验页面 <script setup lang"ts"> import { ref } from vue import { mobileRules, passwordRules } from /utils/rules const mobile ref() const password ref() </script><!-- 表单 --><van-form autocomplete"off">&l…

Day52力扣打卡

打卡记录 Collapsing Strings&#xff08;Trie树&#xff09; 链接 #include <iostream> #include <algorithm> using namespace std; const int N 2e6 10; int son[N][26], idx, cnt1[N], cnt2[N]; int main() {auto insert [&](string& str, int* c…

换种方式开发软件

前 言 作为程序员&#xff0c;经常苦于项目交付&#xff0c;疲于应对各种需求&#xff0c;一路狂奔&#xff0c;很难有时间停下来思考与抽象&#xff0c;聊起来都是“累”&#xff1b;作为产品经理&#xff0c;最痛苦的莫过于梦醒之后无路可走&#xff0c;心里的苦只有自己知道…

如何统计12.5米高程覆盖率?

无论是卫星影像还是高程DEM数据&#xff0c;覆盖率都是大家非常关心的一个重要参数。 我们曾基于WGS84坐标进行过简单的覆盖率计算&#xff0c;而且面积还包括了海洋区域。 因此&#xff0c;最后得出了一个非常不靠谱&#xff0c;看起来也很不漂亮的数据&#xff1a;12%。 为…

python3安装lifelines

目录 一、环境 二、安装lifelines 出现问题 三、测试导入 一、环境&#xff1a; jupyter notebook中新建ipynb文件 二、安装lifelines pip install --upgrade --no-deps githttps://github.com/CamDavidsonPilon/lifelines.git出现问题&#xff1a; 缺少模块autograd、f…

视频相似度对比 python opencv sift flann

提取SIFT特征的代码&#xff0c;返回关键点kp及特征描述符des def SIFT(frame):# 创建SIFT特征提取器sift cv2.xfeatures2d.SIFT_create()# 提取SIFT特征kp, des sift.detectAndCompute(frame, None)return kp, des 这行代码是使用SIFT&#xff08;Scale-Invariant Feature…

【LeetCode:1466. 重新规划路线 | DFS + 图 + 树】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

SE考研真题总结(一)

本帖开始分享考研真题中设计【软件工程】的部分&#xff0c;预计会出5期左右&#xff0c;敬请期待~ 一.单选题 1.程序编写不是软件质量保障过程~ 静态代码扫描是今年来多数被人提及的软件应用安全解决方案之一&#xff0c;指程序员在编写好代码后无需进行编译&#xff0c;直接…

校园外卖小程序源码系统 附带完整的搭建教程

随着大学生消费水平的提高&#xff0c;对于外卖服务的需求也在不断增加。很多学生都面临着课业繁重、时间紧张等问题&#xff0c;无法亲自到餐厅就餐。因此&#xff0c;开发一款适合校园外卖市场的应用软件&#xff0c;将为广大学生提供极大的便利。 以下是部分代码示例&#…

WSL2+tensorflow-gpu 2.3.0 C++ 源码编译(Linux)

一. gcc版本 wsl2已有gcc 版本为9.4.0,但tensorflow2.3.0需对应gcc7.3.1 tensorflow与cuda cudnn python bazel gcc版本对应关系 故需下载一个低版本的gcc,但同时还想保留较高版本的gcc,那么参考文章:深度学习环境搭建(二): Ubuntu不同版本gcc,CUDA,cuDNN共存,切换解…

网络安全(一)--网络环境构成,系统的安全

2. 网络攻防环境 目标 了解攻防环境构成了解入侵检测系统&#xff08;平台&#xff09;的部署位置 2.1. 环境构成 2.1.1. 环境框图 一个基本的网络攻防实验环境包括&#xff1a;靶机、攻击机、入侵检测分析系统、网络连接四部分组成。 一个基础的网络攻防实验环境需要如下…

SpringSecurity6 | 默认用户生成(下)

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; Java从入门到精通 ✨特色专栏&#xf…

visionOS空间计算实战开发教程Day 9 打造“任意门”

我们在​​Day 8​​中演示了attachment的实现&#xff0c;本节的知识点是portal。portal相当于哆啦A梦里的任意门&#xff0c;它让我们可以打开另一个世界&#xff0c;这个世界独立于当前的世界&#xff0c;具有单独的光照系统并且由portal几何图形进行遮罩。 要创建portal&a…