基於WPF+Sqlite開發抽獎軟體【內附源碼】

来源:https://www.cnblogs.com/hsiang/p/18205190
-Advertisement-
Play Games

在很早之前,就想過開發一款抽獎軟體,卻一直沒有實際去做,最近經過一段時間的準備,終於開發出了一款基於WPF+Sqlite版的抽獎軟體,包括客戶端和管理端。本項目主要是為了熟悉WPF開發流程,僅供學習分享使用,如有不足之處,還請指正。 ...


在很早之前,就想過開發一款抽獎軟體,卻一直沒有實際去做,最近經過一段時間的準備,終於開發出了一款基於WPF+Sqlite版的抽獎軟體,包括客戶端和管理端。本項目主要是為了熟悉WPF開發流程,僅供學習分享使用,如有不足之處,還請指正。

 

涉及知識點

 

抽獎軟體是包括客戶端和管理端,在抽獎軟體開發過程中,主要用到瞭如下知識點:

  • 開發工具:Visual Studion 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.openxmlformats.org/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://gitee.com/ahsiang/easy-lucky

 

2. 關鍵字下載

 

關註個人公眾號,回覆關鍵字Lucky即可,如下所示:

以上就是基於WPF+Sqlite開發抽獎軟體實例的全部內容,希望可以拋磚引玉,一起學習,共同進步。


作者:小六公子
出處:http://www.cnblogs.com/hsiang/
本文版權歸作者和博客園共有,寫文不易,支持原創,歡迎轉載【點贊】,轉載請保留此段聲明,且在文章頁面明顯位置給出原文連接,謝謝。
關註個人公眾號,定時同步更新技術及職場文章


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 配置 NGINX 和 NGINX Plus 作為 Web 伺服器 設置虛擬伺服器 在 NGINX Plus 配置文件中,必須包含至少一個 server 指令來定義一個虛擬伺服器。 當 NGINX Plus 處理請求時,首先選擇將服務於該請求的虛擬伺服器。 http { server { # 伺服器配 ...
  • title: Django與前端框架協作開發實戰:高效構建現代Web應用 date: 2024/5/22 20:07:47 updated: 2024/5/22 20:07:47 categories: 後端開發 tags: DjangoREST 前端框架 SSR渲染 SPA路由 SEO優化 組件庫 ...
  • 在使用Wrapper構建條件時,經常因為需要構建的條件過多需要寫半個多小時,還容易粗心寫錯欄位,所以就想搞個可以直接自動構建QueryWrapper的工具類。 ...
  • 今天使用Thinkphp5做非同步任務傳遞where參數時遇到一個問題: 有一段如下代碼: $where['jst.supplier'] = ['exp', Db::raw('>0 or jst.is_supplier=1')]; 在使用swoole做非同步任務時需要把where參數傳遞給非同步任務處理, ...
  • 前言 市面上關於認證授權的框架已經比較豐富了,大都是關於單體應用的認證授權,在分散式架構下,使用比較多的方案是--<應用網關>,網關里集中認證,將認證通過的請求再轉發給代理的服務,這種中心化的方式並不適用於微服務,這裡討論另一種方案--<認證中心>,利用jwt去中心化的特性,減輕認證中心的壓力,有理 ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • 在小公司中,往往沒有一個前後端分離的大型團隊,去各司其職的負責構建web應用程式。面對比較簡單的需求,可能所謂團隊只有一個人,既要開發前端又要開發後端。 如果能有一項技術,能夠前後端通吃,並且具備非常高的開發效率,那就非常適合小公司的小型項目的小型甚至一人團隊來使用了。 aspdotnet就是這樣高 ...
  • 結構體 struct 是一種用戶自定義的值類型,常用於定義一些簡單(輕量)的數據結構。對於一些局部使用的數據結構,優先使用結構體,效率要高很多。 ...
一周排行
    -Advertisement-
    Play Games
  • 問題 有很多應用程式在驗證JSON數據的時候用到了JSON Schema。 在微服務架構下,有時候各個微服務由於各種歷史原因,它們所生成的數據對JSON Object屬性名的大小寫規則可能並不統一,它們需要消費的JSON數據的屬性名可能需要大小寫無關。 遺憾的是,目前的JSON Schema沒有這方 ...
  • 首先下載centos07鏡像,建議使用阿裡雲推薦的地址: https://mirrors.aliyun.com/centos/7.9.2009/isos/x86_64/?spm=a2c6h.25603864.0.0.59b5f5ad5Nfr0X 其實這裡就已經出現第一個坑了 centos 07 /u ...
  • 相信很多.NETer看了標題,都會忍不住好奇,點進來看看,並且順便準備要噴作者! 這裡,首先要申明一下,作者本人也非常喜歡Linq,也在各個項目中常用Linq。 我愛Linq,Linq優雅萬歲!!!(PS:順便吐槽一下,隔壁Java從8.0版本推出的Streams API,抄了個四不像,一點都不優雅 ...
  • 在人生的重要時刻,我站在了畢業的門檻上,望著前方的道路,心中涌動著對未來的無限憧憬與些許忐忑。面前,兩條道路蜿蜒伸展:一是繼續在職場中尋求穩定,一是勇敢地走出一條屬於自己的創新之路。儘管面臨年齡和現實的挑戰,我仍舊選擇勇往直前,用技術這把鑰匙,開啟新的人生篇章。 迴首過去,我深知時間寶貴,精力有限。 ...
  • 單元測試 前言 時隔多個月,終於抽空學習了點新知識,那麼這次來記錄一下C#怎麼進行單元測試,單元測試是做什麼的。 我相信大部分剛畢業的都很疑惑單元測試是乾什麼的?在小廠實習了6個月後,我發現每天除了寫CRUD就是寫CRUD,幾乎用不到單元測試。寫完一個功能直接上手去測,當然這隻是我個人感受,僅供參考 ...
  • 一:背景 1. 講故事 最近在分析dump時,發現有程式的卡死和WeakReference有關,在以前只知道怎麼用,但不清楚底層邏輯走向是什麼樣的,藉著這個dump的契機來簡單研究下。 二:弱引用的玩法 1. 一些基礎概念 用過WeakReference的朋友都知道這裡面又可以分為弱短和弱長兩個概念 ...
  • 最近想把ET打表工具的報錯提示直接調用win系統彈窗,好讓策劃明顯的知道表格哪裡填錯數據,彈窗需要調用System.Windows.Forms庫。操作如下: 需要在 .csproj 文件中添加: <UseWindowsForms>true</UseWindowsForms> 須將目標平臺設置為 Wi ...
  • 從C#3開始,拓展方法這一特性就得到了廣泛的應用。 此功能允許你能夠使用實例方法的語法調用某個靜態方法,以下是一個獲取/創建文件的靜態方法: public static async Task<StorageFile> GetOrCreateFileAsync(this StorageFolder f ...
  • 在Windows 11下,使用WinUI2.6以上版本的ListView長這樣: 然而到了Win10上,儘管其他控制項的樣式沒有改變,但ListViewItem變成了預設樣式(初代Fluent) 最重大的問題是,Win10上的HorizontalAlignment未被設置成Stretch,可能造成嚴重 ...
  • 前言 周六在公司加班,幹完活後越顯無聊,想著下載RabbiitMQ做個小項目玩玩。然而這一下就下載了2個小時,真讓人頭痛。 簡單的講一下如何安裝吧,網上教程和踩坑文章還是很多的,我講我感覺有用的文章放在本文末尾。 安裝地址 erlang 下載 - Erlang/OTP https://www.erl ...