Разработка приложений для Windows Phone 7

Создание локальной базы данных для Windows Phone

Разбить на страницы
Показывать лекцию целиком

Дополнительные материалы к занятию можно скачать здесь.

Вложенные папки: LocalDataBaseSample

Ссылки: http://msdn.microsoft.com/en-us/library/ff431744(v=vs.92).aspx
http://silverlight.codeplex.com/releases/view/60291
http://create.msdn.com/en-us/home/getting_started

В новой версии операционной системы Windows Phone OS 7.1 появилась возможность хранить информацию в реляционных базах данных, которая выступает в роли изолированного контейнера приложения. Для работы с базами данных приложения Windows Phone используют операторы LINQ to SQL. С помощью LINQ to SQL можно задать схему базы данных, осуществлять извлечение данных, а также сохранять изменения в файле базы данных.

На рис 33.1 показана связь между приложением и изолированным хранилищем. Для связи с хранилищем в приложении создается объект DataContext.

(рис 33.1) Связь между приложением и изолированным хранилищем

Перед началом работы с локальной базой данных нужно учесть следующее.

LINQ to SQL используется в качестве ORM engine
Файл базы данных хранится в изолированном хранилище
Для извлечения данных используется LINQ, T-SQL не подходит
Локальная база данных в Windows Phone Mango не увеличивает объем приложения, так как является частью универсальной исполняющей машины
К проекту нужно добавить ссылку на сборку System.Data.Linq
При написании строки подключения используется специфический формат, подобный:
"Data Source='isostore:/DIRECTORY/FILE.sdf'";
        

В данной работе мы создадим базу данных, в главной таблице которой будут храниться классы позвоночных животных, а в подчиненной таблице - виды. За основу мы взяли пример, описанный на сайте Microsoft (http://msdn.microsoft.com/en-us/library/ff431744(v=vs.92).aspx), и немного его переработали.

Для работы нам потребуется новая сборка . После инсталляции файла SilverlightforWindowsPhoneToolkit-Feb2011.msi можно узнать местонахождения файла Microsoft.Phone.Controls.Toolkit.dll следующим образом. Выполните следующую последовательность действий: Пуск -> Все программы -> Microsoft Silverlight for Windows Phone Toolkit -> Binaries. Эта сборка содержит следующие полезные компоненты:

AutoCompleteBox
ContextMenu
DatePicker
GestureService/GestureListener
ListPicker
LongListSelector
Page Transitions
PerformanceProgressBar
TiltEffect
TimePicker
ToggleSwitch
WrapPanel

Нам потребуется элемент управления .

В Visual Studio создаем новое приложение Silverlight for Windows Phone. Назовем его LocalDataBaseSample. В пункте Target Windows Phone Version выберите Windows Phone 7.1.

Скопируйте файл Microsoft.Phone.Controls.Toolkit.dll, описанный выше в папку вашего проекта, например, в папку …\LocalDatabaseSample\LocalDatabaseSample\Bin\Debug. Подключите сборку к проекту, выполнив следующие действия: Solution Explorer -> References -> Add Reference -> Path… -> Microsoft.Phone.Controls.Toolkit.dll.

Далее, нам потребуется подключить к проекту ссылку на сборку System.Data.Linq: Solution Explorer -> References -> Add Reference -> .Net -> System.Data.Linq -> OK.

Для нашего приложения необходимы четыре иконки: appbar.add.rest.png, appbar.cancel.rest.png, appbar.check.rest.png, appbar.delete.rest.png, расположенные по адресу:

C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Icons\dark (64-х разрядные операционные системы)

C:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Icons\dark (32-х разрядные операционные системы)

Создайте папку Images (Solution Explorer -> Add -> Create Folder -> Images), скопируйте туда иконки и добавьте к проекту (Solution Explorer -> Images -> Add -> Existent Item).

Откройте файл MainPage.xaml и заполните его следующим содержимым:

<phone:PhoneApplicationPage 
    x:Class="LocalDatabaseSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True"
    xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls">

    <phone:PhoneApplicationPage.Resources>
        <DataTemplate x:Key="AnimalListBoxItemTemplate">

            <Grid HorizontalAlignment="Stretch" Width="420">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="100" />
                </Grid.ColumnDefinitions>

                <CheckBox 
                    IsChecked="{Binding IsComplete, Mode=TwoWay}" 
                    Grid.Column="0" VerticalAlignment="Top"/>

                <TextBlock 
                    Text="{Binding ItemName}" 
                    FontSize="{StaticResource PhoneFontSizeLarge}" 
                    Grid.Column="1" Grid.ColumnSpan="2" 
                    VerticalAlignment="Top" Margin="-36, 12, 0, 0"/>

                <Button                                
                    Grid.Column="3"
                    x:Name="deleteTaskButton"
                    BorderThickness="0"                                                                  
                    Margin="0, -18, 0, 0"
                    Click="deleteTaskButton_Click">

                    <Image 
                    Source="/Images/appbar.delete.rest.png"
                    Height="75"
                    Width="75"/>

                </Button>
            </Grid>
        </DataTemplate>
    </phone:PhoneApplicationPage.Resources>

    <!--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="Образец локальной базы данных: зоология" 
                Style="{StaticResource PhoneTextNormalStyle}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here.-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <controls:Pivot Margin="0, -36, 0, 0">

                <controls:PivotItem Header="Все">
                    <ListBox 
                        x:Name="allAnimalItemsListBox" 
                        ItemsSource="{Binding AllAnimalItems}" 
                        Margin="12, 0, 12, 0" Width="440" 
                        ItemTemplate="{StaticResource AnimalListBoxItemTemplate}" />
                </controls:PivotItem>

                <controls:PivotItem Header="Птицы">
                    <ListBox 
                        x:Name="BirdsAnimalItemsListBox" 
                        ItemsSource="{Binding BirdsAnimalItems}" 
                        Margin="12, 0, 12, 0" Width="440" 
                        ItemTemplate="{StaticResource AnimalListBoxItemTemplate}" />
                </controls:PivotItem>

                <controls:PivotItem Header="Пресмыкающиеся">
                    <ListBox 
                        x:Name="ReptilesAnimalItemsListBox" 
                        ItemsSource="{Binding ReptilesAnimalItems}" 
                        Margin="12, 0, 12, 0" Width="440" 
                        ItemTemplate="{StaticResource AnimalListBoxItemTemplate}" />
                </controls:PivotItem>

                <controls:PivotItem Header="Рыбы">
                    <ListBox
                        x:Name="FishesAnimalItemsListBox" 
                        ItemsSource="{Binding FishesAnimalItems}" 
                        Margin="12, 0, 12, 0" Width="440" 
                        ItemTemplate="{StaticResource AnimalListBoxItemTemplate}" />
                </controls:PivotItem>

            </controls:Pivot>
        </Grid>
    </Grid>

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">

            <shell:ApplicationBarIconButton 
                IconUri="/Images/appbar.add.rest.png" 
                Text="add" 
                x:Name="newTaskAppBarButton" 
                Click="newTaskAppBarButton_Click"/>

        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>

</phone:PhoneApplicationPage>
    

Откройте файл MainPage.xaml.cs и введите следующий код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

/* 
    Copyright (c) 2011 Microsoft Corporation.  All rights reserved.
    Use of this sample source code is subject to the terms of the Microsoft license 
    agreement under which you licensed this sample source code and is provided AS-IS.
    If you did not accept the terms of the license agreement, you are not authorized 
    to use this sample source code.  For the terms of the license, please see the 
    license agreement between you and Microsoft.
    
*/

// Directive for the ViewModel.
using LocalDatabaseSample.Model;

namespace LocalDatabaseSample
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();

            // Set the page DataContext property to the ViewModel.
            this.DataContext = App.ViewModel;
        }

        private void newTaskAppBarButton_Click(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/NewTaskPage.xaml", UriKind.Relative));
        }


        private void deleteTaskButton_Click(object sender, RoutedEventArgs e)
        {
            // Cast the parameter as a button.
            var button = sender as Button;

            if (button != null)
            {
                // Get a handle for the Animal item bound to the button.
                AnimalItem AnimalForDelete = button.DataContext as AnimalItem;

                App.ViewModel.DeleteAnimalItem(AnimalForDelete);
            }

            // Put the focus back to the main page.
            this.Focus();
        }

        protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
        {
            // Save changes to the database.
            App.ViewModel.SaveChangesToDB();
        }
    }
}
    

Добавьте файл NewTaskPage.xaml в портретной ориентации:

Содержимое файла NewTaskPage.xaml:

<phone:PhoneApplicationPage 
    x:Class="LocalDatabaseSample.NewTaskPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="696" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True"
    xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit">

    <!--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="Образец локальной базы данных: Зоология" 
                Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock 
                x:Name="PageTitle" 
                Text="Добавить" 
                Margin="9,-7,0,0" 
                Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here.-->
        <StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBlock Text="Вид"/>
            <TextBox x:Name="newTaskNameTextBox"/>
            <TextBlock Text="Класс"/>

            <toolkit:ListPicker
                x:Name="categoriesListPicker"
                ItemsSource="{Binding CategoriesList}"
                DisplayMemberPath="Name">
            </toolkit:ListPicker>
        </StackPanel>
    </Grid>

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">

            <shell:ApplicationBarIconButton 
                x:Name="appBarOkButton" 
                IconUri="/Images/appbar.check.rest.png" 
                Text="ok" 
                Click="appBarOkButton_Click"/>

            <shell:ApplicationBarIconButton 
                x:Name="appBarCancelButton" 
                IconUri="/Images/appbar.cancel.rest.png" 
                Text="cancel" 
                Click="appBarCancelButton_Click"/>

        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>

</phone:PhoneApplicationPage>
    

Перейдите к файлу NewTaskPage.xaml.cs и введите следующий код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

/* 
    Copyright (c) 2011 Microsoft Corporation.  All rights reserved.
    Use of this sample source code is subject to the terms of the Microsoft license 
    agreement under which you licensed this sample source code and is provided AS-IS.
    If you did not accept the terms of the license agreement, you are not authorized 
    to use this sample source code.  For the terms of the license, please see the 
    license agreement between you and Microsoft.
    
*/


// Directive for the data model.
using LocalDatabaseSample.Model;

namespace LocalDatabaseSample
{
    public partial class NewTaskPage : PhoneApplicationPage
    {
        public NewTaskPage()
        {
            InitializeComponent();

            // Set the page DataContext property to the ViewModel.
            this.DataContext = App.ViewModel;
        }

        private void appBarOkButton_Click(object sender, EventArgs e)
        {
            // Confirm there is some text in the text box.
            if (newTaskNameTextBox.Text.Length > 0)
            {
                // Create a new Animal item.
                AnimalItem newAnimalItem = new AnimalItem
                {
                    ItemName = newTaskNameTextBox.Text,
                    Category = (AnimalCategory)categoriesListPicker.SelectedItem
                };

                // Add the item to the ViewModel.
                App.ViewModel.AddAnimalItem(newAnimalItem);

                // Return to the main page.
                if (NavigationService.CanGoBack)
                {
                    NavigationService.GoBack();
                }
            }
        }

        private void appBarCancelButton_Click(object sender, EventArgs e)
        {
            // Return to the main page.
            if (NavigationService.CanGoBack)
            {
                NavigationService.GoBack();
            }
        }
    }
}
    

Откройте файл App.xaml.cs и введите следующий код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

/* 
    Copyright (c) 2011 Microsoft Corporation.  All rights reserved.
    Use of this sample source code is subject to the terms of the Microsoft license 
    agreement under which you licensed this sample source code and is provided AS-IS.
    If you did not accept the terms of the license agreement, you are not authorized 
    to use this sample source code.  For the terms of the license, please see the 
    license agreement between you and Microsoft.
    
*/

// Directives 
using LocalDatabaseSample.Model;
using LocalDatabaseSample.ViewModel;

namespace LocalDatabaseSample
{
    public partial class App : Application
    {
        /// <summary>
        /// Provides easy access to the root frame of the Phone Application.
        /// </summary>
        /// <returns>The root frame of the Phone Application.</returns>
        public PhoneApplicationFrame RootFrame { get; private set; }

        // The static ViewModel, to be used across the application.
        private static AnimalViewModel viewModel;
        public static AnimalViewModel ViewModel
        {
            get { return viewModel; }
        }

        /// <summary>
        /// Constructor for the Application object.
        /// </summary>
        public App()
        {
            // Global handler for uncaught exceptions. 
            UnhandledException += Application_UnhandledException;

            // Standard Silverlight initialization
            InitializeComponent();

            // Phone-specific initialization
            InitializePhoneApplication();

            // Show graphics profiling information while debugging.
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // Display the current frame rate counters.
                Application.Current.Host.Settings.EnableFrameRateCounter = true;

                // Show the areas of the app that are being redrawn in each frame.
                //Application.Current.Host.Settings.EnableRedrawRegions = true;

                // Enable non-production analysis visualization mode, 
                // which shows areas of a page that are handed off to GPU with a colored overlay.
                //Application.Current.Host.Settings.EnableCacheVisualization = true;

                // Disable the application idle detection by setting the UserIdleDetectionMode property of the
                // application's PhoneApplicationService object to Disabled.
                // Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run
                // and consume battery power when the user is not using the phone.
                PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
            }

            // Specify the local database connection string.
            string DBConnectionString = "Data Source=isostore:/Animal.sdf";

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

                    // Prepopulate the categories.
                    db.Categories.InsertOnSubmit(new AnimalCategory { Name = "Птицы" });
                    db.Categories.InsertOnSubmit(new AnimalCategory { Name = "Пресмыкающиеся" });
                    db.Categories.InsertOnSubmit(new AnimalCategory { Name = "Рыбы" });

                    // Save categories to the database.
                    db.SubmitChanges();
                }
            }

            // Create the ViewModel object.
            viewModel = new AnimalViewModel(DBConnectionString);

            // Query the local database and load observable collections.
            viewModel.LoadCollectionsFromDatabase();

        }

        // Code to execute when the application is launching (eg, from Start)
        // This code will not execute when the application is reactivated
        private void Application_Launching(object sender, LaunchingEventArgs e)
        {
        }

        // Code to execute when the application is activated (brought to foreground)
        // This code will not execute when the application is first launched
        private void Application_Activated(object sender, ActivatedEventArgs e)
        {
        }

        // Code to execute when the application is deactivated (sent to background)
        // This code will not execute when the application is closing
        private void Application_Deactivated(object sender, DeactivatedEventArgs e)
        {
        }

        // Code to execute when the application is closing (eg, user hit Back)
        // This code will not execute when the application is deactivated
        private void Application_Closing(object sender, ClosingEventArgs e)
        {
        }

        // Code to execute if a navigation fails
        private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // A navigation has failed; break into the debugger
                System.Diagnostics.Debugger.Break();
            }
        }

        // Code to execute on Unhandled Exceptions
        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // An unhandled exception has occurred; break into the debugger
                System.Diagnostics.Debugger.Break();
            }
        }

        #region Phone application initialization

        // Avoid double-initialization
        private bool phoneApplicationInitialized = false;

        // Do not add any additional code to this method
        private void InitializePhoneApplication()
        {
            if (phoneApplicationInitialized)
                return;

            // Create the frame but don't set it as RootVisual yet; this allows the splash
            // screen to remain active until the application is ready to render.
            RootFrame = new PhoneApplicationFrame();
            RootFrame.Navigated += CompleteInitializePhoneApplication;

            // Handle navigation failures
            RootFrame.NavigationFailed += RootFrame_NavigationFailed;

            // Ensure we don't initialize again
            phoneApplicationInitialized = true;
        }

        // Do not add any additional code to this method
        private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
        {
            // Set the root visual to allow the application to render
            if (RootVisual != RootFrame)
                RootVisual = RootFrame;

            // Remove this handler since it is no longer needed
            RootFrame.Navigated -= CompleteInitializePhoneApplication;
        }

        #endregion
    }
}
    

Создайте папку Model и разместите в ней файл кода AnimalDataContext.cs со следующим содержимым:

using System;
using System.ComponentModel;
using System.Data.Linq;
using System.Data.Linq.Mapping;

/* 
    Copyright (c) 2011 Microsoft Corporation.  All rights reserved.
    Use of this sample source code is subject to the terms of the Microsoft license 
    agreement under which you licensed this sample source code and is provided AS-IS.
    If you did not accept the terms of the license agreement, you are not authorized 
    to use this sample source code.  For the terms of the license, please see the 
    license agreement between you and Microsoft.
    
*/

namespace LocalDatabaseSample.Model
{

    public class AnimalDataContext : DataContext
    {
        // Pass the connection string to the base class.
        public AnimalDataContext(string connectionString)
            : base(connectionString)
        { }

        // Specify a table for the Animal items.
        public Table<AnimalItem> Items;

        // Specify a table for the categories.
        public Table<AnimalCategory> Categories;
    }


    [Table]
    public class AnimalItem : INotifyPropertyChanged, INotifyPropertyChanging
    {

        // Define ID: private field, public property, and database column.
        private int _AnimalItemId;

        [Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", 
          CanBeNull = false, AutoSync = AutoSync.OnInsert)]
        public int AnimalItemId
        {
            get { return _AnimalItemId; }
            set
            {
                if (_AnimalItemId != value)
                {
                    NotifyPropertyChanging("AnimalItemId");
                    _AnimalItemId = value;
                    NotifyPropertyChanged("AnimalItemId");
                }
            }
        }

        // 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");
                }
            }
        }

        // Internal column for the associated AnimalCategory ID value
        [Column]
        internal int _categoryId;

        // Entity reference, to identify the AnimalCategory "storage" table
        private EntityRef<AnimalCategory> _category;

        // Association, to describe the relationship between this key and that "storage" table
        [Association(Storage = "_category", ThisKey = "_categoryId", 
          OtherKey = "Id", IsForeignKey = true)]
        public AnimalCategory Category
        {
            get { return _category.Entity; }
            set
            {
                NotifyPropertyChanging("Category");
                _category.Entity = value;

                if (value != null)
                {
                    _categoryId = value.Id;
                }

                NotifyPropertyChanging("Category");
            }
        }

        // Version column aids update performance.
        [Column(IsVersion = true)]
        private Binary _version;

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        // Used to notify that a 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 that a property is about to change
        private void NotifyPropertyChanging(string propertyName)
        {
            if (PropertyChanging != null)
            {
                PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
            }
        }

        #endregion
    }

    [Table]
    public class AnimalCategory : INotifyPropertyChanged, INotifyPropertyChanging
    {

        // Define ID: private field, public property, and database column.
        private int _id;

        [Column(DbType = "INT NOT NULL IDENTITY", IsDbGenerated = true, IsPrimaryKey = true)]
        public int Id
        {
            get { return _id; }
            set
            {
                NotifyPropertyChanging("Id");
                _id = value;
                NotifyPropertyChanged("Id");
            }
        }

        // Define category name: private field, public property, and database column.
        private string _name;

        [Column]
        public string Name
        {
            get { return _name; }
            set
            {
                NotifyPropertyChanging("Name");
                _name = value;
                NotifyPropertyChanged("Name");
            }
        }

        // Define the entity set for the collection side of the relationship.
        private EntitySet<AnimalItem> _Animals;

        [Association(Storage = "_Animals", OtherKey = "_categoryId", ThisKey = "Id")]
        public EntitySet<AnimalItem> Animals
        {
            get { return this._Animals; }
            set { this._Animals.Assign(value); }
        }


        // Assign handlers for the add and remove operations, respectively.
        public AnimalCategory()
        {
            _Animals = new EntitySet<AnimalItem>(
                new Action<AnimalItem>(this.attach_Animal),
                new Action<AnimalItem>(this.detach_Animal)
                );
        }

        // Called during an add operation
        private void attach_Animal(AnimalItem Animal)
        {
            NotifyPropertyChanging("AnimalItem");
            Animal.Category = this;
        }

        // Called during a remove operation
        private void detach_Animal(AnimalItem Animal)
        {
            NotifyPropertyChanging("AnimalItem");
            Animal.Category = null;
        }

        // Version column aids update performance.
        [Column(IsVersion = true)]
        private Binary _version;

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        // Used to notify that a 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 that a property is about to change
        private void NotifyPropertyChanging(string propertyName)
        {
            if (PropertyChanging != null)
            {
                PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
            }
        }

        #endregion
    }
}
    

Создайте папку ViewModel и разместите в ней файл AnimalViewModel.cs со следующим содержимым:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;

/* 
    Copyright (c) 2011 Microsoft Corporation.  All rights reserved.
    Use of this sample source code is subject to the terms of the Microsoft license 
    agreement under which you licensed this sample source code and is provided AS-IS.
    If you did not accept the terms of the license agreement, you are not authorized 
    to use this sample source code.  For the terms of the license, please see the 
    license agreement between you and Microsoft.
    
*/

// Directive for the data model.
using LocalDatabaseSample.Model;

namespace LocalDatabaseSample.ViewModel
{
    public class AnimalViewModel : INotifyPropertyChanged
    {
        // LINQ to SQL data context for the local database.
        private AnimalDataContext AnimalDB;

        // Class constructor, create the data context object.
        public AnimalViewModel(string AnimalDBConnectionString)
        {
            AnimalDB = new AnimalDataContext(AnimalDBConnectionString);
        }

        // All to-do items.
        private ObservableCollection<AnimalItem> _allAnimalItems;
        public ObservableCollection<AnimalItem> AllAnimalItems
        {
            get { return _allAnimalItems; }
            set
            {
                _allAnimalItems = value;
                NotifyPropertyChanged("AllAnimalItems");
            }
        }

        // Animal items associated with the Birds category.
        private ObservableCollection<AnimalItem> _BirdsAnimalItems;
        public ObservableCollection<AnimalItem> BirdsAnimalItems
        {
            get { return _BirdsAnimalItems; }
            set
            {
                _BirdsAnimalItems = value;
                NotifyPropertyChanged("BirdsAnimalItems");
            }
        }

        // Animal items associated with the Reptiles category.
        private ObservableCollection<AnimalItem> _ReptilesAnimalItems;
        public ObservableCollection<AnimalItem> ReptilesAnimalItems
        {
            get { return _ReptilesAnimalItems; }
            set
            {
                _ReptilesAnimalItems = value;
                NotifyPropertyChanged("ReptilesAnimalItems");
            }
        }

        // Animal items associated with the Fishes category.
        private ObservableCollection<AnimalItem> _FishesAnimalItems;
        public ObservableCollection<AnimalItem> FishesAnimalItems
        {
            get { return _FishesAnimalItems; }
            set
            {
                _FishesAnimalItems = value;
                NotifyPropertyChanged("FishesAnimalItems");
            }
        }

        // A list of all categories, used by the add task page.
        private List<AnimalCategory> _categoriesList;
        public List<AnimalCategory> CategoriesList
        {
            get { return _categoriesList; }
            set
            {
                _categoriesList = value;
                NotifyPropertyChanged("CategoriesList");
            }
        }

        // Query database and load the collections and list used by the pivot pages.
        public void LoadCollectionsFromDatabase()
        {

            // Specify the query for all to-do items in the database.
            var AnimalItemsInDB = from AnimalItem Animal in AnimalDB.Items
                                  select Animal;

            // Query the database and load all to-do items.
            AllAnimalItems = new ObservableCollection<AnimalItem>(AnimalItemsInDB);

            // Specify the query for all categories in the database.
            var AnimalCategoriesInDB = from AnimalCategory category in AnimalDB.Categories
                                       select category;


            // Query the database and load all associated items to their respective collections.
            foreach (AnimalCategory category in AnimalCategoriesInDB)
            {
                switch (category.Name)
                {
                    case "Птицы":
                        BirdsAnimalItems = new ObservableCollection<AnimalItem>(category.Animals);
                        break;
                    case "Пресмыкающиеся":
                        ReptilesAnimalItems = new ObservableCollection<AnimalItem>(category.Animals);
                        break;
                    case "Рыбы":
                        FishesAnimalItems = new ObservableCollection<AnimalItem>(category.Animals);
                        break;
                    default:
                        break;
                }
            }

            // Load a list of all categories.
            CategoriesList = AnimalDB.Categories.ToList();

        }

        // Add an Animal item to the database and collections.
        public void AddAnimalItem(AnimalItem newAnimalItem)
        {
            // Add an Animal item to the data context.
            AnimalDB.Items.InsertOnSubmit(newAnimalItem);

            // Save changes to the database.
            AnimalDB.SubmitChanges();

            // Add an Animal item to the "all" observable collection.
            AllAnimalItems.Add(newAnimalItem);

            // Add an Animal item to the appropriate filtered collection.
            switch (newAnimalItem.Category.Name)
            {
                case "Птицы":
                    BirdsAnimalItems.Add(newAnimalItem);
                    break;
                case "Пресмыкающиеся":
                    ReptilesAnimalItems.Add(newAnimalItem);
                    break;
                case "Рыбы":
                    FishesAnimalItems.Add(newAnimalItem);
                    break;
                default:
                    break;
            }
        }

        // Remove an Animal task item from the database and collections.
        public void DeleteAnimalItem(AnimalItem AnimalForDelete)
        {

            // Remove the Animal item from the "all" observable collection.
            AllAnimalItems.Remove(AnimalForDelete);

            // Remove the Animal item from the data context.
            AnimalDB.Items.DeleteOnSubmit(AnimalForDelete);

            // Remove the Animal item from the appropriate category.   
            switch (AnimalForDelete.Category.Name)
            {
                case "Птицы":
                    BirdsAnimalItems.Remove(AnimalForDelete);
                    break;
                case "Пресмыкающиеся":
                    ReptilesAnimalItems.Remove(AnimalForDelete);
                    break;
                case "Рыбы":
                    FishesAnimalItems.Remove(AnimalForDelete);
                    break;
                default:
                    break;
            }

            // Save changes to the database.
            AnimalDB.SubmitChanges();
        }



        // Write changes in the data context to the database.
        public void SaveChangesToDB()
        {
            AnimalDB.SubmitChanges();
        }

        #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
    }
}
    

Запустите проект, нажав клавишу F5. Нажмите на кнопку Start, затем выберите пункт SETTINGS:

Выберите пункт Region + Language, В разделе Display language выберите русский язык:

Сохраните настройки.

Вернитесь в приложение LocalDataBaseSample. Поработайте с базой данных.

Страницы:

Дополнительные материалы к занятию можно скачать здесь.

Вложенные папки: LocalDataBaseSample

Ссылки: http://msdn.microsoft.com/en-us/library/ff431744(v=vs.92).aspx
http://silverlight.codeplex.com/releases/view/60291
http://create.msdn.com/en-us/home/getting_started

В новой версии операционной системы Windows Phone OS 7.1 появилась возможность хранить информацию в реляционных базах данных, которая выступает в роли изолированного контейнера приложения. Для работы с базами данных приложения Windows Phone используют операторы LINQ to SQL. С помощью LINQ to SQL можно задать схему базы данных, осуществлять извлечение данных, а также сохранять изменения в файле базы данных.

На рис 33.1 показана связь между приложением и изолированным хранилищем. Для связи с хранилищем в приложении создается объект DataContext.

(рис 33.1) Связь между приложением и изолированным хранилищем

Перед началом работы с локальной базой данных нужно учесть следующее.

LINQ to SQL используется в качестве ORM engine
Файл базы данных хранится в изолированном хранилище
Для извлечения данных используется LINQ, T-SQL не подходит
Локальная база данных в Windows Phone Mango не увеличивает объем приложения, так как является частью универсальной исполняющей машины
К проекту нужно добавить ссылку на сборку System.Data.Linq
При написании строки подключения используется специфический формат, подобный:
"Data Source='isostore:/DIRECTORY/FILE.sdf'";
        

В данной работе мы создадим базу данных, в главной таблице которой будут храниться классы позвоночных животных, а в подчиненной таблице - виды. За основу мы взяли пример, описанный на сайте Microsoft (http://msdn.microsoft.com/en-us/library/ff431744(v=vs.92).aspx), и немного его переработали.

Для работы нам потребуется новая сборка . После инсталляции файла SilverlightforWindowsPhoneToolkit-Feb2011.msi можно узнать местонахождения файла Microsoft.Phone.Controls.Toolkit.dll следующим образом. Выполните следующую последовательность действий: Пуск -> Все программы -> Microsoft Silverlight for Windows Phone Toolkit -> Binaries. Эта сборка содержит следующие полезные компоненты:

AutoCompleteBox
ContextMenu
DatePicker
GestureService/GestureListener
ListPicker
LongListSelector
Page Transitions
PerformanceProgressBar
TiltEffect
TimePicker
ToggleSwitch
WrapPanel

Нам потребуется элемент управления .

В Visual Studio создаем новое приложение Silverlight for Windows Phone. Назовем его LocalDataBaseSample. В пункте Target Windows Phone Version выберите Windows Phone 7.1.

Скопируйте файл Microsoft.Phone.Controls.Toolkit.dll, описанный выше в папку вашего проекта, например, в папку …\LocalDatabaseSample\LocalDatabaseSample\Bin\Debug. Подключите сборку к проекту, выполнив следующие действия: Solution Explorer -> References -> Add Reference -> Path… -> Microsoft.Phone.Controls.Toolkit.dll.

Далее, нам потребуется подключить к проекту ссылку на сборку System.Data.Linq: Solution Explorer -> References -> Add Reference -> .Net -> System.Data.Linq -> OK.

Для нашего приложения необходимы четыре иконки: appbar.add.rest.png, appbar.cancel.rest.png, appbar.check.rest.png, appbar.delete.rest.png, расположенные по адресу:

C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Icons\dark (64-х разрядные операционные системы)

C:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Icons\dark (32-х разрядные операционные системы)

Создайте папку Images (Solution Explorer -> Add -> Create Folder -> Images), скопируйте туда иконки и добавьте к проекту (Solution Explorer -> Images -> Add -> Existent Item).

Откройте файл MainPage.xaml и заполните его следующим содержимым:

<phone:PhoneApplicationPage 
    x:Class="LocalDatabaseSample.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True"
    xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls">

    <phone:PhoneApplicationPage.Resources>
        <DataTemplate x:Key="AnimalListBoxItemTemplate">

            <Grid HorizontalAlignment="Stretch" Width="420">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="100" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="100" />
                </Grid.ColumnDefinitions>

                <CheckBox 
                    IsChecked="{Binding IsComplete, Mode=TwoWay}" 
                    Grid.Column="0" VerticalAlignment="Top"/>

                <TextBlock 
                    Text="{Binding ItemName}" 
                    FontSize="{StaticResource PhoneFontSizeLarge}" 
                    Grid.Column="1" Grid.ColumnSpan="2" 
                    VerticalAlignment="Top" Margin="-36, 12, 0, 0"/>

                <Button                                
                    Grid.Column="3"
                    x:Name="deleteTaskButton"
                    BorderThickness="0"                                                                  
                    Margin="0, -18, 0, 0"
                    Click="deleteTaskButton_Click">

                    <Image 
                    Source="/Images/appbar.delete.rest.png"
                    Height="75"
                    Width="75"/>

                </Button>
            </Grid>
        </DataTemplate>
    </phone:PhoneApplicationPage.Resources>

    <!--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="Образец локальной базы данных: зоология" 
                Style="{StaticResource PhoneTextNormalStyle}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here.-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <controls:Pivot Margin="0, -36, 0, 0">

                <controls:PivotItem Header="Все">
                    <ListBox 
                        x:Name="allAnimalItemsListBox" 
                        ItemsSource="{Binding AllAnimalItems}" 
                        Margin="12, 0, 12, 0" Width="440" 
                        ItemTemplate="{StaticResource AnimalListBoxItemTemplate}" />
                </controls:PivotItem>

                <controls:PivotItem Header="Птицы">
                    <ListBox 
                        x:Name="BirdsAnimalItemsListBox" 
                        ItemsSource="{Binding BirdsAnimalItems}" 
                        Margin="12, 0, 12, 0" Width="440" 
                        ItemTemplate="{StaticResource AnimalListBoxItemTemplate}" />
                </controls:PivotItem>

                <controls:PivotItem Header="Пресмыкающиеся">
                    <ListBox 
                        x:Name="ReptilesAnimalItemsListBox" 
                        ItemsSource="{Binding ReptilesAnimalItems}" 
                        Margin="12, 0, 12, 0" Width="440" 
                        ItemTemplate="{StaticResource AnimalListBoxItemTemplate}" />
                </controls:PivotItem>

                <controls:PivotItem Header="Рыбы">
                    <ListBox
                        x:Name="FishesAnimalItemsListBox" 
                        ItemsSource="{Binding FishesAnimalItems}" 
                        Margin="12, 0, 12, 0" Width="440" 
                        ItemTemplate="{StaticResource AnimalListBoxItemTemplate}" />
                </controls:PivotItem>

            </controls:Pivot>
        </Grid>
    </Grid>

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">

            <shell:ApplicationBarIconButton 
                IconUri="/Images/appbar.add.rest.png" 
                Text="add" 
                x:Name="newTaskAppBarButton" 
                Click="newTaskAppBarButton_Click"/>

        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>

</phone:PhoneApplicationPage>
    

Откройте файл MainPage.xaml.cs и введите следующий код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

/* 
    Copyright (c) 2011 Microsoft Corporation.  All rights reserved.
    Use of this sample source code is subject to the terms of the Microsoft license 
    agreement under which you licensed this sample source code and is provided AS-IS.
    If you did not accept the terms of the license agreement, you are not authorized 
    to use this sample source code.  For the terms of the license, please see the 
    license agreement between you and Microsoft.
    
*/

// Directive for the ViewModel.
using LocalDatabaseSample.Model;

namespace LocalDatabaseSample
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();

            // Set the page DataContext property to the ViewModel.
            this.DataContext = App.ViewModel;
        }

        private void newTaskAppBarButton_Click(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/NewTaskPage.xaml", UriKind.Relative));
        }


        private void deleteTaskButton_Click(object sender, RoutedEventArgs e)
        {
            // Cast the parameter as a button.
            var button = sender as Button;

            if (button != null)
            {
                // Get a handle for the Animal item bound to the button.
                AnimalItem AnimalForDelete = button.DataContext as AnimalItem;

                App.ViewModel.DeleteAnimalItem(AnimalForDelete);
            }

            // Put the focus back to the main page.
            this.Focus();
        }

        protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
        {
            // Save changes to the database.
            App.ViewModel.SaveChangesToDB();
        }
    }
}
    

Добавьте файл NewTaskPage.xaml в портретной ориентации:

Содержимое файла NewTaskPage.xaml:

<phone:PhoneApplicationPage 
    x:Class="LocalDatabaseSample.NewTaskPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="696" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True"
    xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit">

    <!--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="Образец локальной базы данных: Зоология" 
                Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock 
                x:Name="PageTitle" 
                Text="Добавить" 
                Margin="9,-7,0,0" 
                Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here.-->
        <StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <TextBlock Text="Вид"/>
            <TextBox x:Name="newTaskNameTextBox"/>
            <TextBlock Text="Класс"/>

            <toolkit:ListPicker
                x:Name="categoriesListPicker"
                ItemsSource="{Binding CategoriesList}"
                DisplayMemberPath="Name">
            </toolkit:ListPicker>
        </StackPanel>
    </Grid>

    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">

            <shell:ApplicationBarIconButton 
                x:Name="appBarOkButton" 
                IconUri="/Images/appbar.check.rest.png" 
                Text="ok" 
                Click="appBarOkButton_Click"/>

            <shell:ApplicationBarIconButton 
                x:Name="appBarCancelButton" 
                IconUri="/Images/appbar.cancel.rest.png" 
                Text="cancel" 
                Click="appBarCancelButton_Click"/>

        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>

</phone:PhoneApplicationPage>
    

Перейдите к файлу NewTaskPage.xaml.cs и введите следующий код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

/* 
    Copyright (c) 2011 Microsoft Corporation.  All rights reserved.
    Use of this sample source code is subject to the terms of the Microsoft license 
    agreement under which you licensed this sample source code and is provided AS-IS.
    If you did not accept the terms of the license agreement, you are not authorized 
    to use this sample source code.  For the terms of the license, please see the 
    license agreement between you and Microsoft.
    
*/


// Directive for the data model.
using LocalDatabaseSample.Model;

namespace LocalDatabaseSample
{
    public partial class NewTaskPage : PhoneApplicationPage
    {
        public NewTaskPage()
        {
            InitializeComponent();

            // Set the page DataContext property to the ViewModel.
            this.DataContext = App.ViewModel;
        }

        private void appBarOkButton_Click(object sender, EventArgs e)
        {
            // Confirm there is some text in the text box.
            if (newTaskNameTextBox.Text.Length > 0)
            {
                // Create a new Animal item.
                AnimalItem newAnimalItem = new AnimalItem
                {
                    ItemName = newTaskNameTextBox.Text,
                    Category = (AnimalCategory)categoriesListPicker.SelectedItem
                };

                // Add the item to the ViewModel.
                App.ViewModel.AddAnimalItem(newAnimalItem);

                // Return to the main page.
                if (NavigationService.CanGoBack)
                {
                    NavigationService.GoBack();
                }
            }
        }

        private void appBarCancelButton_Click(object sender, EventArgs e)
        {
            // Return to the main page.
            if (NavigationService.CanGoBack)
            {
                NavigationService.GoBack();
            }
        }
    }
}
    

Откройте файл App.xaml.cs и введите следующий код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;

/* 
    Copyright (c) 2011 Microsoft Corporation.  All rights reserved.
    Use of this sample source code is subject to the terms of the Microsoft license 
    agreement under which you licensed this sample source code and is provided AS-IS.
    If you did not accept the terms of the license agreement, you are not authorized 
    to use this sample source code.  For the terms of the license, please see the 
    license agreement between you and Microsoft.
    
*/

// Directives 
using LocalDatabaseSample.Model;
using LocalDatabaseSample.ViewModel;

namespace LocalDatabaseSample
{
    public partial class App : Application
    {
        /// <summary>
        /// Provides easy access to the root frame of the Phone Application.
        /// </summary>
        /// <returns>The root frame of the Phone Application.</returns>
        public PhoneApplicationFrame RootFrame { get; private set; }

        // The static ViewModel, to be used across the application.
        private static AnimalViewModel viewModel;
        public static AnimalViewModel ViewModel
        {
            get { return viewModel; }
        }

        /// <summary>
        /// Constructor for the Application object.
        /// </summary>
        public App()
        {
            // Global handler for uncaught exceptions. 
            UnhandledException += Application_UnhandledException;

            // Standard Silverlight initialization
            InitializeComponent();

            // Phone-specific initialization
            InitializePhoneApplication();

            // Show graphics profiling information while debugging.
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // Display the current frame rate counters.
                Application.Current.Host.Settings.EnableFrameRateCounter = true;

                // Show the areas of the app that are being redrawn in each frame.
                //Application.Current.Host.Settings.EnableRedrawRegions = true;

                // Enable non-production analysis visualization mode, 
                // which shows areas of a page that are handed off to GPU with a colored overlay.
                //Application.Current.Host.Settings.EnableCacheVisualization = true;

                // Disable the application idle detection by setting the UserIdleDetectionMode property of the
                // application's PhoneApplicationService object to Disabled.
                // Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run
                // and consume battery power when the user is not using the phone.
                PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled;
            }

            // Specify the local database connection string.
            string DBConnectionString = "Data Source=isostore:/Animal.sdf";

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

                    // Prepopulate the categories.
                    db.Categories.InsertOnSubmit(new AnimalCategory { Name = "Птицы" });
                    db.Categories.InsertOnSubmit(new AnimalCategory { Name = "Пресмыкающиеся" });
                    db.Categories.InsertOnSubmit(new AnimalCategory { Name = "Рыбы" });

                    // Save categories to the database.
                    db.SubmitChanges();
                }
            }

            // Create the ViewModel object.
            viewModel = new AnimalViewModel(DBConnectionString);

            // Query the local database and load observable collections.
            viewModel.LoadCollectionsFromDatabase();

        }

        // Code to execute when the application is launching (eg, from Start)
        // This code will not execute when the application is reactivated
        private void Application_Launching(object sender, LaunchingEventArgs e)
        {
        }

        // Code to execute when the application is activated (brought to foreground)
        // This code will not execute when the application is first launched
        private void Application_Activated(object sender, ActivatedEventArgs e)
        {
        }

        // Code to execute when the application is deactivated (sent to background)
        // This code will not execute when the application is closing
        private void Application_Deactivated(object sender, DeactivatedEventArgs e)
        {
        }

        // Code to execute when the application is closing (eg, user hit Back)
        // This code will not execute when the application is deactivated
        private void Application_Closing(object sender, ClosingEventArgs e)
        {
        }

        // Code to execute if a navigation fails
        private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // A navigation has failed; break into the debugger
                System.Diagnostics.Debugger.Break();
            }
        }

        // Code to execute on Unhandled Exceptions
        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            if (System.Diagnostics.Debugger.IsAttached)
            {
                // An unhandled exception has occurred; break into the debugger
                System.Diagnostics.Debugger.Break();
            }
        }

        #region Phone application initialization

        // Avoid double-initialization
        private bool phoneApplicationInitialized = false;

        // Do not add any additional code to this method
        private void InitializePhoneApplication()
        {
            if (phoneApplicationInitialized)
                return;

            // Create the frame but don't set it as RootVisual yet; this allows the splash
            // screen to remain active until the application is ready to render.
            RootFrame = new PhoneApplicationFrame();
            RootFrame.Navigated += CompleteInitializePhoneApplication;

            // Handle navigation failures
            RootFrame.NavigationFailed += RootFrame_NavigationFailed;

            // Ensure we don't initialize again
            phoneApplicationInitialized = true;
        }

        // Do not add any additional code to this method
        private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
        {
            // Set the root visual to allow the application to render
            if (RootVisual != RootFrame)
                RootVisual = RootFrame;

            // Remove this handler since it is no longer needed
            RootFrame.Navigated -= CompleteInitializePhoneApplication;
        }

        #endregion
    }
}
    

Создайте папку Model и разместите в ней файл кода AnimalDataContext.cs со следующим содержимым:

using System;
using System.ComponentModel;
using System.Data.Linq;
using System.Data.Linq.Mapping;

/* 
    Copyright (c) 2011 Microsoft Corporation.  All rights reserved.
    Use of this sample source code is subject to the terms of the Microsoft license 
    agreement under which you licensed this sample source code and is provided AS-IS.
    If you did not accept the terms of the license agreement, you are not authorized 
    to use this sample source code.  For the terms of the license, please see the 
    license agreement between you and Microsoft.
    
*/

namespace LocalDatabaseSample.Model
{

    public class AnimalDataContext : DataContext
    {
        // Pass the connection string to the base class.
        public AnimalDataContext(string connectionString)
            : base(connectionString)
        { }

        // Specify a table for the Animal items.
        public Table<AnimalItem> Items;

        // Specify a table for the categories.
        public Table<AnimalCategory> Categories;
    }


    [Table]
    public class AnimalItem : INotifyPropertyChanged, INotifyPropertyChanging
    {

        // Define ID: private field, public property, and database column.
        private int _AnimalItemId;

        [Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", 
          CanBeNull = false, AutoSync = AutoSync.OnInsert)]
        public int AnimalItemId
        {
            get { return _AnimalItemId; }
            set
            {
                if (_AnimalItemId != value)
                {
                    NotifyPropertyChanging("AnimalItemId");
                    _AnimalItemId = value;
                    NotifyPropertyChanged("AnimalItemId");
                }
            }
        }

        // 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");
                }
            }
        }

        // Internal column for the associated AnimalCategory ID value
        [Column]
        internal int _categoryId;

        // Entity reference, to identify the AnimalCategory "storage" table
        private EntityRef<AnimalCategory> _category;

        // Association, to describe the relationship between this key and that "storage" table
        [Association(Storage = "_category", ThisKey = "_categoryId", 
          OtherKey = "Id", IsForeignKey = true)]
        public AnimalCategory Category
        {
            get { return _category.Entity; }
            set
            {
                NotifyPropertyChanging("Category");
                _category.Entity = value;

                if (value != null)
                {
                    _categoryId = value.Id;
                }

                NotifyPropertyChanging("Category");
            }
        }

        // Version column aids update performance.
        [Column(IsVersion = true)]
        private Binary _version;

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        // Used to notify that a 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 that a property is about to change
        private void NotifyPropertyChanging(string propertyName)
        {
            if (PropertyChanging != null)
            {
                PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
            }
        }

        #endregion
    }

    [Table]
    public class AnimalCategory : INotifyPropertyChanged, INotifyPropertyChanging
    {

        // Define ID: private field, public property, and database column.
        private int _id;

        [Column(DbType = "INT NOT NULL IDENTITY", IsDbGenerated = true, IsPrimaryKey = true)]
        public int Id
        {
            get { return _id; }
            set
            {
                NotifyPropertyChanging("Id");
                _id = value;
                NotifyPropertyChanged("Id");
            }
        }

        // Define category name: private field, public property, and database column.
        private string _name;

        [Column]
        public string Name
        {
            get { return _name; }
            set
            {
                NotifyPropertyChanging("Name");
                _name = value;
                NotifyPropertyChanged("Name");
            }
        }

        // Define the entity set for the collection side of the relationship.
        private EntitySet<AnimalItem> _Animals;

        [Association(Storage = "_Animals", OtherKey = "_categoryId", ThisKey = "Id")]
        public EntitySet<AnimalItem> Animals
        {
            get { return this._Animals; }
            set { this._Animals.Assign(value); }
        }


        // Assign handlers for the add and remove operations, respectively.
        public AnimalCategory()
        {
            _Animals = new EntitySet<AnimalItem>(
                new Action<AnimalItem>(this.attach_Animal),
                new Action<AnimalItem>(this.detach_Animal)
                );
        }

        // Called during an add operation
        private void attach_Animal(AnimalItem Animal)
        {
            NotifyPropertyChanging("AnimalItem");
            Animal.Category = this;
        }

        // Called during a remove operation
        private void detach_Animal(AnimalItem Animal)
        {
            NotifyPropertyChanging("AnimalItem");
            Animal.Category = null;
        }

        // Version column aids update performance.
        [Column(IsVersion = true)]
        private Binary _version;

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        // Used to notify that a 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 that a property is about to change
        private void NotifyPropertyChanging(string propertyName)
        {
            if (PropertyChanging != null)
            {
                PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
            }
        }

        #endregion
    }
}
    

Создайте папку ViewModel и разместите в ней файл AnimalViewModel.cs со следующим содержимым:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;

/* 
    Copyright (c) 2011 Microsoft Corporation.  All rights reserved.
    Use of this sample source code is subject to the terms of the Microsoft license 
    agreement under which you licensed this sample source code and is provided AS-IS.
    If you did not accept the terms of the license agreement, you are not authorized 
    to use this sample source code.  For the terms of the license, please see the 
    license agreement between you and Microsoft.
    
*/

// Directive for the data model.
using LocalDatabaseSample.Model;

namespace LocalDatabaseSample.ViewModel
{
    public class AnimalViewModel : INotifyPropertyChanged
    {
        // LINQ to SQL data context for the local database.
        private AnimalDataContext AnimalDB;

        // Class constructor, create the data context object.
        public AnimalViewModel(string AnimalDBConnectionString)
        {
            AnimalDB = new AnimalDataContext(AnimalDBConnectionString);
        }

        // All to-do items.
        private ObservableCollection<AnimalItem> _allAnimalItems;
        public ObservableCollection<AnimalItem> AllAnimalItems
        {
            get { return _allAnimalItems; }
            set
            {
                _allAnimalItems = value;
                NotifyPropertyChanged("AllAnimalItems");
            }
        }

        // Animal items associated with the Birds category.
        private ObservableCollection<AnimalItem> _BirdsAnimalItems;
        public ObservableCollection<AnimalItem> BirdsAnimalItems
        {
            get { return _BirdsAnimalItems; }
            set
            {
                _BirdsAnimalItems = value;
                NotifyPropertyChanged("BirdsAnimalItems");
            }
        }

        // Animal items associated with the Reptiles category.
        private ObservableCollection<AnimalItem> _ReptilesAnimalItems;
        public ObservableCollection<AnimalItem> ReptilesAnimalItems
        {
            get { return _ReptilesAnimalItems; }
            set
            {
                _ReptilesAnimalItems = value;
                NotifyPropertyChanged("ReptilesAnimalItems");
            }
        }

        // Animal items associated with the Fishes category.
        private ObservableCollection<AnimalItem> _FishesAnimalItems;
        public ObservableCollection<AnimalItem> FishesAnimalItems
        {
            get { return _FishesAnimalItems; }
            set
            {
                _FishesAnimalItems = value;
                NotifyPropertyChanged("FishesAnimalItems");
            }
        }

        // A list of all categories, used by the add task page.
        private List<AnimalCategory> _categoriesList;
        public List<AnimalCategory> CategoriesList
        {
            get { return _categoriesList; }
            set
            {
                _categoriesList = value;
                NotifyPropertyChanged("CategoriesList");
            }
        }

        // Query database and load the collections and list used by the pivot pages.
        public void LoadCollectionsFromDatabase()
        {

            // Specify the query for all to-do items in the database.
            var AnimalItemsInDB = from AnimalItem Animal in AnimalDB.Items
                                  select Animal;

            // Query the database and load all to-do items.
            AllAnimalItems = new ObservableCollection<AnimalItem>(AnimalItemsInDB);

            // Specify the query for all categories in the database.
            var AnimalCategoriesInDB = from AnimalCategory category in AnimalDB.Categories
                                       select category;


            // Query the database and load all associated items to their respective collections.
            foreach (AnimalCategory category in AnimalCategoriesInDB)
            {
                switch (category.Name)
                {
                    case "Птицы":
                        BirdsAnimalItems = new ObservableCollection<AnimalItem>(category.Animals);
                        break;
                    case "Пресмыкающиеся":
                        ReptilesAnimalItems = new ObservableCollection<AnimalItem>(category.Animals);
                        break;
                    case "Рыбы":
                        FishesAnimalItems = new ObservableCollection<AnimalItem>(category.Animals);
                        break;
                    default:
                        break;
                }
            }

            // Load a list of all categories.
            CategoriesList = AnimalDB.Categories.ToList();

        }

        // Add an Animal item to the database and collections.
        public void AddAnimalItem(AnimalItem newAnimalItem)
        {
            // Add an Animal item to the data context.
            AnimalDB.Items.InsertOnSubmit(newAnimalItem);

            // Save changes to the database.
            AnimalDB.SubmitChanges();

            // Add an Animal item to the "all" observable collection.
            AllAnimalItems.Add(newAnimalItem);

            // Add an Animal item to the appropriate filtered collection.
            switch (newAnimalItem.Category.Name)
            {
                case "Птицы":
                    BirdsAnimalItems.Add(newAnimalItem);
                    break;
                case "Пресмыкающиеся":
                    ReptilesAnimalItems.Add(newAnimalItem);
                    break;
                case "Рыбы":
                    FishesAnimalItems.Add(newAnimalItem);
                    break;
                default:
                    break;
            }
        }

        // Remove an Animal task item from the database and collections.
        public void DeleteAnimalItem(AnimalItem AnimalForDelete)
        {

            // Remove the Animal item from the "all" observable collection.
            AllAnimalItems.Remove(AnimalForDelete);

            // Remove the Animal item from the data context.
            AnimalDB.Items.DeleteOnSubmit(AnimalForDelete);

            // Remove the Animal item from the appropriate category.   
            switch (AnimalForDelete.Category.Name)
            {
                case "Птицы":
                    BirdsAnimalItems.Remove(AnimalForDelete);
                    break;
                case "Пресмыкающиеся":
                    ReptilesAnimalItems.Remove(AnimalForDelete);
                    break;
                case "Рыбы":
                    FishesAnimalItems.Remove(AnimalForDelete);
                    break;
                default:
                    break;
            }

            // Save changes to the database.
            AnimalDB.SubmitChanges();
        }



        // Write changes in the data context to the database.
        public void SaveChangesToDB()
        {
            AnimalDB.SubmitChanges();
        }

        #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
    }
}
    

Запустите проект, нажав клавишу F5. Нажмите на кнопку Start, затем выберите пункт SETTINGS:

Выберите пункт Region + Language, В разделе Display language выберите русский язык:

Сохраните настройки.

Вернитесь в приложение LocalDataBaseSample. Поработайте с базой данных.

Вернуться к учебному плану