天天看點

使用Xamarin開發移動應用示例——數獨遊戲(六)使用資料庫

項目代碼可以從Github下載下傳:https://github.com/zhenl/ZL.Shudu 。代碼随項目進度更新。

現在我們希望為應用增加更多的功能,比如記錄每個完成的遊戲,可以讓使用者自己添加新的數獨遊戲等等,這些功能需要資料庫的支援。我們使用Sqlite資料庫儲存遊戲的資料。Sqlite是基于檔案的單機關系型資料庫,使用起來非常友善,首先安裝程式包sqlite-net-pcl,可以在Visual Studio 2022中使用Nuget管理器安裝最新版本,然後,添加POCO類的定義和資料庫通路的方法,這裡我們需要記錄完成的遊戲和輸入的遊戲。在使用資料庫時,首先根據指定資料庫的路徑建立資料庫連接配接,如果資料庫檔案不存在,則建立新的資料庫檔案:

readonly SQLiteAsyncConnection _database;
 _database = new SQLiteAsyncConnection(dbPath);
           

然後根據定義的POCO建立資料庫表(如果不存在):

_database.CreateTableAsync<InputGameInfo>().Wait();
 _database.CreateTableAsync<FinishGame>().Wait();
           

接下來就可以使用相應的CRUD函數進行操作了。

下面是記錄完成遊戲的POCO。數獨的初始狀态和完成狀态是9X9矩陣,由于每個格子隻是1-9的數字,采用字元串存儲,長度是固定的,恢複為矩陣也比較友善,是以這裡采用string類型。完成的步驟是一個清單,每個步驟儲存行、列和輸入值,這裡也用字元串儲存,每個步驟之間用指定分隔符隔開。

using SQLite;
using System;

namespace ZL.Shudu.Services
{
    public class FinishGame
    {
        [PrimaryKey, AutoIncrement]
        public int Id { get; set; }
        /// <summary>
        /// 遊戲的初始狀态
        /// </summary>
        public string Sudoku { get; set; }
        /// <summary>
        /// 遊戲的結果
        /// </summary>
        public string Result { get; set; }
        /// <summary>
        /// 遊戲過程
        /// </summary>
        public string Steps { get; set; }
        /// <summary>
        /// 遊戲完成日期
        /// </summary>
        public DateTime PlayDate { get; set; }
        /// <summary>
        /// 使用時間
        /// </summary>
        public long TotalTime { get; set; }
    }
}

           

輸入遊戲的POCO:

using SQLite;
using System;

namespace ZL.Shudu.Services
{
    public class InputGameInfo
    {
        [PrimaryKey, AutoIncrement]
        public int ID { get; set; }
        /// <summary>
        /// 遊戲的初始狀态
        /// </summary>
        public string Sudoku { get; set; }
        /// <summary>
        /// 輸入日期
        /// </summary>
        public DateTime InputDate { get; set; }
        /// <summary>
        /// 是否在遊戲中使用
        /// </summary>
        public bool UsedInGame { get; set; }
    }
}

           

操作資料庫的類:

using SQLite;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace ShuduApp.Db
{
    public class Database
    {
        readonly SQLiteAsyncConnection _database;

        public Database(string dbPath)
        {
            _database = new SQLiteAsyncConnection(dbPath);
            _database.CreateTableAsync<InputGameInfo>().Wait();
            _database.CreateTableAsync<FinishGame>().Wait();
        }

        #region InputGameInfo
        public Task<List<InputGameInfo>> GetGamesAsync()
        {
            return _database.Table<InputGameInfo>().ToListAsync();
        }

        public Task<int> SaveGameAsync(InputGameInfo game)
        {
            return _database.InsertAsync(game);
        }

        public Task<int> UpdateGameAsync(InputGameInfo game)
        {
            return _database.UpdateAsync(game);
        }

        public Task<int> DeleteGameAsync(InputGameInfo game)
        {
            return _database.DeleteAsync(game);
        }

        #endregion

        #region FinishGame
        public Task<List<FinishGame>> GetFinishGamesAsync()
        {
            return _database.Table<FinishGame>().ToListAsync();
        }

        public Task<int> SaveFinishGameAsync(FinishGame game)
        {
            return _database.InsertAsync(game);
        }

        public Task<int> UpdateFinishGameAsync(FinishGame game)
        {
            return _database.UpdateAsync(game);
        }

        public Task<int> DeleteFinishGameAsync(FinishGame game)
        {
            return _database.DeleteAsync(game);
        }
        #endregion
    }
}

           

完成這些以後,我們改造Game頁面,增加儲存結果到資料和從資料庫産生新遊戲的代碼。

首先是儲存結果到資料庫:

private async Task SaveToDb()
        {
            try
            {
                var finobj = new FinishGame();

                for (var i = 0; i < 9; i++)
                {
                    for (var j = 0; j < 9; j++)
                    {
                        finobj.Sudoku += chess[i, j].ToString();
                    }
                }

                for (var i = 0; i < 9; i++)
                {
                    for (var j = 0; j < 9; j++)
                    {
                        finobj.Result += string.IsNullOrEmpty(buttons[i, j].Text) ? "0" : buttons[i, j].Text;
                    }
                }

                foreach (var str in steps)
                {
                    finobj.Steps += str + ";";
                }

                finobj.TotalTime = (DateTime.Now - dtBegin).Ticks;

                finobj.PlayDate = DateTime.Now;

                var id=await App.Database.SaveFinishGameAsync(finobj);

            }
            catch (Exception ex)
            {

                lbMessage.Text = ex.Message;
            }
        }
           

在判斷結束的代碼中加入上述方法。然後是在初始化時從資料庫中擷取遊戲:

private async Task<List<InputGameInfo>> LoadFromDb()
        {
            var leng = chesses.GetLength(0);
            var task = App.Database.GetGamesAsync();
            var lst = task.Result;

            for (int k = 0; k < leng; k++)
            {
                var sudoku = "";
                for (var i = 0; i < 9; i++)
                {
                    for (var j = 0; j < 9; j++)
                    {
                        sudoku += chesses[k, i, j].ToString();
                    }
                }
                var obj = lst.FirstOrDefault(o => o.Sudoku == sudoku);
                if (obj == null)
                {
                    await App.Database.SaveGameAsync(new InputGameInfo
                    {
                        Sudoku = sudoku,
                        InputDate = DateTime.Now,
                        UsedInGame = true
                    });
                }
            }

            var l= await App.Database.GetGamesAsync();
            lst = l.Where(o => o.UsedInGame).ToList();
            return lst;
        }
           

在這裡我們判斷資料庫中是否有遊戲,如果沒有,将預制的遊戲儲存到資料庫,然後從資料庫中生成新的遊戲。

我們增加一個新的頁面,用來檢視現有的遊戲:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:d="http://xamarin.com/schemas/2014/forms" xmlns:d1="http://xamarin.com/schemas/2014/forms/design"
             x:Class="ZL.Shudu.Views.GameList">
    <ContentPage.Content>
        <StackLayout>
            <ListView x:Name="MyListView"
            d1:ItemsSource="{Binding Items}"
            CachingStrategy="RecycleElement"
                   IsVisible="True">
                <d:ListView.ItemsSource>
                    <x:Array Type="{x:Type x:String}">
                        <x:String>Item 1</x:String>
                        <x:String>Item 2</x:String>
                        <x:String>Item 3</x:String>
                        <x:String>Item 4</x:String>
                        <x:String>Item 5</x:String>
                    </x:Array>
                </d:ListView.ItemsSource>
            </ListView>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
           

背景代碼:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace ZL.Shudu.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class GameList : ContentPage
    {
        public ObservableCollection<string> Items { get; set; }

        public GameList()
        {
            InitializeComponent();
            RefreshList();
        }

        public async Task RefreshList()
        {
            Items = await GetItems();
            MyListView.ItemsSource = Items;
            MyListView.IsVisible = true;
        }

        public async Task<ObservableCollection<string>> GetItems()
        {
            var items = new ObservableCollection<string>();

            var lst = await App.Database.GetGamesAsync();

            foreach (var obj in lst)
            {
                items.Add(obj.ID.ToString());
            }
            return items;
        }

    }
}
           

在導航頁面中增加對這個頁面的導航:

<TabBar>
        <ShellContent Title="遊戲" Icon="icon_about.png" Route="Game"  ContentTemplate="{DataTemplate local:Game}" />
        <ShellContent Title="遊戲清單" Icon="icon_about.png" Route="GameList"  ContentTemplate="{DataTemplate local:GameList}" />
    </TabBar>

           

使用這個頁面,可以檢視現有的遊戲。

下一步,我們編寫檢視完成遊戲的清單和增加新遊戲的頁面。

本文來自部落格園,作者:尋找無名的特質,轉載請注明原文連結:https://www.cnblogs.com/zhenl/p/15834953.html