之前一直在捣鼓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
之后我们得到一个vsix的VS扩展文件,安装之后,在我们的应用上右键添加引用(Add reference):
我们看到了SQLite for Windows Runtime,需要注意的是我们需要添加C++ Runtime Package和SQLite Package。 这样做的原因是需要为应用提供运行环境,如果不这样做可能在WACK(Windows App Certification Kit)测试中失败。
完成之后sqlite是以dll形式存在的,也就是说如果我们需要使用dll中封装的方法我们需要使用P/Invoke的方法并自己在应用中重新封装工作量巨大。在这里我们推荐使用sqlite-net。这是一个开源的轻量级的库,可以让.Net平台操作sqlite数据库。我们可以通过nuget获得:
如果没有安装NuGet的话,可以看这里NuGet学习笔记(1)——初识NuGet及快速安装使用
在工具菜单中选择:
之后在控制台中输入:
完成之后我们将会得到这两个文件:
数据库操作接口
为数据访问层的所有储存库创建一个通用的接口。 首先我们在工程里新建一个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)); } } } }
工程文件列表
哈哈,大功告成!!!工程文件可以到这里下载 链接:http://pan.baidu.com/s/1jGIZ4yy 密码:k0s3
参考
人民邮电出版社《精通Windows应用开发》
发表评论