ICHARM
ICHARM
【C#】绑定SQLite数据库的数据到ListView控件
【C#】绑定SQLite数据库的数据到ListView控件

之前一直在捣鼓VS自带的数据库LocalDB,但是因为是开发Windows商店应用,本来很天真的想着在商店应用里使用LocalDB数据库的,但是彻底暴走了,商店应用是运行在winRT的安全沙盒里面,对数据的读写有着严格的限制,根本无法使用本地的Sql server,无奈只好使用微软推荐的Sqlite。

下面我已C# + XAML的windows商店应用的方式来展现Sqlite的操作,我们主要实现的是将SQLite里的数据绑定到ListView控件,并实现数据的动态更新。

首先新建一个SQLiteTest的空白工程

安装SQLite和为工程添加引用

这个真的有点麻烦,不像使用ado.net添加命名空间就行了,这里因为就不详细介绍了,大家可以参考:数据库系统在WinRT中的使用(二)Part 1:SQLite的使用,下面是摘取部分

在应用中添加SQLite引用

SQLite项目组已经为我们制作好了SQLite for Windows Runtime,并将之做成了一个VS扩展,使得使用起来更加方便。

请到下载:

http://www.sqlite.org/download.html

https://d5ypwg.dm1.livefilestore.com/y1pKWeBTZ4hMrH86I86ZUnt8IEiEcgKBKkXQSF3WYkKm__9P6xsS_7ERFMep2Zf8oIsjZqfls_rzAchb4_FW7JDOMPLyPE7LTGL/1.png?psid=1

之后我们得到一个vsixVS扩展文件,安装之后,在我们的应用上右键添加引用(Add reference):

https://d5ypwg.dm1.livefilestore.com/y1pjoouiKtOP-JgnSmEBTI0kIu9Mu1b64cv7ObgxdLpDXlq7W5Z3lmttKZDuV0PndiwHzqILmslYvzUhWfjN3dXXC55Z53GPxdb/2.png?psid=1

我们看到了SQLite for Windows Runtime,需要注意的是我们需要添加C++ Runtime PackageSQLite Package 这样做的原因是需要为应用提供运行环境,如果不这样做可能在WACKWindows App Certification Kit)测试中失败。

完成之后sqlite是以dll形式存在的,也就是说如果我们需要使用dll中封装的方法我们需要使用P/Invoke的方法并自己在应用中重新封装工作量巨大。在这里我们推荐使用sqlite-net。这是一个开源的轻量级的库,可以让.Net平台操作sqlite数据库。我们可以通过nuget获得:

如果没有安装NuGet的话,可以看这里NuGet学习笔记(1)——初识NuGet及快速安装使用

在工具菜单中选择:

https://d5ypwg.dm1.livefilestore.com/y1pbVsFi-AcfUVxuUSoDRXSgiAzin8htSAC9tkc4zGRTRPxRDB28AB6QhEbpMBpNFeP9TRQv5njY50d-rgs3IWyG4mo4rvjZbPc/3.png?psid=1

之后在控制台中输入:

https://d5ypwg.dm1.livefilestore.com/y1pKWeBTZ4hMrER3oLDCol_5VdUIiYqPU6wVUdnOgYAEqCNK-60-k-d61b8Um5kzYbC0nK5BwWBwycFtKojNTQ5KKRoVHSsOgQf/4.png?psid=1

完成之后我们将会得到这两个文件:

https://d5ypwg.dm1.livefilestore.com/y1pSKi0RXTGoNIBLPUSs6bRrYPX8Fkr7sTH3V-2TMo3Gkakm28kgFLVD9GaZvTsv31EDWzU_bc4urz9IsAfDhQ_roKhUfW4ufCK/5.png?psid=1

 

 

数据库操作接口

为数据访问层的所有储存库创建一个通用的接口。 首先我们在工程里新建一个Data新文件夹 然后再添加一个接口的新建项(右击Data文件夹->添加->新建项->接口) 下面是我添加的IDataRepository.cs的接口,里面定义了4个数据库操作的函数,注意要引入System.Collections.ObjectModel命名空间。

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

namespace SQLiteTest.Data
{
    interface IDataRepository
    {
        Task Add(T foot);
        Task<ObservableCollection> Load();
        Task Remove(T foot);
        Task Update(T foot);
    }
}

创建数据模型

因为哀差闷是要做餐馆管理系统,所以这里演示菜单表的数据模型。

右击项目添加一个类的新建项(右击项目->添加->新建项->类)

下面是我新建的Foot.cs,注意引入命名空间using SQLite;

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

namespace SQLiteTest
{
    class Foot
    {
        [PrimaryKey, AutoIncrement]        //设footID为主键
        public int footID { get; set; }   
        public String footName { get; set; }
        public String footPrice { get; set; }
        public String Categories { get; set; }
    }
}

创建视图模型

视图模型作为视图的数据上下文,右键Data文件夹-添加-新建项-类 命名为ViewModel.cs

下面是我的ViewModel.cs和代码注释:(注意引入using System.Collections.ObjectModel;using System.ComponentModel;)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;   //不要忘了引入这个
using System.ComponentModel;            //不要忘了引入这个

namespace SQLiteTest.Data
{
    class ViewModel : INotifyPropertyChanged
    {
        IDataRepository _data;         //添加一个IDataRepository类型的成员变量

        public ViewModel(IDataRepository data)    //构造函数
        {
            _data = data;
        }

        //为了实现INotifyPropertyChanged接口,所以要让ViewModel继承INotifyProperChanged类,并创建下面的PropertyChanged事件(还要引入上面的System.ComponentModel命名空间)
        public event PropertyChangedEventHandler PropertyChanged;

        //下面的方法确保上面的事件拥有监听器,然后使用事件参数fieldName触发该事件。下面的写法是使用了.Net4.5以上的新功能,即使用CallerMemberName特性
        //获取方法调用者的方法和属性名称。
        private void RaisePropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string fieldName = "")
        {
            if (PropertyChanged != null)
            {
                // PropertyChanged(this, new PropertyChangedEventArgs(fieldName));
                PropertyChanged(this, new PropertyChangedEventArgs(fieldName));
            }
        }

        //上面的代码展示了视图的当前状态


        //为视图模型添加公共属性SelectedItem,如果属性的值发生改变,那么RaisePropertyChanged方法就会被调用
        private Foot _seletedItem;
        public Foot SelectedItem
        {
            get
            {
                return this._seletedItem;
            }
            set
            {
                if (value != _seletedItem)
                {
                    _seletedItem = value;
                    RaisePropertyChanged();
                }
            }
        }
        //为视图模型添加公共属性Foot,如果属性的值发生改变,那么RaisePropertyChanged方法就会被调用
        //要先确保引入了System.Collections.ObjectModel命名空间
        private ObservableCollection _Foot;
        public ObservableCollection Foot
        {
            get
            {
                return _Foot;
            }
            set
            {
                _Foot = value;
                RaisePropertyChanged();
            }
        }
        //上面的两个属性主要是为了实现数据库中的数据发生变化时,视图中的数据能及时自动更新



        //异步加载数据的方法
        public async void Initialize()
        {
            Foot = await _data.Load();
        }

        internal void AddFoot(Foot cust)
        {
            _data.Add(cust);
        }
        internal void DeleteFoot(Foot cust)
        {
            _data.Remove(cust);
        }

    }
}


创建数据库操作类

在Data创建一个名为SQLiteRepository的新类,实现IDataRepository接口(继承IDataRepository)。首先引入这两个命名空间Windows.Storage;System.Collections.ObjectModel;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;   //下面三个命名空间不能忘了
using Windows.Storage;
using SQLite;

namespace SQLiteTest.Data
{
    class SQLiteRepository : IDataRepository  //继承IDataRepository接口
    {
        //添加一个类级变量,该变量指向储存数据库的位置(下面为当前目录)
        private static readonly string _dbPath = Windows.Storage.ApplicationData.Current.LocalFolder.Path + @"\mrestaurant.SQLite";  

        //声明一个ObservableCollection集合
        ObservableCollection _Foot;

        public SQLiteRepository() //构造函数调用Inittialize()
        {
            Initialize();
        }
        public void Initialize()//若数据库不存在,则新建该数据库,并用下列数据初始化该数据库;
        {
            using (var db = new SQLite.SQLiteConnection(_dbPath))
            {
                db.CreateTable();
                //创建数据表,并初始化
                if (db.ExecuteScalar("select count(1) from Foot") == 0)
                {
                    db.Insert(new Foot()
                    {
                        footID = 1001,
                        footName = "酸辣海草",
                        footPrice = "10",
                        Categories = "开胃菜"
                    });
                    db.Insert(new Foot()
                    {
                        footID = 1002,
                        footName = "糖炒山楂",
                        footPrice = "10",
                        Categories = "开胃菜"
                    });
                    db.Insert(new Foot()
                    {
                        footID = 2001,
                        footName = "红烧豆腐",
                        footPrice = "25",
                        Categories = "烧菜"
                    });
                    db.Insert(new Foot()
                    {
                        footID = 3001,
                        footName = "紫菜蛋汤",
                        footPrice = "15",
                        Categories = "汤"
                    });

                }
                else
                {
                    Load();
                }
            }
        }

        public async Task<ObservableCollection> Load() //连接数据库并取得所有记录
        {
            //var list = new ObservableCollection();
            var connection = new SQLiteAsyncConnection(_dbPath);
            _Foot = new ObservableCollection(
                await connection.QueryAsync("Select * from Foot"));

            return _Foot;  
        }
     
        public Task Add(Foot obj)  //连接数据库插入新的数据记录
        {
            _Foot.Add(obj);
            var connection = new SQLiteAsyncConnection(_dbPath);
            return connection.InsertAsync(obj);
        }

        public Task Remove(Foot obj) //连接数据库删除数据记录
        {
            _Foot.Add(obj);
            var connection = new SQLiteAsyncConnection(_dbPath);
            return connection.DeleteAsync(obj);
        }

        public Task Update(Foot obj)  //连接数据库,更新数据库数据记录(用新值替换旧值)
        {
            var oldFoot = _Foot.FirstOrDefault(
                c => c.footID == obj.footID);
            if (oldFoot == null)
            {
                throw new System.ArgumentException("Foot not Found");

            }
            _Foot.Remove(oldFoot);
            _Foot.Add(obj);

            var connection = new SQLiteAsyncConnection(_dbPath);
            return connection.UpdateAsync(obj);
        }

    }
}


XAML界面编写

MainPage.xaml 编码如下:

<Page
    x:Class="SQLiteTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:SQLiteTest"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <Page.BottomAppBar>
        <CommandBar Height="101">
            <CommandBar.SecondaryCommands>
                <AppBarButton x:Name="Delete" Label="Delete" Icon="Delete" Tapped="footDelete"  />
            </CommandBar.SecondaryCommands>
        </CommandBar>
    </Page.BottomAppBar>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <ScrollViewer RenderTransformOrigin="0.499,0.541" Margin="257,0" Grid.Row="1">
            <ListView Name="FootList" ItemsSource="{Binding Foot}" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" Height="615">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Text="{Binding Categories}" FontSize="30"/>
                            <TextBlock Text="{Binding footName}" FontSize="30"/>
                            <TextBlock Text="{Binding footPrice}" FontSize="30"/>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </ScrollViewer>
    </Grid>
</Page>

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using SQLiteTest.Data;              //这个是最关键的添加这个命名空间

// “空白页”项模板在 http://go.microsoft.com/fwlink/?LinkId=234238 上有介绍

namespace SQLiteTest
{
    /// <summary>
    /// 可用于自身或导航至 Frame 内部的空白页。
    /// </summary>
    public sealed partial class MainPage : Page
    {

        private IDataRepository<Foot> data = new SQLiteRepository();
        private ViewModel _vm;

        public MainPage()
        {
            this.InitializeComponent();
            _vm = new ViewModel(data);
            _vm.Initialize();
            FootList.DataContext = _vm;  //当定FootList的数据源
        }

        private async void footDelete(object sender, TappedRoutedEventArgs e)
        {
            if (_vm.SelectedItem != null)
            {
                _vm.DeleteFoot(_vm.SelectedItem);
                Windows.UI.Popups.MessageDialog msg = new Windows.UI.Popups.MessageDialog("删除成功");
                await msg.ShowAsync();
                this.Frame.Navigate(typeof(MainPage));
            }
        }
    }
}

工程文件列表

https://cdn.shortpixel.ai/client/q_glossy,ret_img,w_397/http://www.icharm.me/wp-content/uploads/2015/11/20151121215352.jpg

https://cdn.shortpixel.ai/client/q_glossy,ret_img,w_520/http://www.icharm.me/wp-content/uploads/2015/11/20151121214937.jpg

哈哈,大功告成!!!工程文件可以到这里下载 链接:http://pan.baidu.com/s/1jGIZ4yy 密码:k0s3

参考

人民邮电出版社《精通Windows应用开发》

 

发表评论

textsms
account_circle
email

ICHARM

【C#】绑定SQLite数据库的数据到ListView控件
之前一直在捣鼓VS自带的数据库LocalDB,但是因为是开发Windows商店应用,本来很天真的想着在商店应用里使用LocalDB数据库的,但是彻底暴走了,商店应用是运行在winRT的安全沙盒里面,对数…
扫描二维码继续阅读
2015-11-21