分享

基于WPF+Sqlite开发抽奖软件【内附源码】

 老码识途 2024-05-22 发布于广东

在很早之前,就想开发一款抽奖软件,却没有实际去做,最近经过一段时间的准备,终于开发出了一款基于WPF+Sqlite版的抽奖软件,包括客户端和管理端。本项目主要是为了熟悉WPF开发流程,仅供学习分享使用,如有不足之处,还请指正。

涉及知识点


抽奖软件包括客户端和管理端,在开发过程中,主要用到如下知识点:

  • 开发工具:Visual Studio 2022

  • 开发框架:.NET6.0 + WPF

  • MVVM框架:CommunityToolkit.Mvvm 8.2.2

  • 数据库:Sqlite

  • ORM框架:SqlSugarCore 5.1.4.154

  • 数据库客户端:SQLiteStudio 3.4.4

数据表设计


根据抽奖软件的功能进行拆解,主要包括:

  • Gift(礼品表),存储礼品基础信息
  • Lucky(奖品表),存储奖品信息
  • User(抽奖用户表),存储需要抽奖的基础用户
  • Winner(中奖表),中奖明细

各个表详细创建语句如下所示:

Gift(礼品表),主要包括礼品名称,图片路径等,如下所示:
CREATE TABLE gift (    Id       INTEGER       PRIMARY KEY AUTOINCREMENT,    Name     VARCHAR (255),    ImageUrl VARCHAR (255) );

Lucky(奖品表),主要包括,奖品名称,数量,对应礼品ID,奖品等级(如:一等奖,二等奖),奖品类型,奖品排序(抽奖顺序),如下所示:

CREATE TABLE lucky (    Id         INTEGER      PRIMARY KEY AUTOINCREMENT,    Name       VARCHAR (50),    Count      INTEGER,    GiftId     INTEGER,    Level      INTEGER,    LuckyType  VARCHAR (50),    LuckyOrder INTEGER);

User(抽奖用户表),参与抽奖的用户,主要用户的名称,如下所示:

CREATE TABLE user (    Id   INTEGER      PRIMARY KEY AUTOINCREMENT,    Name VARCHAR (50) );

Winner(中奖表),主要包括中奖用户ID,奖品ID,中奖时间等。如下所示:

CREATE TABLE winner (    Id         INTEGER  PRIMARY KEY AUTOINCREMENT,    userid     INTEGER,    luckyid    INTEGER,    winnertime DATETIME);

功能设计


抽奖软件主要包括客户端,和管理端,主要功能如下:

  • 客户端,主要用于抽奖,包括首页,抽奖页面【Enter键开始和停止抽奖,Next键切换奖项】,结束语页面。
  • 管理端,主要用于管理数据信息,包括用户管理,礼品管理,奖品管理,中奖管理等功能,主要是对各个数据表的增删改查。

核心源码


本实例项目虽然比较小,但作为一个完整的项目,为了层次清晰及便于维护,采用MVVM开发模式,UI和业务逻辑分层处理,并单独封装DAL层。

1. 抽奖页面源码

整个项目最核心的就是抽奖页面,UI层代码如下所示:
<UserControl x:Class="EasyLucky.Views.Lucky"             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"             xmlns:mc="http://schemas./markup-compatibility/2006"              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"              xmlns:i="http://schemas.microsoft.com/xaml/behaviors"             xmlns:local="clr-namespace:EasyLucky.Views"             mc:Ignorable="d"              d:DesignHeight="450" d:DesignWidth="1000">    <i:Interaction.Triggers>        <i:EventTrigger EventName="Loaded">            <i:InvokeCommandAction Command="{Binding LoadedCommand}" PassEventArgsToCommand="True" ></i:InvokeCommandAction>        </i:EventTrigger>    </i:Interaction.Triggers>    <Grid>        <i:Interaction.Triggers>            <i:EventTrigger EventName="MouseDown">                <i:InvokeCommandAction Command="{Binding MouseDownCommand}" PassEventArgsToCommand="True" ></i:InvokeCommandAction>            </i:EventTrigger>        </i:Interaction.Triggers>        <Grid.ColumnDefinitions>            <ColumnDefinition></ColumnDefinition>            <ColumnDefinition></ColumnDefinition>        </Grid.ColumnDefinitions>        <Grid.RowDefinitions>            <RowDefinition Height="Auto"></RowDefinition>            <RowDefinition Height="*"></RowDefinition>            <RowDefinition Height="Auto"></RowDefinition>        </Grid.RowDefinitions>        <Border Grid.ColumnSpan="2" Grid.RowSpan="3">            <Image Source="/imgs/BG_12.jpg"  Stretch="Fill"></Image>        </Border>        <StackPanel Orientation="Horizontal" VerticalAlignment="Top" Margin="0 40 0 0" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center">            <TextBlock Text="正在抽取的是 " FontSize="40" Foreground="White" VerticalAlignment="Center"></TextBlock>            <TextBlock Text="{Binding DataM.CurLucky.Lucky.Level}" FontSize="60" Foreground="Gold" FontWeight="DemiBold"></TextBlock>            <TextBlock Text=" 等奖,共 " FontSize="40" Foreground="White" VerticalAlignment="Center"></TextBlock>            <TextBlock Text="{Binding DataM.CurLucky.Lucky.Count}" FontSize="60" Foreground="Gold" FontWeight="DemiBold"></TextBlock>            <TextBlock Text=" 名" FontSize="40" Foreground="White" VerticalAlignment="Center"></TextBlock>        </StackPanel>        <ItemsControl Grid.Row="1" Grid.Column="0" ItemsSource="{Binding DataM.CurUsers}" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center">            <ItemsControl.ItemsPanel>                <ItemsPanelTemplate>                    <UniformGrid Columns="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.DataM.Column}" Rows="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}},Path=DataContext.DataM.Row}" >                    </UniformGrid>                </ItemsPanelTemplate>            </ItemsControl.ItemsPanel>            <ItemsControl.ItemTemplate>                <DataTemplate>                    <TextBlock Text="{Binding Name}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="40" FontWeight="DemiBold" Foreground="White" Margin="30"></TextBlock>                </DataTemplate>            </ItemsControl.ItemTemplate>        </ItemsControl>                <StackPanel Margin="100 0 0 10" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Center">            <Grid>                <Grid.ColumnDefinitions>                    <ColumnDefinition></ColumnDefinition>                    <ColumnDefinition></ColumnDefinition>                </Grid.ColumnDefinitions>                <Grid.RowDefinitions>                    <RowDefinition></RowDefinition>                    <RowDefinition></RowDefinition>                </Grid.RowDefinitions>                <StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="0">                    <TextBlock Text="{Binding DataM.CurLucky.Lucky.Level}" FontSize="40" Foreground="Gold" FontWeight="DemiBold" VerticalAlignment="Center"></TextBlock>                    <TextBlock Text=" 等奖奖品" FontSize="40" Foreground="White" VerticalAlignment="Center"></TextBlock>                </StackPanel>                <TextBlock Text="{Binding DataM.CurLucky.Gift.Name}" FontSize="40" Grid.Row="1" Grid.Column="0" Foreground="Gold" FontWeight="DemiBold" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock>                <Image Margin="20 0 0 0" Source="{Binding DataM.CurLucky.Gift.ImageSource}" Stretch="Fill" Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" Width="200" Height="150"></Image>            </Grid>        </StackPanel>        <TextBlock x:Name="btn" Grid.Column="1" Grid.Row="2" Background="Transparent" Width="10" Height="10" Focusable="True" HorizontalAlignment="Right" VerticalAlignment="Bottom">            <i:Interaction.Triggers>                <i:EventTrigger EventName="KeyDown">                    <i:InvokeCommandAction Command="{Binding KeyDownCommand}" PassEventArgsToCommand="True"></i:InvokeCommandAction>                </i:EventTrigger>            </i:Interaction.Triggers>        </TextBlock>    </Grid></UserControl>

2. 业务逻辑代码

业务逻辑代码在ViewModel 中,包括开始,停止,切换等内容。如下所示:

开始抽奖,通过Enter键触发:
private void Start(){  cts = new CancellationTokenSource();  token = cts.Token;  task = Task.Run(() =>  {    var luckyCount = this.DataM.CurLucky.Lucky.Count;    var userCount = this.DataM.Users.Count;    var random = new Random(DateTime.Now.Second);    var rnd = random.Next(0,userCount);    int index = rnd;    if(index+luckyCount > userCount)    {      index = userCount - luckyCount;    }        while (!token.IsCancellationRequested)    {      var users=new List<User>();      if(index+luckyCount > userCount)      {        //读到最后再循环读取        for(int i = index; i < userCount; i++)        {          users.Add(this.DataM.Users[i]);        }        for(int i = 0; i < luckyCount - (userCount - index); i++)        {          users.Add(this.DataM.Users[i]);        }        index = luckyCount - (userCount - index);      }      else      {        //顺序读取        for (int i = index; i < index+luckyCount; i++)        {          users.Add(this.DataM.Users[i]);        }        index=index+luckyCount;      }      Application.Current.Dispatcher.Invoke(new Action(() =>      {        this.DataM.CurUsers = new ObservableCollection<User>(users);      }));      Thread.Sleep(100);    }  },token);  this.DataM.State = 1;}

停止抽奖 ,并保存中奖结果:

private void Stop(){  cts.Cancel();  //获取当前获奖名单  var users = this.DataM.CurUsers.ToList();  var lucky = this.DataM.CurLucky.Lucky;  if (winnerDal == null)  {    winnerDal = new WinnerDal();  }  foreach(var user in users)  {    var entity = new WinnerEntity()    {      UserId = user.Id,      LuckyId = lucky.Id,      WinnerTime = DateTime.Now,    };    int id= this.winnerDal.AddWinner(entity);    if(id <1)    {      MessageBox.Show("添加失败");      break;    }  }  //  for(int i=0; i<users.Count; i++)  {    var user = users[i];    this.DataM.Users.Remove(user);//从列表中移除中奖名单  }  this.DataM.State=0;}

下一个奖项,按照奖项顺序选择下一个奖项,通过Next键触发,如下所示:

private void Next(){  int order = this.DataM.CurLucky.Lucky.LuckyOrder;  var next = this.DataM.Luckys.FirstOrDefault(item => item.LuckyOrder > order);  if (next != null)  {    this.DataM.CurLucky.Lucky = next;    var giftId = this.DataM.CurLucky.Lucky.GiftId;    this.DataM.CurLucky.Gift = this.DataM.Gifts.FirstOrDefault(item => item.Id == giftId);    if (next.Count > 4)    {      this.DataM.Row = 2;      this.DataM.Column = (int)Math.Ceiling(next.Count * 1.0d / 2);    }    this.DataM.State = 0;    this.DataM.CurUsers.Clear();  }  else  {    WeakReferenceMessenger.Default.Send(new StateChangedMessage(2));  }}

效果演示


抽奖软件实例演示,客户端主要包括首页,抽奖页,结束页,如下所示:

首页实例

抽奖页面

结束语页面

管理端主要是对数据的管理,包括礼品管理,用户管理,奖项管理,中奖管理,属于常规的数据管理页面,如下所示:

源码下载


1. gitee下载

源码已上传至gitee,用户可通过gitee链接进行下载,如下所示:
项目链接:https:///ahsiang/easy-lucky

2. 关键字下载

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多