导出 (0) 打印
全部展开

如何为 Windows Phone 创建基本的本地数据库应用程序

2012/2/9

使用 Windows Phone OS 7.1,您可以将关系数据存储在驻留在应用程序独立存储容器的本地数据库中。本主题将指导您创建使用本地数据库存储数据的基本单页待办事项列表。有关在 Windows Phone 应用程序中使用本地数据库的更多信息,请参阅 Windows Phone 本地数据库概述

提示提示:

若要在使用模型视图查看模型 (MVVM) 模式的情况下,实现此包含附加数据库表与应用程序页、透视控件和 Silverlight for Windows Phone 工具包的应用程序,请参阅如何使用 MVVM 为 Windows Phone 创建本地数据库应用程序

本主题包括以下主要步骤:

  1. 创建应用程序 UI

  2. 生成数据上下文

  3. 创建数据库

  4. 完成应用程序

下图显示了一个有抱负的开发人员眼中的应用程序外观示例。

AP_Con_IStorage_DB2

在文本框中输入文本并触摸“add”会将“待办事项”添加到应用程序中的列表。触摸删除图标会移除列表中的项。由于待办事项保存在本地数据库中,列表中的值将会在两次应用程序启动期间内保留。

注意注意:

以下过程中的步骤用于 Visual Studio 2010 Express for Windows Phone。 当您使用用于 Visual Studio 2010 Professional 或 Visual Studio 2010 Ultimate 的插件时,您可能会看到菜单命令或窗口布局中的一些微小改变。

在本节中,将创建应用程序项目并准备用户界面。

创建应用程序 UI

  1. 在 Visual Studio 2010 Express for Windows Phone 中,通过选择“文件 | 新建项目”菜单命令创建一个新项目。

  2. 将显示“新建项目”窗口。展开“Visual C#”模板,然后选择“Silverlight for Windows Phone”模板。

  3. 选择“Windows Phone 应用程序”模板。用您选择的名称填写“名称”框。

  4. 单击“确定”。将显示“新建 Windows Phone 应用程序”窗口。

  5. “Windows Phone 目标版本”菜单中,确保已选择 Windows Phone 7.1。

  6. 单击“确定”。将创建一个新的项目,并且“MainPage.xaml”将在 Visual Studio 设计器窗口中打开。

  7. “项目”菜单中选择“添加现有项”。该操作将打开“添加现有项”菜单,我们可以从中选择用于删除待办事项的图标。

  8. “添加现有项”窗口中,导航到以下路径之一并选择命名为 appbar.delete.rest.png 的图标。该图标设计用于深色背景并且颜色为白色;该图标在“添加现有项”窗口的白色背景中可能显示为空白。

    • 64 位操作系统C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Icons\dark

    • 32 位操作系统C:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Icons\dark

    注意注意:

    此步骤假定采用的是以默认方式安装的 Visual Studio。如果您将其安装在其他位置,则在相应的位置查找图标。

  9. 单击“添加”。该操作将图标添加到解决方案资源管理器中的列表。

  10. “解决方案资源管理器”中,右键单击图标并设置文件属性,以便以“内容”的形式生成图标并且始终复制到输出目录(“始终复制”)。

  11. MainPage.xaml 上,删除名为 LayoutRootGrid 的 XAML 代码,并替换为以下代码。

    <!--LayoutRoot is the root grid where all page content is placed.-->
        <Grid x:Name="LayoutRoot" Background="Transparent">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
    
            <!--TitlePanel contains the name of the application and page title.-->
            <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
                <TextBlock x:Name="ApplicationTitle" Text="LOCAL DATABASE EXAMPLE" Style="{StaticResource PhoneTextNormalStyle}"/>
                <TextBlock x:Name="PageTitle" Text="to-do list" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
            </StackPanel>
    
            <!--ContentPanel - place additional content here.-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                
                <!-- Bind the list box to the observable collection. -->
                <ListBox x:Name="toDoItemsListBox" ItemsSource="{Binding ToDoItems}" 
                         Grid.Row="0" Margin="12, 0, 12, 0" Width="440">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Grid HorizontalAlignment="Stretch" Width="440">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="50" />
                                    <ColumnDefinition Width="*" />                               
                                    <ColumnDefinition Width="100" />                                
                                </Grid.ColumnDefinitions>
                                <CheckBox
                                    IsChecked="{Binding IsComplete, Mode=TwoWay}"
                                    Grid.Column="0"
                                    VerticalAlignment="Center"/>
                                <TextBlock
                                    Text="{Binding ItemName}"
                                    FontSize="{StaticResource PhoneFontSizeLarge}"
                                    Grid.Column="1"
                                    VerticalAlignment="Center"/>
                                <Button
                                    Grid.Column="2"
                                    x:Name="deleteTaskButton"
                                    BorderThickness="0"                                
                                    Margin="0"
                                    Click="deleteTaskButton_Click">
                                    <Image Source="appbar.delete.rest.png"/>                                
                                </Button>
                            </Grid>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>      
                
                <Grid Grid.Row="1">                
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <TextBox
                        x:Name="newToDoTextBox"                    
                        Grid.Column="0"
                        Text="add new task"
                        FontFamily="{StaticResource PhoneFontFamilyLight}"                    
                        GotFocus="newToDoTextBox_GotFocus"/>
                    <Button 
                        Content="add"
                        Grid.Column="1"
                        x:Name="newToDoAddButton"
                        Click="newToDoAddButton_Click"/>                
                </Grid>
            </Grid>
        </Grid>
    
    

    XAML 代码将向应用程序添加两个 Grid 元素。其中一个 Grid 包含显示待办事项的 toDoItemsListBox。随着绑定到列表的待办事项越多,ListBox 的尺寸将有所增加,逐渐将第二个 Grid 推向屏幕下方。另一个 Grid 元素包含用来输入新待办事项的 newToDoTextBoxButton

在本节中,将指定一个确定数据库架构的对象模型并创建数据上下文。

生成数据上下文

  1. 打开主页的代码隐藏文件(命名为 MainPage.xaml.cs)。该页面将包含大部分应用程序逻辑。为了简便起见,该应用程序将特意保留在一个页面中。实际应用程序通常会使用模型视图查看模型 (MVVM) 编程模式。有关更多信息,请参阅在 Windows Phone 应用程序中实现模型视图查看模型模式

  2. 该应用程序需要引用 Windows Phone 的 LINQ to SQL 程序集。从“项目”菜单中,单击“添加引用”,从“.NET”标签中选择“System.Data.Linq”,然后单击“确定”

  3. 在页面顶部添加以下指令。

    using System.Data.Linq;
    using System.Data.Linq.Mapping;
    using System.ComponentModel;
    using System.Collections.ObjectModel;
    
    
  4. MainPage 类下,添加以下代码。这是一个名为 ToDoItem 的实体类,表示本地数据库中应用程序的数据库表。该类实现 INotifyPropertyChanged 以进行更改跟踪。实现 INotifyPropertyChanging 有助于限制与更改跟踪相关的内存占用。表属性 [Table] 指示 LINQ to SQL 运行时将类映射到本地数据库表。

    [Table]
    public class ToDoItem : INotifyPropertyChanged, INotifyPropertyChanging
    {
    // Define ID: private field, public property and database column.
    private int _toDoItemId;
    
    [Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
    public int ToDoItemId
    {
        get
        {
            return _toDoItemId;
        }
        set
        {
            if (_toDoItemId != value)
            {
                NotifyPropertyChanging("ToDoItemId");
                _toDoItemId = value;
                NotifyPropertyChanged("ToDoItemId");
            }
        }
    }
    
    // Define item name: private field, public property and database column.
    private string _itemName;
    
    [Column]
    public string ItemName
    {
        get
        {
            return _itemName;
        }
        set
        {
            if (_itemName != value)
            {
                NotifyPropertyChanging("ItemName");
                _itemName = value;
                NotifyPropertyChanged("ItemName");
            }
        }
    }
    
    // Define completion value: private field, public property and database column.
    private bool _isComplete;
    
    [Column]
    public bool IsComplete
    {
        get
        {
            return _isComplete;
        }
        set
        {
            if (_isComplete != value)
            {
                NotifyPropertyChanging("IsComplete");
                _isComplete = value;
                NotifyPropertyChanged("IsComplete");
            }
        }
    }
    // Version column aids update performance.
    [Column(IsVersion = true)]
    private Binary _version;
    
    #region INotifyPropertyChanged Members
    
    public event PropertyChangedEventHandler PropertyChanged;
    
    // Used to notify the page that a data context property changed
    private void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
    #endregion
    
    #region INotifyPropertyChanging Members
    
    public event PropertyChangingEventHandler PropertyChanging;
    
    // Used to notify the data context that a data context property is about to change
    private void NotifyPropertyChanging(string propertyName)
    {
        if (PropertyChanging != null)
        {
            PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
        }
    }
    
    #endregion
    }
    
    

    ToDoItem 类具有三个公共属性,分别与三个数据库列相对应:

    • ToDoItemId:由数据库自动填充的标识符列。同时,该列也是一个主键,系统会为其自动创建数据库索引。这些以及其他设置均使用在属性语法上方编写的 LINQ to SQL Column 映射属性指定。

    • ItemName:存储待办事项文本的列。

    • IsComplete:存储待办事项完成状态的列。

    重要说明重要说明:

    为了限制更改跟踪所需的内存占用,请始终对数据上下文中的对象实现 INotifyPropertyChanging 接口。

  5. MainPage 类下,添加以下代码。这是一个名为 ToDoDataContext 的类。该类继承自 DataContext,被称为数据上下文。最重要的是,该代码将调用基构造函数并声明名为 ToDoItems 的数据库表。

    public class ToDoDataContext : DataContext
    {
        // Specify the connection string as a static, used in main page and app.xaml.
        public static string DBConnectionString = "Data Source=isostore:/ToDo.sdf";
    
        // Pass the connection string to the base class.
        public ToDoDataContext(string connectionString)
            : base(connectionString)
        { }
    
        // Specify a single table for the to-do items.
        public Table<ToDoItem> ToDoItems;
    }
    
    
    注意注意:

    不要求数据库连接字符串必须为静态字段,该特定示例中仅为方便使用而要求。有关连接字符串的更多信息,请参阅 Windows Phone 本地数据库连接字符串

在本节中,将添加创建数据库的代码(若不存在)。

创建数据库

  1. 打开应用程序的代码隐藏文件(命名为 App.xaml.cs)。该文件包含应用程序对象的代码。

  2. 在命名为 App() 的应用程序对象的构造函数中,将以下代码添加到方法的结尾处。此处将添加数据库创建代码,以便在主页中代码运行之前数据库便已存在。

    // Create the database if it does not exist.
    using (ToDoDataContext db = new ToDoDataContext(ToDoDataContext.DBConnectionString))
    {
        if (db.DatabaseExists() == false)
        {
            //Create the database
            db.CreateDatabase();
        }
    }
    
    

    ToDoDataContext 类的构造函数中,连接字符串静态字段仅出于简便而使用。这等效于将值 "Data Source=isostore:/ToDo.sdf" 传递到构造函数。

在本节中,将完成应用程序代码的剩余部分。

完成应用程序

  1. 打开主页的代码隐藏文件(命名为 MainPage.xaml.cs)。该文件将包含应用程序代码的剩余部分。

  2. 用下面的代码替换 MainPage 类。为了支持数据绑定,该代码向 MainPage 类的签名添加了 INotifyPropertyChanged 接口及对应的 INotifyPropertyChanged 成员。

    public partial class MainPage : PhoneApplicationPage, INotifyPropertyChanged
    {
    
        // Constructor
        public MainPage()
        {
            InitializeComponent();
        }
    
    
        #region INotifyPropertyChanged Members
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        // Used to notify Silverlight that a property has changed.
        private void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
    
    
  3. MainPage 类中,将以下代码添加到类构造函数上方。该代码声明一个名为 toDoDB 的私有数据上下文和一个名为 ToDoItems 的公共属性 ObservableCollectionToDoItems 将用来将数据绑定到 UI。

    // Data context for the local database
    private ToDoDataContext toDoDB;
    
    // Define an observable collection property that controls can bind to.
    private ObservableCollection<ToDoItem> _toDoItems;
    public ObservableCollection<ToDoItem> ToDoItems
    {
        get
        {
            return _toDoItems;
        }
        set
        {
            if (_toDoItems != value)
            {
                _toDoItems = value;
                NotifyPropertyChanged("ToDoItems");
            }
        }
    }
    
    
  4. MainPage 类构造函数内部,将以下代码添加到 InitializeComponent 调用的下方。该代码实例化(本地数据库)数据上下文(再次使用静态连接字符串 DBConnectionString),并将主页设置为数据上下文(页面)的根。

    // Connect to the database and instantiate data context.
    toDoDB = new ToDoDataContext(ToDoDataContext.DBConnectionString);
                
    // Data context and observable collection are children of the main page.
    this.DataContext = this;
    
    
  5. MainPage 类中,将以下代码添加到类构造函数下方。当导航到该页面时,该代码将查询本地数据库并使用结果填充 ToDoItems 集合。由于 XAML 中配置的数据绑定,toDoItemsListBox 控件将使用相应的待完成事项自动进行填充。

    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
    // Define the query to gather all of the to-do items.
    var toDoItemsInDB = from ToDoItem todo in toDoDB.ToDoItems
                        select todo;
    
    // Execute the query and place the results into a collection.
    ToDoItems = new ObservableCollection<ToDoItem>(toDoItemsInDB);
                
        // Call the base method.
        base.OnNavigatedTo(e);
    }
    
    
  6. MainPage 类中,将以下代码添加到类构造函数下方。该代码用来将待办事项添加到数据库。newToDoTextBox_GotFocus 在用户输入新待办事项之前清除文本框。newToDoAddButton_Click 创建新 ToDoItem 对象并将其添加到 ToDoItems 集合和 toDoDB 数据上下文。在导航出页面和调用 SubmitChanges 方法之前,新待办事项不会实际添加到本地数据库。

    private void newToDoTextBox_GotFocus(object sender, RoutedEventArgs e)
    {
        // Clear the text box when it gets focus.
        newToDoTextBox.Text = String.Empty;
    }
    
    private void newToDoAddButton_Click(object sender, RoutedEventArgs e)
    {
        // Create a new to-do item based on the text box.
        ToDoItem newToDo = new ToDoItem { ItemName = newToDoTextBox.Text };
    
        // Add a to-do item to the observable collection.
        ToDoItems.Add(newToDo);
                
        // Add a to-do item to the local database.
        toDoDB.ToDoItems.InsertOnSubmit(newToDo);          
    }
    
    protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
    {
        // Call the base method.
        base.OnNavigatedFrom(e);
    
        // Save changes to the database.
        toDoDB.SubmitChanges();
    }
    
    
    重要说明重要说明:

    在调用 SubmitChanges 方法之前,已添加到数据上下文的新项目将不会保存到数据库。

  7. MainPage 类中,将以下代码添加到类构造函数下方。该代码在用户按删除图标时调用。该操作将从 ToDoItems 集合和 toDoDB 数据上下文中移除相应的待办事项。在调用 SubmitChanges 方法之前,已删除的待办事项将不会从本地数据库中实际移除。

    private void deleteTaskButton_Click(object sender, RoutedEventArgs e)
    {
        // Cast parameter as a button.
        var button = sender as Button;
    
        if (button != null)
        {
            // Get a handle for the to-do item bound to the button.
            ToDoItem toDoForDelete = button.DataContext as ToDoItem;
    
            // Remove the to-do item from the observable collection.
            ToDoItems.Remove(toDoForDelete);
    
            // Remove the to-do item from the local database.
            toDoDB.ToDoItems.DeleteOnSubmit(toDoForDelete);
    
            // Save changes to the database.
            toDoDB.SubmitChanges();
    
            // Put the focus back to the main page.
            this.Focus();
        }
    }
    
    
    重要说明重要说明:

    在调用 SubmitChanges 方法之前,已从数据上下文中移除的项目将不会从数据库移除。

  8. 现在您已经完成了该应用程序。按 F5 开始调试并测试该应用程序。

显示:
© 2014 Microsoft