Основы разработки приложений беспроводных устройств

Лабораторный практикум 1

Показывать лекцию целиком

Лабораторная работа №1. Телефонная книжка

Задание

Создать простую телефонную книжку для Windows Phone 7 с возможностью создания новых контактов, просмотра, редактирования и удаления имеющихся.

Освоение

  • навигация между страницами
  • основные элементы управления и разметки (Grid, StackPanel, TextBox, TextBlock, Button, ListBox)
  • события
  • контекст ввода
  • меню приложения
  • Описание

    Приложение, которое мы будем создавать, основано на 4 основных функциях управления данными – CRUD (create, read, update, delete).

    Для начала определимся, что хотим получить. Приложение будет состоять из 2 окон: основного со списком контактов и окна редактирования/добавления контактов Рис. 2.1 .

    (рис 2.1) Внешний вид приложения

    Создадим новый проект Silverlight for Windows Phone – Windows Phone Application.

    Откроем файл разметки главной страницы MainPage.xaml. Изменим текст названия приложения ApplicationTitle, например, на "КОНТАКТЫ". Для того чтобы выделить больше места для будущего списка контактов, закомментируем или удалим блок заголовка страницы PageTitle.

    <!--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="page name" Margin="9,-7,0,0" 
                Style="{StaticResource PhoneTextTitle1Style}"/-->
            </StackPanel>
    

    Внутрь объекта Grid с именем ContentPanel поместим элемент ListBox. Назовем его listContacts (атрибут Name – необходим тем элементам, к которым будет непосредственное обращение из кода программы) и определим высоту списка (атрибут Height). Внутрь ListBox поместим несколько первых контактов, которые будут доступны сразу после запуска приложения. Каждый элемент списка необходимо заключить в тег ListBoxItem. Т.к. контакт состоит из имени и номера телефона, добавим внутрь объекта ListBoxItem два текстовых блока TextBlock. Определим для них атрибуты FontSize (размер шрифта) и Margin (отступы). Поскольку. данные блоки идут последовательно друг за другом, их необходимо заключить в тег StackPanel.

    <!--ContentPanel - place additional content here-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <ListBox Name="listContacts" Height="615">
                    <ListBoxItem>
                        <StackPanel Margin="10,7,10,7">
                            <TextBlock Text="Андреев Андрей" FontSize="28" />
                            <TextBlock Text="+79215555555" FontSize="22" Margin="50,0,0,0" />
                        </StackPanel>
                    </ListBoxItem>
                    <ListBoxItem>
                        <StackPanel Margin="10,7,10,7">
                            <TextBlock Text="Иванов Иван" FontSize="28" />
                            <TextBlock Text="+79114444444" FontSize="22" Margin="50,0,0,0" />
                        </StackPanel>
                    </ListBoxItem>
                    <ListBoxItem>
                        <StackPanel Margin="10,7,10,7">
                            <TextBlock Text="Алексеев Алексей" FontSize="28" />
                            <TextBlock Text="+79656666666" FontSize="22" Margin="50,0,0,0" />
                        </StackPanel>
                    </ListBoxItem>
                </ListBox>
            </Grid>
    

    Создадим меню на главной странице нашего приложения. Для этого в самом низу файла MainPage.xaml уберем комментарии, в которые заключен тег phone:PhoneApplicationPage.ApplicationBar и его содержимое. Добавим еще один элемент shell:ApplicationBarIconButton и изменим текст (атрибут Text) для всех пунктов меню. Также можно поменять картинки для пунктов меню (атрибут IconUri). В данном примере мы этого делать не будем. Добавим обработчики нажатия на кнопки меню. Для этого добавим в теги shell:ApplicationBarIconButton атрибут Click. При этом в файле MainPage.xaml.cs автоматически будут добавлены соответствующие пустые обработчики.

    Элементы shell:ApplicationBar.MenuItems закомментируем или удалим – для данного приложения они нам не понадобятся.

    <!--Sample code showing usage of ApplicationBar-->
        <phone:PhoneApplicationPage.ApplicationBar>
            <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" 
                Text="Добавить" Click="ApplicationBarMenuAdd_Click" />
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" 
                Text="Изменить" Click="ApplicationBarMenuEdit_Click" />
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button3.png" 
                Text="Удалить" Click="ApplicationBarMenuRemove_Click" />
            </shell:ApplicationBar>
        </phone:PhoneApplicationPage.ApplicationBar>
    

    Добавим в проект приложения новую страницу – Windows Phone Portrait Page. Назовем ее PageEdit. Откроем файл PageEdit.xaml. Изменим имя приложения на "КОНТАКТЫ". Можно также удалить заголовок страницы. В данном случаем мы его оставим.

    <!--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>
    

    Внутрь объекта Grid с именем ContentPanel поместим элементы управления. Пусть текстовые поля будут находиться в одной таблице (Grid), а кнопки в другой:

    текстовый блок "Имя:" текстовое поле "txtName"
    текстовый блок "Телефон:" текстовое поле "txtPhone"
    кнопка btnApply кнопка btnCancel

    Таблицы поместим в тег StackPanel. Элемент Grid состоит из части объявления строк и столбцов и части содержимого. Элементы содержимого должны содержать в себе атрибуты Grid.Column и Grid.Row, которые обозначают индексы столбца и строки таблицы, в которой находятся (индексы нумеруются с нуля). Атрибут ShowGridLines позволяет сделать видимой или невидимой границу таблицы. Определим также вертикальное выравнивание элементов (VerticalAlignment) и размер шрифта (FontSize). Для текстового поля txtPhone определим контекст ввода (InputScope). Контекст ввода служит для того, чтобы пользователю было удобнее вводить те или иные данные в текстовое поле. Если установить значение атрибута InputScope в "TelephoneNumber", то клавиатура будет установлена в телефонный режим ввода Рис. 2.2 .

    (рис 2.2) Клавиатура в телефонном режиме ввода

    <Grid ShowGridLines="False" Margin="0,20,0,0">
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>
    					
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="340" />
                        </Grid.ColumnDefinitions>
    
                        <TextBlock Text="Имя:" Grid.Column="0" Grid.Row="0" VerticalAlignment="Center" FontSize="24" />
                        <TextBlock Text="Телефон:" Grid.Column="0" Grid.Row="1" VerticalAlignment="Center" FontSize="24" />
                        <TextBox Name="txtName" Text="Имя" Grid.Column="1" Grid.Row="0" />
                        <TextBox Name="txtPhone" Text="Телефон" InputScope="TelephoneNumber" Grid.Column="1" Grid.Row="1" />
                   </Grid>
    

    Для кнопок btnApply и btnCancel определим атрибут Click – обработчик кнопок.

    Итак, весь код содержимого ContentPanel в итоге должен выглядеть примерно так:

    <!--ContentPanel - place additional content here-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <StackPanel Margin="5,5,5,5">
                    <Grid ShowGridLines="False" Margin="0,20,0,0">
                       <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>
    
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="340" />
                        </Grid.ColumnDefinitions>
    
                        <TextBlock Text="Имя:" Grid.Column="0" Grid.Row="0" VerticalAlignment="Center" FontSize="24" />
                        <TextBlock Text="Телефон:" Grid.Column="0" Grid.Row="1" VerticalAlignment="Center" FontSize="24" />
                        <TextBox Name="txtName" Text="Имя" Grid.Column="1" Grid.Row="0" />
                        <TextBox Name="txtPhone" Text="Телефон" InputScope="TelephoneNumber" Grid.Column="1" Grid.Row="1" />
                    </Grid>
    
                    <Grid Margin="0,20,0,0">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="90"/>
                        </Grid.RowDefinitions>
    
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="220" />
                            <ColumnDefinition Width="220" />
                        </Grid.ColumnDefinitions>
    
                        <Button Name="btnApply" Grid.Column="0" Grid.Row="0" Content="Принять" Click="btnApply_Click" />
                        <Button Name="btnCancel" Grid.Column="1" Grid.Row="0" Content="Отмена" Click="btnCancel_Click" />
                    </Grid>
                </StackPanel>
            </Grid>
    

    Теперь перейдем к программированию логики нашего приложения.

    Откроем файл MainPage.xaml.cs. При нажатии на кнопку "Добавить" должен происходить переход на страницу PageEdit.xaml. Для этого в самом верху кода пропишем директиву, облегчит написание переходов между страницами:

    using System.Windows.Navigation;
    

    Перейдем к обработчику нажатия на кнопку "Добавить". Напишем здесь код перехода на страницу добавления/изменения контактов:

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

    В обработчике нажатия на кнопку "Удалить" следует получить индекс выделенного элемента списка и, если он не равен -1 (если есть выделенный элемент), удалить данный элемент. Поскольку в элементе ListBox мы задали значение атрибута Name="listContacts", то обращение к списку из кода программы следует осуществлять через объект listContacts.

    private void ApplicationBarMenuRemove_Click(object sender, EventArgs e)
    {
        int nIndex = listContacts.SelectedIndex;
    
        if (-1 != nIndex)
        {
           listContacts.Items.RemoveAt(nIndex);
        }
        else
        {
           MessageBox.Show("Контакт не выбран.");
                }
            }
    

    Теперь перейдем к обработчику нажатия на кнопку "Изменить". Здесь также следует получить индекс выделенного элемента списка и проверить, что он не равен -1. Поскольку элементы списка контактов в приложении задаются динамически, то обращение по имени к этим элементам затруднено. Поэтому для получения значений имени контакта и телефона необходимо:

  • получить выделенный элемент списка и привести его к типу ListBoxItem;
  • получить содержимое элемента ListBoxItem и привести его к типу StackPanel;
  • получить коллекцию элементов StackPanel и из нее взять элемент с индексом 0 (для имени контакта) или 1 (для телефона контакта) и привести его к типу TextBlock;
  • получить значение свойства Text элемента TextBlock.
  • Данная процедура множественного преобразования типов на C# будет выглядеть следующим образом:

    string strName = ((TextBlock)((StackPanel)((ListBoxItem)listContacts.SelectedItem)
    .Content).Children.ElementAt(0)).Text;
         string strPhone = ((TextBlock)((StackPanel)((ListBoxItem)listContacts.SelectedItem)
         .Content).Children.ElementAt(1)).Text;
    

    Полученные имя и телефон следует передать на страницу PageEdit.xaml для того, чтобы заполнить данными значениями текстовые поля. Кроме того, после редактирования и возвращения измененных значений нам необходимо знать индекс выделенного элемента (вообще говоря, можно обойтись и без этого, т.к. выделенный индекс должен запомниться, но в нашем примере мы поступим именно так).

    Передача параметров между страницами осуществляется так же, как и в web-приложениях GET-запрос. Поскольку после адреса страницы ставится символ "?", за которым следуют пары "ключ=значение", разделенные символом "". Передаваемые строковые значения следует преобразовывать с помощью функции Uri.EscapeDataString(). В этом случае будет обеспечена правильная передача специальных символов, таких как "".

    private void ApplicationBarMenuEdit_Click(object sender, EventArgs e)
            {
                int nIndex = listContacts.SelectedIndex;
    
                if (-1 != nIndex)
                {
                    string strName = ((TextBlock)((StackPanel)((ListBoxItem)listContacts.SelectedItem)
                    .Content).Children.ElementAt(0)).Text;
                    string strPhone = ((TextBlock)((StackPanel)((ListBoxItem)listContacts.SelectedItem)
                    .Content).Children.ElementAt(1)).Text;
    
                    NavigationService.Navigate(new Uri("/PageEdit.xaml?name=" + Uri.EscapeDataString(strName) +
                            "phone=" + Uri.EscapeDataString(strPhone) +
                            "id=" + Uri.EscapeDataString(nIndex.ToString()),
                            UriKind.Relative));
                }
                else
                {
                    MessageBox.Show("Контакт не выбран.");
                }
            }
    

    Перейдем к файлу PageEdit.xaml.cs. В самый верх добавим директиву:

    using System.Windows.Navigation;
    

    В класс PageEdit добавим новую переменную, которая будет хранить значение индекса текущего элемента:

    private int nCurrentId = -1;
    

    Добавим в класс перегруженный метод перехвата пришедших запросов OnNavigatedTo(NavigationEventArgs e). В этом методе будем считывать и обрабатывать пришедшие имена, телефоны и индексы контактов.

    Если в полученном запросе есть ключи id, name и phone, значит, пользователь нажал кнопку "Редактировать". В этом случае просто следует присвоить свойствам Text текстовых полей пришедшие значения.

    Если полученный запрос не содержит таких ключей, значит, пользователь нажал кнопку "Добавить". В этом случае следует очистить свойства Text.

    protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                //если есть ключи, значит - режим редактирования
                if (NavigationContext.QueryString.ContainsKey("id") 
                    NavigationContext.QueryString.ContainsKey("name") 
                    NavigationContext.QueryString.ContainsKey("phone"))
                {
                    if (!int.TryParse(NavigationContext.QueryString["id"].ToString(), out nCurrentId))
                    {
                        nCurrentId = -1;
                    }
    
                    txtName.Text = NavigationContext.QueryString["name"].ToString();
                    txtPhone.Text = NavigationContext.QueryString["phone"].ToString();
    
                    PageTitle.Text = "изменение";
                }
                else
                {
                    //режим добавления
    
                    nCurrentId = -1;
                    txtName.Text = "";
                    txtPhone.Text = "";
    
                    PageTitle.Text = "добавление";
                }
    
                txtName.Focus();
            }
    

    Теперь добавим обработчики нажатий на кнопки "Отмена" и "Принять". В первом случае будем выдавать сообщение с вопросом, точно ли пользователь хочет отменить действие. При подтверждении перейдем на главную страницу, вызвав метод NavigationService.GoBack():

    private void btnCancel_Click(object sender, RoutedEventArgs e)
            {
                MessageBoxResult result = MessageBox.Show("Изменения будут потеряны. 
                Продолжить?", "Отмена", MessageBoxButton.OKCancel);
                if (result == MessageBoxResult.OK)
                {
                    NavigationService.GoBack();
                }
            }
    

    Во втором случае будем проверять свойство Text текстовых полей на пустоту. Если же они непустые, будем передавать в главную страницу значения этих свойств. Если осуществлять переход на главную страницу посредством методы NavigationService.Navigate(), то страница MainPage.xaml будет перезагружаться, и все изменения будут потеряны. Поскольку мы пока что не умеем сохранять данные в базе или файле, будем использовать статический класс для передачи значений.

    Создадим в проекте новый класс. Назовем его Contact:

    public static class Contact
        {
            public static int m_Id;
            public static string m_Name;
            public static string m_Phone;
        }
    

    Теперь в обработчике нажатия на кнопку "Принять" просто будем заполнять поля статические поля класса, а переход осуществлять методом NavigationService.GoBack().

    private void btnApply_Click(object sender, RoutedEventArgs e)
            {
                if (txtName.Text.Trim().Length > 0)
                {
                    if (txtPhone.Text.Trim().Length > 0)
                    {
                        Contact.m_Id = nCurrentId;
                        Contact.m_Name = txtName.Text;
                        Contact.m_Phone = txtPhone.Text;
    
                        NavigationService.GoBack();
                    }
                    else
                    {
                        MessageBox.Show("Поле телефона не может быть пустым.");
                        txtPhone.Focus();
                    }
                }
                else
                {
                    MessageBox.Show("Поле имени не может быть пустым.");
                    txtName.Focus();
                }
            }
    

    Перейдем снова в файл MainPage.xaml.cs. Добавим в класс перегруженный метод перехвата пришедших запросов OnNavigatedTo(NavigationEventArgs e).

    Если значения полей статического класса Contact не равны null, то, если индекс равен -1, то добавляем новый контакт, иначе изменяем контакт. В конце следует обнулить поля класса Contact, чтобы при обновлении страницы (например, при переходе на страницу добавления/изменения и нажатия кнопки "Отмена") контакты не дублировались.

    protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                if ((null != Contact.m_Name)  (null != Contact.m_Phone))
                {
                    if (-1 == Contact.m_Id)
                    {
                        //добавление нового контакта
                        AddNewContact(Contact.m_Name, Contact.m_Phone);
                    }
                    else
                    {
                        //редактирование контакта
                        EditContact(Contact.m_Id, Contact.m_Name, Contact.m_Phone);
                    }
    
                    //обнуляем добавленный контакт (чтоб избежать дублирование контакта)
                    Contact.m_Id = 0;
                    Contact.m_Name = null;
                    Contact.m_Phone = null;
                }
            }
    

    Остается написать функции добавления нового контакта и изменения имеющего.

    При добавлении необходимо создать объекты ListBoxItem, StackPanel и TextBlock, заполнить необходимые свойства и добавить объекты TextBlock в StackPanel, StackPanel в ListBoxItem, а ListBoxItem в listContacts:

    private void AddNewContact(string strName, string strPhone)
            {
                ListBoxItem lstitNew = new ListBoxItem();
                StackPanel stkNew = new StackPanel();
                TextBlock txtNameNew = new TextBlock();
                TextBlock txtPhoneNew = new TextBlock();
    
                txtNameNew.Text = strName;
                txtNameNew.FontSize = 28;
                txtPhoneNew.Text = strPhone;
                txtPhoneNew.FontSize = 22;
                txtPhoneNew.Margin = new Thickness(50, 0, 0, 0);
    
                stkNew.Margin = new Thickness(10, 7, 10, 7);
                stkNew.Children.Add(txtNameNew);
                stkNew.Children.Add(txtPhoneNew);
    
                lstitNew.Content = stkNew;
    
                listContacts.Items.Add(lstitNew);
                listContacts.SelectedIndex = listContacts.Items.Count - 1;
            }
    

    При изменении придется снова воспользоваться множественным приведение типов:

    private void EditContact(int nIndex, string strName, string strPhone)
            {
                if ((nIndex >= 0)  (nIndex < listContacts.Items.Count))
                {
                    ((TextBlock)((StackPanel)((ListBoxItem)listContacts.Items[nIndex]).Content)
                    .Children.ElementAt(0)).Text = strName;
                    ((TextBlock)((StackPanel)((ListBoxItem)listContacts.Items[nIndex]).Content)
                    .Children.ElementAt(1)).Text = strPhone;
                }
                else
                {
                    MessageBox.Show("Ошибка. Индекс за границами массива.");
                }
            }
    

    Теперь можно скомпилировать приложение, запустить его на эмуляторе или телефоне и проверить его функционирование.

    Лабораторная работа №2. Блокнот

    Задание

    Создать приложение "Блокнот" для Windows Phone 7 с возможностью изменения настроек текста (шрифт, размер, цвет, выравнивание).

    Освоение

  • навигация между страницами
  • основные элементы управления и разметки (Grid, StackPanel, TextBox, TextBlock, Button, RadioButton, CheckBox, Slider, ScrollViewer)
  • события
  • компонент Pivot
  • меню приложения
  • Описание

    Создадим новый проект Silverlight for Windows PhoneWindows Phone Application. Приложение будет состоять из 2 окон:

  • основное с текстовым полем
  • окно настроек
  • Начнем с основного окна.

    Откроем файл разметки главной страницы MainPage.xaml. Изменим текст названия приложения ApplicationTitle, например, на "БЛОКНОТ". Для того чтобы выделить больше места для текстового поля, закомментируем или удалим блок заголовка страницы PageTitle.

    <!--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="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/-->
            </StackPanel>
    

    Внутрь объекта Grid с именем ContentPanel поместим элемент ScrollViewer, а внутрь него TextBox. ScrollViewer нужен для обеспечения вертикальной прокрутки текстового поля. Определим ширину, высоту и автоматическое появление ScrollViewer. Текстовому полю дадим имя txtMain, назначим размер шрифта по умолчанию 24. Также выставим свойства AcceptsReturn="True" (перенос строки при нажатии на кнопку Enter на клавиатуре) и TextWrapping="Wrap" (перенос текста на новую строку по достижении границы текстового поля).

    < !--ContentPanel - place additional content here-->
            < Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                < ScrollViewer Height="620" Width="450" VerticalScrollBarVisibility="Auto">
                    < TextBox Name="txtMain" Text="Здесь можно печатать любой текст"
                     FontSize="24" AcceptsReturn="True" TextWrapping="Wrap" />
                < /ScrollViewer>
            < /Grid>
    

    Создадим меню на главной странице нашего приложения. Для этого в самом низу файла MainPage.xaml уберем комментарии, в которые заключен тег phone:PhoneApplicationPage.ApplicationBar и его содержимое. Удалим элементы shell:ApplicationBarIconButton и оставим только один элемент shell:ApplicationBarMenuItem. Назначим ему текст "Настройки" и событие Click="MenuProperties_Click".

    <!--Sample code showing usage of ApplicationBar-->
        <phone:PhoneApplicationPage.ApplicationBar>
            <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
                <shell:ApplicationBar.MenuItems>
                    <shell:ApplicationBarMenuItem Text="Настройки" Click="MenuProperties_Click" />
                </shell:ApplicationBar.MenuItems>
            </shell:ApplicationBar>
        </phone:PhoneApplicationPage.ApplicationBar>
    

    Перейдем к написанию кода страницы. Для этого откроем файл MainPage.xaml.cs.

    Для обеспечения перехода между страницами добавим в самый верх директиву:

    using System.Windows.Navigation;
    

    Теперь обдумаем, каким образом буем осуществлять передачу настроек текстового поля между страницами. Поскольку нам пока неизвестно, как работать файлами и локальной базой в Windows Phone 7, создадим статический класс Properties со статическими переменными:

    public static class Properties
        {
            public static bool bApply;
    
            public static int nFontSize;
            public static string strFontFamily;
            public static bool bItalic;
            public static bool bBold;
    
            public static TextAlignment taHAlignment;
    
            public static Color colorFont;
            public static Color colorBack;
        }
    

    Теперь в обработчике нажатия на кнопку меню напишем сохранение параметров текстового поля. После этого будем осуществлять переход на страницу настроек:

    private void MenuProperties_Click(object sender, EventArgs e)
            {
                Properties.nFontSize = (int)txtMain.FontSize;
                Properties.strFontFamily = txtMain.FontFamily.Source;
    
                Properties.bItalic = (txtMain.FontStyle == FontStyles.Italic);
                Properties.bBold = (txtMain.FontWeight == FontWeights.Bold);
    
                Properties.taHAlignment = txtMain.TextAlignment;
    
                Properties.colorFont = ((SolidColorBrush)txtMain.Foreground).Color;
                Properties.colorBack = ((SolidColorBrush)txtMain.Background).Color;
    
                NavigationService.Navigate(new Uri("/PropertiesPage.xaml", UriKind.Relative));
            }
    

    Добавим в проект новую страницу – Windows Phone Portrait Page. Назовем ее PropertiesPage. Откроем файл PropertiesPage.xaml и приступим к написанию разметки окна настроек.

    Так как настроек достаточно много, все они на одной странице будут выглядеть громоздко. Поэтому можно использовать компонент Pivot, который является аналогом панели вкладок в Windows-приложениях для настольного ПК Рис. 2.3 .

    (рис 2.3) Пример панели вкладок в Windows-приложениях

    Для того чтобы создать компонент Pivot на странице, необходимо добавить в References нашего проекта компонент Microsoft.Phone.Controls и в файле xaml в самый верх добавить пространство имен:

    xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
    

    Примечание: Вместо "controls" можно придумать любое другое название. В этом случае на странице разметки при использовании элементов управления из данного пространства имен нужно использовать соответствующее указанное название.

    Теперь мы можем создать компонент Pivot:

    < controls:Pivot Title="НАСТРОЙКИ">
                    
                < controls:PivotItem Header="шрифт">
                < /controls:PivotItem>
                    
                < controls:PivotItem Header="текст">
                < /controls:PivotItem>
                    
                < controls:PivotItem Header="цвет">
                < /controls:PivotItem>
            < /controls:Pivot>
    

    Поместим внутрь каждого "таба" элементы для изменения параметров текстового поля. Назовем первый – "шрифт". Будем менять шрифт, размер и начертание текста в текстовом поле. Для изменения размера будем использовать элементы Slider и TextBlock. Для изменения шрифта – несколько RadioButton. Для изменения начертания – CheckBox. Все элементы поместим внутрь таблицы Grid, состоящей из 2 колонок и 3 строк:

    <controls:PivotItem Header="шрифт">
                    <Grid Margin="10,0,10,0">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="90"/>
                            <RowDefinition/>
                            <RowDefinition/>
                        </Grid.RowDefinitions>
    
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="180" />
                            <ColumnDefinition Width="270" />
                        </Grid.ColumnDefinitions>
    
                        <TextBlock Text="Шрифт: " Margin="0,15,0,0" FontSize="26" Grid.Column="0" Grid.Row="0" />
                        <StackPanel Orientation="Horizontal"  Grid.Column="1" Grid.Row="0">
                            <Slider Name="sliderFontSize" Value="24" Minimum="1" Maximum="72"
                             Width="200" ValueChanged="sliderFontSize_ValueChanged" SmallChange="1" />
                            <TextBlock Name="lblFontSize" Text="24" FontSize="26" VerticalAlignment="Center" />
                        </StackPanel>
    
                        <TextBlock Text="Размер: " VerticalAlignment="Top" FontSize="26" Margin="0,15,0,0" 
                        Grid.Column="0" Grid.Row="1" />
                        <StackPanel Grid.Column="1" Grid.Row="1">
                            <RadioButton GroupName="fontSize" Name="radioFont1" Content="Segoe WP" 
                            IsChecked="True" Click="radioFont1_Click" />
                            <RadioButton GroupName="fontSize" Name="radioFont2" Content="Verdana"
                            FontFamily="Verdana" Click="radioFont2_Click" />
                            <RadioButton GroupName="fontSize" Name="radioFont3" Content="Courier New"
                             FontFamily="Courier New" Click="radioFont3_Click" />
                        </StackPanel>
    
                        <TextBlock Text="Начертания: " VerticalAlignment="Top" FontSize="26" 
                        Margin="0,15,0,0" Grid.Column="0" Grid.Row="2" />
                        <StackPanel Grid.Column="1" Grid.Row="2">
                            <CheckBox Name="checkItalic" Content="Курсив" Grid.Column="1" 
                            Grid.Row="2" FontStyle="Italic" Click="checkItalic_Click" />
                            <CheckBox Name="checkBold" Content="Полужирный" Grid.Column="1" 
                            Grid.Row="3" FontWeight="Bold" Click="checkBold_Click" />
                        </StackPanel>
                    </Grid>
                </controls:PivotItem>
    

    Второй PivotItem назовем "текст". Сюда добавим только RadioButton, с помощью которых будем задавать выравнивание:

    <controls:PivotItem Header="текст">
                    <Grid Margin="10,0,10,0">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="224" />
                        </Grid.RowDefinitions>
    
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="200" />
                            <ColumnDefinition Width="270" />
                        </Grid.ColumnDefinitions>
    
                        <TextBlock Text="Выравнивание по горизонтали: " FontSize="26" Margin="0,15,0,0" 
                        TextWrapping="Wrap" Grid.Column="0" Grid.Row="0" />
                        <StackPanel Grid.Column="1" Grid.Row="0">
                            <RadioButton GroupName="hAlign" Name="radioHAl1" Content="Center" 
                            Click="radioHAl1_Click" />
                            <RadioButton GroupName="hAlign" Name="radioHAl2" Content="Left" I
                            sChecked="True" Click="radioHAl2_Click" />
                            <RadioButton GroupName="hAlign" Name="radioHAl3" Content="Right"
                             Click="radioHAl3_Click" />
                        </StackPanel>
                    </Grid>
                </controls:PivotItem>
    

    Третий PivotItem назовем "цвет". Здесь будем менять цвета шрифта и фона текстового поля. Для этого воспользуемся элементом управления Rectangle. Также в этот элемент добавим небольшое текстовое поле, на котором будем демонстрировать пользователю сочетание выбранных им цветов:

    <controls:PivotItem Header="цвет">
                    <Grid Margin="10,0,10,0">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="200" />
                            <RowDefinition Height="200" />
                            <RowDefinition />
                        </Grid.RowDefinitions>
    
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="200" />
                            <ColumnDefinition Width="270" />
                        </Grid.ColumnDefinitions>
    
                        <TextBlock Text="Цвет шрифта: " FontSize="26" Margin="0,15,0,0" 
    TextWrapping="Wrap" Grid.Column="0" Grid.Row="0" />
                        <StackPanel Grid.Column="1" Grid.Row="0">
                            <Rectangle Height="32" Name="rectFont1" Stroke="White" StrokeThickness="1" 
                            Fill="Black" MouseEnter="rectFont1_MouseEnter" />
                            <Rectangle Height="32" Name="rectFont2" Stroke="Black" StrokeThickness="1" 
                            Fill="Red" MouseEnter="rectFont2_MouseEnter" />
                            <Rectangle Height="32" Name="rectFont3" Stroke="Black" StrokeThickness="1" 
                            Fill="Green" MouseEnter="rectFont3_MouseEnter" />
                            <Rectangle Height="32" Name="rectFont4" Stroke="Black" StrokeThickness="1" 
                            Fill="Blue" MouseEnter="rectFont4_MouseEnter" />
                            <Rectangle Height="32" Name="rectFont5" Stroke="Black" StrokeThickness="1" 
                            Fill="Yellow" MouseEnter="rectFont5_MouseEnter" />
                            <Rectangle Height="32" Name="rectFont6" Stroke="Black" StrokeThickness="1" 
                            Fill="White" MouseEnter="rectFont6_MouseEnter" />
                        </StackPanel>
    
                        <TextBlock Text="Цвет фона: " FontSize="26" Margin="0,15,0,0" 
    TextWrapping="Wrap" Grid.Column="0" Grid.Row="1" />
                        <StackPanel Grid.Column="1" Grid.Row="1">
                            <Rectangle Height="32" Name="rectBack1" Stroke="White" StrokeThickness="1"
                             Fill="Black" MouseEnter="rectBack1_MouseEnter" />
                            <Rectangle Height="32" Name="rectBack2" Stroke="Black" StrokeThickness="1" 
                            Fill="Red" MouseEnter="rectBack2_MouseEnter" />
                            <Rectangle Height="32" Name="rectBack3" Stroke="Black" StrokeThickness="1" 
                            Fill="Green" MouseEnter="rectBack3_MouseEnter" />
                            <Rectangle Height="32" Name="rectBack4" Stroke="Black" StrokeThickness="1" 
                            Fill="Blue" MouseEnter="rectBack4_MouseEnter" />
                            <Rectangle Height="32" Name="rectBack5" Stroke="Black" StrokeThickness="1" 
                            Fill="Yellow" MouseEnter="rectBack5_MouseEnter" />
                            <Rectangle Height="32" Name="rectBack6" Stroke="Black" StrokeThickness="1"
                             Fill="White" MouseEnter="rectBack6_MouseEnter" />
                        </StackPanel>
    
                        <TextBox Name="txtSample" Text="Пример" Height="80" Width="200" Grid.Row="2" Grid.ColumnSpan="2" />
                    </Grid>
                </controls:PivotItem>
            </controls:Pivot>
    

    По аналогии со страницей MainPage.xaml раскомментируем внизу элементы меню. Оставим две кнопки "Принять" и "Отмена":

    <!--Sample code showing usage of ApplicationBar--<
        <phone:PhoneApplicationPage.ApplicationBar<
            <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True"<
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" 
                Text="Принять" Click="btnApply_Click" /<
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" 
                Text="Отмена" Click="btnCancel_Click" /<
                <!--shell:ApplicationBar.MenuItems<
                    <shell:ApplicationBarMenuItem x:Name="menuItem1" Text="MenuItem 1"/<
                    <shell:ApplicationBarMenuItem x:Name="menuItem2" Text="MenuItem 2"/<
                </shell:ApplicationBar.MenuItems--<
            </shell:ApplicationBar<
        </phone:PhoneApplicationPage.ApplicationBar<
    

    Перейдем к коду.

    При нажатии на элементы раздела "шрифт" будем записывать в переменные глобального класса соответствующие новые значения. Поскольку значения элемента Slider могут быть нецелыми, будем их округлять. Новое значение будем писать в TextBlock с именем lblFontSize для удобства пользователя:

    private void sliderFontSize_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
            {
                if (null != sliderFontSize)
                {
                    Properties.nFontSize = (int)Math.Round(sliderFontSize.Value);
                    lblFontSize.Text = Properties.nFontSize.ToString();
                }
            }
    
            private void radioFont1_Click(object sender, RoutedEventArgs e)
            {
                Properties.strFontFamily = radioFont1.Content.ToString();
            }
    
            private void radioFont2_Click(object sender, RoutedEventArgs e)
            {
                Properties.strFontFamily = radioFont2.Content.ToString();
            }
    
            private void radioFont3_Click(object sender, RoutedEventArgs e)
            {
                Properties.strFontFamily = radioFont3.Content.ToString();
            }
    
            private void checkItalic_Click(object sender, RoutedEventArgs e)
            {
                Properties.bItalic = checkItalic.IsChecked.Value;
            }
    
            private void checkBold_Click(object sender, RoutedEventArgs e)
            {
                Properties.bBold = checkBold.IsChecked.Value;
            }
    

    Аналогичные обработчики событий сделаем для элементов вкладки "текст":

    private void radioHAl1_Click(object sender, RoutedEventArgs e)
            {
                Properties.taHAlignment = TextAlignment.Center;
            }
    
            private void radioHAl2_Click(object sender, RoutedEventArgs e)
            {
                Properties.taHAlignment = TextAlignment.Left;
            }
    
            private void radioHAl3_Click(object sender, RoutedEventArgs e)
            {
                Properties.taHAlignment = TextAlignment.Right;
            }
    
            private void radioHAl4_Click(object sender, RoutedEventArgs e)
            {
                Properties.taHAlignment = TextAlignment.Justify;
            }
    

    При обработке нажатий на элементы Rectangle будем записывать цвет в переменную и присваивать небольшому текстовому полю на странице:

    private void rectFont1_MouseEnter(object sender, MouseEventArgs e)
            {
                txtSample.Foreground = rectFont1.Fill;
                Properties.colorFont = Color.FromArgb(255, 0, 0, 0);
            }
    
            private void rectFont2_MouseEnter(object sender, MouseEventArgs e)
            {
                txtSample.Foreground = rectFont2.Fill;
                Properties.colorFont = Color.FromArgb(255, 255, 0, 0);
            }
    
            private void rectFont3_MouseEnter(object sender, MouseEventArgs e)
            {
                txtSample.Foreground = rectFont3.Fill;
                Properties.colorFont = Color.FromArgb(255, 0, 255, 0);
            }
    
            private void rectFont4_MouseEnter(object sender, MouseEventArgs e)
            {
                txtSample.Foreground = rectFont4.Fill;
                Properties.colorFont = Color.FromArgb(255, 0, 0, 255);
            }
    
            private void rectFont5_MouseEnter(object sender, MouseEventArgs e)
            {
                txtSample.Foreground = rectFont5.Fill;
                Properties.colorFont = Color.FromArgb(255, 255, 255, 0);
            }
    
            private void rectFont6_MouseEnter(object sender, MouseEventArgs e)
            {
                txtSample.Foreground = rectFont6.Fill;
                Properties.colorFont = Color.FromArgb(255, 255, 255, 255);
            }
    
            private void rectBack1_MouseEnter(object sender, MouseEventArgs e)
            {
                txtSample.Background = new SolidColorBrush(Color.FromArgb(255, 128, 128, 128));
                Properties.colorBack = Color.FromArgb(255, 0, 0, 0);
            }
    
            private void rectBack2_MouseEnter(object sender, MouseEventArgs e)
            {
                txtSample.Background = rectBack2.Fill;
                Properties.colorBack = Color.FromArgb(255, 255, 0, 0);
            }
    
            private void rectBack3_MouseEnter(object sender, MouseEventArgs e)
            {
                txtSample.Background = rectBack3.Fill;
                Properties.colorBack = Color.FromArgb(255, 0, 255, 0);
            }
    
            private void rectBack4_MouseEnter(object sender, MouseEventArgs e)
            {
                txtSample.Background = rectBack4.Fill;
                Properties.colorBack = Color.FromArgb(255, 0, 0, 255);
            }
    
            private void rectBack5_MouseEnter(object sender, MouseEventArgs e)
            {
                txtSample.Background = rectBack5.Fill;
                Properties.colorBack = Color.FromArgb(255, 255, 255, 0);
            }
    
            private void rectBack6_MouseEnter(object sender, MouseEventArgs e)
            {
                txtSample.Background = rectBack6.Fill;
                Properties.colorBack = Color.FromArgb(255, 255, 255, 255);
            }
    

    Для обеспечения перехода на главную страницу пропишем наверху директиву:

    using System.Windows.Navigation;
    

    Теперь напишем обработчики нажатия на кнопки меню. Так как при прямом переходе на главную страницу, она будет перезагружена, и данные потеряны, переход будем выполнять с помощью команды NavigationService.GoBack(). Данные будут передавать посредством статического класса Properties.

    private void btnApply_Click(object sender, EventArgs e)
            {
                Properties.bApply = true;
    
                //если перейти на страницу /MainPage.xaml, она будет обновлена, а данные потеряны
                //поэтому ГоБэк
                NavigationService.GoBack();
            }
    
            private void btnCancel_Click(object sender, EventArgs e)
            {
                MessageBoxResult result = MessageBox.Show("Изменения будут потеряны. Продолжить?", 
    "Отмена", MessageBoxButton.OKCancel);
                if (result == MessageBoxResult.OK)
                {
                    Properties.bApply = false;
    
                    NavigationService.GoBack();
                }
            }
    

    Переменная Properties.bApply нужна для того, чтобы на главной странице при присвоении текстовому полю новых параметров, знать, проинициализированы ли соответствующие переменные класса Properties.

    Теперь напишем обработчик инициализации элементов управления при переходе на страницу настроек. Для этого перегрузим метод OnNavigatedTo() и внутри него будем задавать для каждого элемента управления значение соответствующей переменной класса Properties:

    protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                sliderFontSize.Value = Properties.nFontSize;
    
                if (Properties.strFontFamily.Equals("Verdana"))
                {
                    radioFont2.IsChecked = true;
                }
                else
                {
                    if (Properties.strFontFamily.Equals("Courier New"))
                    {
                        radioFont3.IsChecked = true;
                    }
                    else
                    {
                        radioFont1.IsChecked = true; //Segoe WP
                    }
                }
    
                checkItalic.IsChecked = Properties.bItalic;
                checkBold.IsChecked = Properties.bBold;
    
                if (TextAlignment.Center == Properties.taHAlignment)
                {
                    radioHAl1.IsChecked = true;
                }
                else
                {
                    if (TextAlignment.Right == Properties.taHAlignment)
                    {
                        radioHAl3.IsChecked = true;
                    }
                    else
                    {
                        radioHAl2.IsChecked = true; //Left
                    }
                }
    
                txtSample.Foreground = new SolidColorBrush(Properties.colorFont);
                txtSample.Background = new SolidColorBrush(Properties.colorBack);
            }
    

    Вернемся к коду главной страницы (MainPage.xaml.cs). В конструкторе выполним инициализацию статической переменной Properties.bApply:

    // Constructor
            public MainPage()
            {
                InitializeComponent();
    
                //чтобы в самом начале не выполнялся OnNavigatedTo()
                Properties.bApply = false;
            }
    

    Перегрузим метод OnNavigatedTo(), в котором будем присваивать свойствам текстового поля значения из переменных класса Properties:

    protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                if (true == Properties.bApply)
                {
                    txtMain.FontSize = Properties.nFontSize;
                    txtMain.FontFamily = new FontFamily(Properties.strFontFamily);
    
                    txtMain.FontStyle = Properties.bItalic ? FontStyles.Italic : FontStyles.Normal;
                    txtMain.FontWeight = Properties.bBold ? FontWeights.Bold : FontWeights.Normal;
    
                    txtMain.TextAlignment = Properties.taHAlignment;
    
                    txtMain.Foreground = new SolidColorBrush(Properties.colorFont);
                    txtMain.Background = new SolidColorBrush(Properties.colorBack);
                }
            }
    

    Теперь можно скомпилировать приложение, запустить на эмуляторе или телефоне и проверить его функциональность.

    Лабораторная работа №3. Меню ресторана

    Задание

    Создать приложение "Меню ресторана" для Windows Phone 7 с использованием компонента Panorama. Предусмотреть возможность ввода номера дисконтной карты и подсчета скидки в реальном времени.

    Освоение

  • основные элементы управления и разметки (Grid, StackPanel, TextBox, TextBlock, CheckBox, Button)
  • компонент Panorama
  • события
  • контекст ввода
  • Описание

    Создадим новый проект Silverlight for Windows Phone – Windows Phone Application.

    Приложение будет состоять из одного окна, основанного на компоненте Panorama. Данный компонент позволяет выводить информацию за границы экрана, оставаясь в рамках одного окна. При перемещении между областями видимости происходит смещение картинки на заднем фоне. Потому компонент и получил название Panorama.

    Откроем файл разметки главной страницы MainPage.xaml. Компонент Panorama имеет свой заголовок, поэтому с целью экономии места на экране закомментируем или удалим часть кода, отвечающего за заголовок окна TitlePanel:

    <!--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="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>
                <TextBlock x:Name="PageTitle" Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
            </StackPanel-->
    

    Наше приложение будет автоматически подсчитывать сумму счета и вычислять скидку в случае, если введен код дисконтной карты. Таким образом, на экране необходимо разместить элементы вывода такой информации. Представим разметки страницы в виде таблицы с одним столбцом и двумя строками. В первой строке будет расположен компонент Panorama, во второй – элементы вывода суммы счета.

    Для того чтобы создать компонент Panorama на странице, необходимо добавить в References нашего проекта компонент Microsoft.Phone.Controls и в файле xaml в самый верх добавить пространство имен:

    xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
    

    Примечание: Вместо "controls" можно придумать любое другое название. В этом случае на странице разметки при использовании элементов управления из данного пространства имен нужно использовать соответствующее указанное название.

    Добавим в элемент Grid с именем ContentPanel разметку страницы. Внутри элемента Grid вначале нужно объявить, сколько будет строк и сколько столбцов у нашей таблицы. Каждому элементу содержимого страницы присваиваются индексы строк и столбцов Grid.Column и Grid.Row.

    Компоненту controls:Panorama зададим атрибут заголовка (Title). Внутри определим фоновую картинку с помощью тега controls:Panorama.Background (картинку с указанным названием необходимо добавить в проект приложения):

    <controls:Panorama.Background>
                        <ImageBrush ImageSource="Panorama.jpg" />
                    </controls:Panorama.Background>
    

    Содержимое панорамы будем помещать в элементы controls:PanoramaItem. Каждому элементу зададим заголовок (Header), соответствующий "странице" меню ресторана: салаты, первое, второе, напитки и скидка.

    После компонента controls:Panorama определим элементы TextBlock, объединенные в блок StackPanel.

    <!--ContentPanel - place additional content here-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition Height="90" />
                </Grid.RowDefinitions>
    
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
    
                <controls:Panorama Title="кафешка" Grid.Column="0" Grid.Row="0">
                    <controls:Panorama.Background>
                        <ImageBrush ImageSource="Panorama.jpg" />
                    </controls:Panorama.Background>
    
                    <controls:PanoramaItem Header="салаты">
                    </controls:PanoramaItem>
                    
                    <controls:PanoramaItem Header="первое">
                    </controls:PanoramaItem>
    
                    <controls:PanoramaItem Header="второе">
                    </controls:PanoramaItem>
    
                    <controls:PanoramaItem Header="напитки">
                    </controls:PanoramaItem>
    
                    <controls:PanoramaItem Header="скидка">
                    </controls:PanoramaItem>
                </controls:Panorama>
                
                <!-- Посчет суммы в реальном времени -->
                <StackPanel Grid.Column="0" Grid.Row="1">
                    <TextBlock Name="lblSum" Text="Сумма: 0 р." VerticalAlignment="Bottom" Margin="12,0,12,0" />
                    <TextBlock Name="lblDsc" Text="Скидки нет" VerticalAlignment="Bottom" Margin="12,0,12,0" />
                    <TextBlock Name="lblAll" Text="Итого: 0 р." VerticalAlignment="Bottom" Margin="12,0,12,0" />
                </StackPanel>
            </Grid>
    

    Создадим раздел меню "салаты". Для этого в первый элемент PanoramaItem добавим таблицу Grid, состоящую из 4 колонок. В первой будет располагаться CheckBox с наименованием салата (при нажатии на него будем изменять сумму счета). Во второй – TextBlock с массой салата в граммах. В третьей – TextBlock с ценой салата. В четвертой – валюта ("р."). Такое разделение задумано специально, чтобы автоматизировать процесс подсчета стоимости заказа. Для этого мы просто буем суммировать значения 3 колонки для всех включенных элементов CheckBox. Можно реализовать и другую логику, в том числе можно сделать меню динамическим списком.

    <controls:PanoramaItem Header="салаты">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="70" />
                                <RowDefinition Height="70" />
                                <RowDefinition Height="70" />
                            </Grid.RowDefinitions>
    
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="230" />
                                <ColumnDefinition Width="70" />
                                <ColumnDefinition Width="60" />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>
    
                            <CheckBox Name="checkSalad1" Content="Греческий" FontSize="26" VerticalAlignment="Center" 
                            Grid.Column="0" Grid.Row="0" Click="checkSalad1_Click" />
                            <TextBlock Text="100 г" FontSize="22" HorizontalAlignment="Right" 
                            VerticalAlignment="Center" Grid.Column="1" Grid.Row="0" />
                            <TextBlock Name="costSalad1" Text="70" FontSize="22" HorizontalAlignment="Right" 
                            VerticalAlignment="Center" Grid.Column="2" Grid.Row="0" />
                            <TextBlock Text=" р." FontSize="22" HorizontalAlignment="Left" 
                            VerticalAlignment="Center" Grid.Column="3" Grid.Row="0" />
    
                            <CheckBox Name="checkSalad2" Content="Крабовый" FontSize="26" VerticalAlignment="Center" 
                            Grid.Column="0" Grid.Row="1" Click="checkSalad2_Click" />
                            <TextBlock Text="100 г" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center"
                             Grid.Column="1" Grid.Row="1" />
                            <TextBlock Name="costSalad2" Text="40" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" 
                            Grid.Column="2" Grid.Row="1" />
                            <TextBlock Text=" р." FontSize="22" HorizontalAlignment="Left" VerticalAlignment="Center" 
                            Grid.Column="3" Grid.Row="1" />
    
                            <CheckBox Name="checkSalad3" Content="Оливье" FontSize="26" VerticalAlignment="Center" 
                            Grid.Column="0" Grid.Row="2" Click="checkSalad3_Click"  />
                            <TextBlock Text="100 г" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" 
                            Grid.Column="1" Grid.Row="2" />
                            <TextBlock Name="costSalad3" Text="45" FontSize="22" HorizontalAlignment="Right" 
                            VerticalAlignment="Center" Grid.Column="2" Grid.Row="2" />
                            <TextBlock Text=" р." FontSize="22" HorizontalAlignment="Left" VerticalAlignment="Center"
                             Grid.Column="3" Grid.Row="2" />
                        </Grid>
                    </controls:PanoramaItem>
    

    Аналогичным образом реализуем разделы меню "первое", "второе" и "напитки":

    <controls:PanoramaItem Header="первое">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="70" />
                                <RowDefinition Height="70" />
                                <RowDefinition Height="70" />
                            </Grid.RowDefinitions>
    
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="230" />
                                <ColumnDefinition Width="70" />
                                <ColumnDefinition Width="60" />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>
    
                            <CheckBox Name="checkSup1" Content="Борщ" FontSize="26" VerticalAlignment="Center" Grid.Column="0" 
                            Grid.Row="0" Click="checkSup1_Click" />
                            <TextBlock Text="200 г" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" Grid.Column="1"
                             Grid.Row="0" />
                            <TextBlock Name="costSup1" Text="50" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" 
                            Grid.Column="2" Grid.Row="0" />
                            <TextBlock Text=" р." FontSize="22" HorizontalAlignment="Left" VerticalAlignment="Center" Grid.Column="3" 
                            Grid.Row="0" />
    
                            <CheckBox Name="checkSup2" Content="Грибной" FontSize="26" VerticalAlignment="Center" Grid.Column="0" 
                            Grid.Row="1" Click="checkSup2_Click" />
                            <TextBlock Text="200 г" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" Grid.Column="1"
                             Grid.Row="1" />
                            <TextBlock Name="costSup2" Text="60" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" 
                            Grid.Column="2" Grid.Row="1" />
                            <TextBlock Text=" р." FontSize="22" HorizontalAlignment="Left" VerticalAlignment="Center" Grid.Column="3" 
                            Grid.Row="1" />
    
                            <CheckBox Name="checkSup3" Content="Солянка" FontSize="26" VerticalAlignment="Center" Grid.Column="0" 
                            Grid.Row="2" Click="checkSup3_Click"  />
                            <TextBlock Text="200 г" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" Grid.Column="1" 
                            Grid.Row="2" />
                            <TextBlock Name="costSup3" Text="55" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" 
                            Grid.Column="2" Grid.Row="2" />
                            <TextBlock Text=" р." FontSize="22" HorizontalAlignment="Left" VerticalAlignment="Center" Grid.Column="3" 
                            Grid.Row="2" />
                        </Grid>
                    </controls:PanoramaItem>
    
                    <controls:PanoramaItem Header="второе">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="70" />
                                <RowDefinition Height="70" />
                                <RowDefinition Height="70" />
                            </Grid.RowDefinitions>
    
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="230" />
                                <ColumnDefinition Width="70" />
                                <ColumnDefinition Width="60" />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>
    
                            <CheckBox Name="checkSec1" Content="Котлеты" FontSize="26" VerticalAlignment="Center" 
                            Grid.Column="0"  Grid.Row="0" Click="checkSec1_Click" />
                            <TextBlock Text="200 г" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" 
                            Grid.Column="1"  Grid.Row="0" />
                            <TextBlock Name="costSec1" Text="60" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" 
                            Grid.Column="2" Grid.Row="0" />
                            <TextBlock Text=" р." FontSize="22" HorizontalAlignment="Left" VerticalAlignment="Center" Grid.Column="3"
                             Grid.Row="0" />
    
                            <CheckBox Name="checkSec2" Content="Отбивная" FontSize="26" VerticalAlignment="Center" Grid.Column="0" 
                            Grid.Row="1" Click="checkSec2_Click" />
                            <TextBlock Text="200 г" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" Grid.Column="1"
                             Grid.Row="1" />
                            <TextBlock Name="costSec2" Text="100" FontSize="22" HorizontalAlignment="Right" 
                            VerticalAlignment="Center" Grid.Column="2" Grid.Row="1" />
                            <TextBlock Text=" р." FontSize="22" HorizontalAlignment="Left" VerticalAlignment="Center"
                             Grid.Column="3" Grid.Row="1" />
    
                            <CheckBox Name="checkSec3" Content="Плов" FontSize="26" VerticalAlignment="Center" 
                            Grid.Column="0" 
                            Grid.Row="2" Click="checkSec3_Click" />
                            <TextBlock Text="200 г" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" Grid.Column="1" 
                            Grid.Row="2" />
                            <TextBlock Name="costSec3" Text="80" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" 
                            Grid.Column="2" Grid.Row="2" />
                            <TextBlock Text=" р." FontSize="22" HorizontalAlignment="Left" VerticalAlignment="Center" Grid.Column="3" 
                            Grid.Row="2" /> </Grid>
                    </controls:PanoramaItem>
    
                    <controls:PanoramaItem Header="напитки">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="70" />
                                <RowDefinition Height="70" />
                                <RowDefinition Height="70" />
                            </Grid.RowDefinitions>
    
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="230" />
                                <ColumnDefinition Width="70" />
                                <ColumnDefinition Width="60" />
                                <ColumnDefinition />
                            </Grid.ColumnDefinitions>
    
                            <CheckBox Name="checkDrnk1" Content="Компот" FontSize="26" VerticalAlignment="Center" 
                            Grid.Column="0" Grid.Row="0" Click="checkDrnk1_Click" />
                            <TextBlock Text="0,2 л" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" 
                            Grid.Column="1" Grid.Row="0" />
                            <TextBlock Name="costDrnk1" Text="15" FontSize="22" HorizontalAlignment="Right" 
                            VerticalAlignment="Center" Grid.Column="2" Grid.Row="0" />
                            <TextBlock Text=" р." FontSize="22" HorizontalAlignment="Left" VerticalAlignment="Center" 
                            Grid.Column="3" Grid.Row="0" />
    
                            <CheckBox Name="checkDrnk2" Content="Сок" FontSize="26" VerticalAlignment="Center" 
                            Grid.Column="0" Grid.Row="1" Click="checkDrnk2_Click" />
                            <TextBlock Text="0,2 л" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" 
                            Grid.Column="1" Grid.Row="1" />
                            <TextBlock Name="costDrnk2" Text="20" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" 
                            Grid.Column="2" Grid.Row="1" />
                            <TextBlock Text=" р." FontSize="22" HorizontalAlignment="Left" VerticalAlignment="Center" 
                            Grid.Column="3" Grid.Row="1" />
    
                            <CheckBox Name="checkDrnk3" Content="Чай" FontSize="26" VerticalAlignment="Center" 
                            Grid.Column="0" Grid.Row="2" Click="checkDrnk3_Click" />
                            <TextBlock Text="0,2 л" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" 
                            Grid.Column="1" Grid.Row="2" />
                            <TextBlock Name="costDrnk3" Text="15" FontSize="22" HorizontalAlignment="Right" VerticalAlignment="Center" 
                            Grid.Column="2" Grid.Row="2" />
                            <TextBlock Text=" р." FontSize="22" HorizontalAlignment="Left" VerticalAlignment="Center" 
                            Grid.Column="3" Grid.Row="2" />
                        </Grid>
                    </controls:PanoramaItem>
    

    В раздел ввода скидки добавим элемент TextBlock, текстовое поле для ввода номера дисконтной карты и две кнопки: "Применить скидку" и "Сбросить". Поскольку в текстовое поле требуется вводить только цифры, определим контекст ввода. Для этого атрибуту InputScope элемента TextBox присвоим значение Number. Таким образом, при нажатии на TextBox клавиатура телефона будет принимать следующий вид Рис. 2.4 :

    (рис 2.4) Клавиатура для ввода номера карты
    <controls:PanoramaItem Header="скидка">
                        <StackPanel>
                            <TextBlock Text="Введите номер карты:" FontSize="26" />
                            <TextBox Name="txtDiscount" Text="" InputScope="Number" />
    
                            <Button Name="btnDiscount" Content="Применить скидку" Click="btnDiscount_Click" />
                            <Button Name="btnDiscNull" Content="Сбросить" Click="btnDiscNull_Click" />
                        </StackPanel>
                    </controls:PanoramaItem>
    

    Перейдем к написанию логики приложения. Откроем файл MainPage.xaml.cs.

    В класс MainPage добавим константу, определяющую размер возможной скидки, и две переменные: одна для хранения суммы счета, другая для определения, активирован ли код скидки.

    private const float DISCOUNT = 0.10f; //размер скидки
    
            private float m_nSumma;
            private bool m_IsDiscount;
    

    Для хранения списка существующих скидочных кодов создадим еще одну переменную – список значений типа int. И для сопровождения списка создадим функцию проверки правильности кода:

    private List<int> Codes;
    
            private bool IsCodeAgree(int code)
            {
                bool bRes = false;
    
                for (int i = 0; i < Codes.Count; i++)
                {
                    if (Codes[i] == code)
                    {
                        bRes = true;
                        break;
                    }
                }
    
                return bRes;
            }
    

    В конструкторе класса MainPage будем инициализировать эти переменные. Также создадим несколько скидочный кодов по-умолчанию:

            // Constructor
            public MainPage()
            {
                InitializeComponent();
    
                Codes = new List<int>();
    
                Codes.Add(1111111111);
                Codes.Add(1234567890);
                Codes.Add(0101010101);
    
                m_nSumma = 0;
                m_IsDiscount = false;
            }
    

    В обработчиках нажатия на CheckBox будем менять сумму счета и обновлять ее в поле TextBlock. Также в функции RefreshSum() будем вычислять скидку и выводить итоговое значение счета внизу главной страницы приложения:

            private void RefreshSum()
            {
                lblSum.Text = "Сумма: " + m_nSumma.ToString() + " р.";
    
                if (m_IsDiscount)
                {
                    lblDsc.Text = "Скидка " + (m_nSumma * DISCOUNT).ToString() + " р. (" + ((int)(DISCOUNT * 100)).ToString() + "%)";
                    lblAll.Text = "Итого: " + (m_nSumma * (1f - DISCOUNT)).ToString() + " р.";
                }
                else
                {
                    lblDsc.Text = "Скидки нет";
                    lblAll.Text = "Итого: " + m_nSumma.ToString() + " р.";
                }
            }
    
            private void checkSalad1_Click(object sender, RoutedEventArgs e)
            {
                int cost = int.Parse(costSalad1.Text);
                m_nSumma += checkSalad1.IsChecked.Value ? cost : -cost;
                RefreshSum();
            }
    
            private void checkSalad2_Click(object sender, RoutedEventArgs e)
            {
                int cost = int.Parse(costSalad2.Text);
                m_nSumma += checkSalad2.IsChecked.Value ? cost : -cost;
                RefreshSum();
            }
    
            private void checkSalad3_Click(object sender, RoutedEventArgs e)
            {
                int cost = int.Parse(costSalad3.Text);
                m_nSumma += checkSalad3.IsChecked.Value ? cost : -cost;
                RefreshSum();
            }
    
            private void checkSup1_Click(object sender, RoutedEventArgs e)
            {
                int cost = int.Parse(costSup1.Text);
                m_nSumma += checkSup1.IsChecked.Value ? cost : -cost;
                RefreshSum();
            }
    
            private void checkSup2_Click(object sender, RoutedEventArgs e)
            {
                int cost = int.Parse(costSup2.Text);
                m_nSumma += checkSup2.IsChecked.Value ? cost : -cost;
                RefreshSum();
            }
    
            private void checkSup3_Click(object sender, RoutedEventArgs e)
            {
                int cost = int.Parse(costSup3.Text);
                m_nSumma += checkSup3.IsChecked.Value ? cost : -cost;
                RefreshSum();
            }
    
            private void checkSec1_Click(object sender, RoutedEventArgs e)
            {
                int cost = int.Parse(costSec1.Text);
                m_nSumma += checkSec1.IsChecked.Value ? cost : -cost;
                RefreshSum();
            }
    
            private void checkSec2_Click(object sender, RoutedEventArgs e)
            {
                int cost = int.Parse(costSec2.Text);
                m_nSumma += checkSec2.IsChecked.Value ? cost : -cost;
                RefreshSum();
            }
    
            private void checkSec3_Click(object sender, RoutedEventArgs e)
            {
                int cost = int.Parse(costSec3.Text);
                m_nSumma += checkSec3.IsChecked.Value ? cost : -cost;
                RefreshSum();
            }
    
            private void checkDrnk1_Click(object sender, RoutedEventArgs e)
            {
                int cost = int.Parse(costDrnk1.Text);
                m_nSumma += checkDrnk1.IsChecked.Value ? cost : -cost;
                RefreshSum();
            }
    
            private void checkDrnk2_Click(object sender, RoutedEventArgs e)
            {
                int cost = int.Parse(costDrnk2.Text);
                m_nSumma += checkDrnk2.IsChecked.Value ? cost : -cost;
                RefreshSum();
            }
    
            private void checkDrnk3_Click(object sender, RoutedEventArgs e)
            {
                int cost = int.Parse(costDrnk3.Text);
                m_nSumma += checkDrnk3.IsChecked.Value ? cost : -cost;
                RefreshSum();
            }
    

    При нажатии на кнопку "Применить скидку" будем проверять код дисконтной карты, а при нажатии на кнопку "Сбросить" выключать подсчет скидки:

           private void btnDiscount_Click(object sender, RoutedEventArgs e)
            {
                int code = 0;
    
                if (int.TryParse(txtDiscount.Text, out code))
                {
                    if (IsCodeAgree(code))
                    {
                        m_IsDiscount = true;
                        RefreshSum();
                    }
                    else
                    {
                        MessageBox.Show("Неверный код.");
                    }
                }
                else
                {
                    MessageBox.Show("Неверный код.");
                }
            }
    
            private void btnDiscNull_Click(object sender, RoutedEventArgs e)
            {
                txtDiscount.Text = "";
                m_IsDiscount = false;
                RefreshSum();
            }
    

    Теперь можно скомпилировать приложение, запустить на эмуляторе или телефоне и проверить его функциональность.

    Лабораторная работа №4. Калькулятор

    Задание

    Создать приложение "Калькулятор" для Windows Phone 7 с тремя возможными режимами: обычным, инженерным и режимом для программистов (перевод из одной системы счисления в другую).

    Освоение

  • навигация между страницами
  • основные элементы управления и разметки (Grid, StackPanel, TextBox, TextBlock, Button, RadioButton)
  • события
  • контекст ввода
  • меню приложения
  • Описание

    Создадим новый проект Silverlight for Windows Phone – Windows Phone Application.

    Приложение будет состоять из трех окон:

  • обычный режим
  • инженерный
  • режим для программистов
  • Для начала откроем файл разметки главной страницы MainPage.xaml. В самом верху страницы разметки изменим выводимое название приложения, например, на "КАЛЬКУЛЯТОР (обычный)". Заголовок страницы удалим или закомментируем с целью экономии места:

          <!--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="page name" Margin="9,-7,0,0" 
                Style="{StaticResource PhoneTextTitle1Style}"/-->
            </StackPanel>
    

    Разместим на данной страницы кнопки для основных математических операций. Для этого в разделе ContentPanel дополним таблицу Grid. Пусть в ней будет 4 колонки (для кнопок) и 3 строки (для текстового поля и двух рядок кнопок). Определим это в специальных тегах Grid.RowDefinitions и Grid.ColumnDefinitions:

          <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <Grid.RowDefinitions>
                    <RowDefinition Height="120" />
                    <RowDefinition Height="90" />
                    <RowDefinition Height="90" />
                </Grid.RowDefinitions>
    
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition />
                    <ColumnDefinition />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
    
    		…
    
            </Grid>
    

    Для позиционирования элементов управления внутри таблицы используются атрибуты Grid.Row и Grid.Column. Они хранят индексы строки и столбца родительской таблицы.

    Элементы управления будем описывать на месте многоточия. Сначала опишем блок элементов для ввода/вывода значений: два TextBlock для введенного аргумента и операции и TextBox для ввода. Выравнивание в этих элементах (атрибут TextAlignment) будет по правому краю. Также определим отступы с помощью атрибута Margin. Для текстового поля определим контекст ввода – какого типа данные можно вводить. Установим атрибут InputScope="Number". При этом при активации данного текстового поля клавиатура будет принимать следующий вид Рис. 2.5 :

    (рис 2.5) Клавиатура для ввода значений

    Также определим обработчики событий для текстового поля – изменение текста и изменения выделения. Это необходимо для того, чтобы предотвратить ввод неверных данных. Описание действий данных обработчиков будет описано ниже.

    Также добавим кнопки для операций "+", "-", "*", "/", смена знака на противоположный, остаток от деления, сброс и равно. Добавим обработчики нажатий на данные кнопки.

          <StackPanel Grid.ColumnSpan="4" Grid.Row="0" Grid.Column="0">
                    <TextBlock Name="lblArg1" Text="" TextAlignment="Right" Height="30" Margin="15,0,15,0" />
                    <TextBlock Name="lblArgOp" Text="" TextAlignment="Right" Height="30" Margin="15,0,15,0" />
                    <TextBox Name="txtEnter" Text="" TextAlignment="Right" VerticalAlignment="Bottom" InputScope="Number" 
                    Height="70" TextChanged="txtEnter_TextChanged" SelectionChanged="txtEnter_SelectionChanged" />
                </StackPanel>
    
                <Button Content="+" Height="100" Width="100" Grid.Row="1" 
                Grid.Column="0" Click="btnAdd_Click" />
                <Button Content="-" Height="100" Width="100" Grid.Row="1" 
                Grid.Column="1" Click="btnSub_Click" />
                <Button Content="*" Height="100" Width="100" Grid.Row="1" 
                Grid.Column="2" Click="btnMul_Click" />
                <Button Content="/" Height="100" Width="100" Grid.Row="1" 
                Grid.Column="3" Click="btnDiv_Click" />
    
                <Button Content="±" Height="100" Width="100" Grid.Row="2" 
                Grid.Column="0" Click="btnInv_Click" />
                <Button Content="%" Height="100" Width="100" Grid.Row="2" 
                Grid.Column="1" Click="btnMod_Click" />
                <Button Content="C" Height="100" Width="100" Grid.Row="2" 
                Grid.Column="2" Click="btnRes_Click" />
                <Button Content="=" Height="100" Width="100" Grid.Row="2" 
                Grid.Column="3" Click="btnEnter_Click" />
    

    Для перехода к другим режимам калькулятора добавим кнопки в меню приложения. Для этого раскомментируем код внизу страницы разметки и немного его изменим, добавим обработчики нажатий на кнопки:

      <!--Sample code showing usage of ApplicationBar-->
        <phone:PhoneApplicationPage.ApplicationBar>
            <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" 
                Text="Инженерный" Click="Menu1_Click" />
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" 
                Text="Программист" Click="Menu2_Click" />
                
                <!--shell:ApplicationBar.MenuItems>
                    <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                    <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
                </shell:ApplicationBar.MenuItems-->
            </shell:ApplicationBar>
        </phone:PhoneApplicationPage.ApplicationBar>
     

    Перейдем к написанию кода для данной страницы.

    Для начала в классе напишем перечисление для существующих операций и определим две переменные для хранения уже введенного первого операнда и операции:

    enum Operation
      {
       ADD,
       SUP,
       MUL,
       DIV,
       MOD
      }
    
        private double arg1;
        private Operation oper;
    

    В конструкторе проинициализируем первый операнд нулем:

           // Constructor
            public MainPage()
            {
                InitializeComponent();
    
                arg1 = 0d;
            }
    

    Напишем функцию, которая будет считать результат. В случае деления она также будет проверять второй операнд на неравенство 0.

       private double Count(double arg2)
            {
                double result = 0d;
    
                switch (oper)
                {
                    case Operation.ADD:
                        result = arg1 + arg2;
                        break;
                    case Operation.SUP:
                        result = arg1 - arg2;
                        break;
                    case Operation.MUL:
                        result = arg1 * arg2;
                        break;
                    case Operation.DIV:
                        if (arg2 != 0)
                        {
                            result = arg1 / arg2;
                        }
                        else
                        {
                            MessageBox.Show("Делить на ноль нельзя.");
                            result = double.MaxValue;
                        }
                        break;
                    case Operation.MOD:
                        result = arg1 % arg2;
                        break;
                    default:
                        break;
                }
    
                return result;
            }
    

    Напишем обработчики нажатий на кнопки. Одинаковый функционал вынесем в отдельную функцию Operation_Click().

           private void Operation_Click()
            {
                //если мы вводим первый аргумент
                if (0d == arg1)
                {
                    lblArg1.Text = txtEnter.Text;
                    txtEnter.Text = "";
    
                    arg1 = double.Parse(lblArg1.Text);
                }
                else
                {
                    //если первый аргумент уже есть
    
                    if (txtEnter.Text.Length > 0)
                    {
                        double arg2 = double.Parse(txtEnter.Text);
    
                        if ((Operation.DIV == oper)  (0 == arg2))
                        {
                            MessageBox.Show("Делить на ноль нельзя.");
                            txtEnter.Text = "";
                        }
                        else
                        {
                            arg1 = Count(arg2);
                            lblArg1.Text = arg1.ToString();
                            txtEnter.Text = "";
                        }
                    }
                }
    
                txtEnter.Focus();
            }
    
            private void btnAdd_Click(object sender, RoutedEventArgs e)
            {
                Operation_Click();
    
                lblArgOp.Text = "+";
                oper = Operation.ADD;
            }
    
            private void btnSub_Click(object sender, RoutedEventArgs e)
            {
                Operation_Click();
    
                lblArgOp.Text = "-";
                oper = Operation.SUP;
            }
    
            private void btnMul_Click(object sender, RoutedEventArgs e)
            {
                Operation_Click();
    
                lblArgOp.Text = "*";
                oper = Operation.MUL;
            }
    
            private void btnDiv_Click(object sender, RoutedEventArgs e)
            {
                Operation_Click();
    
                lblArgOp.Text = "/";
                oper = Operation.DIV;
            }
    
            private void btnInv_Click(object sender, RoutedEventArgs e)
            {
                if (txtEnter.Text.Length > 0)
                {
                    txtEnter.Text = (- double.Parse(txtEnter.Text)).ToString();
                }
                txtEnter.Focus();
            }
    
            private void btnMod_Click(object sender, RoutedEventArgs e)
            {
                Operation_Click();
    
                lblArgOp.Text = "%";
                oper = Operation.MOD;
            }
    
            private void btnRes_Click(object sender, RoutedEventArgs e)
            {
                arg1 = 0d;
                lblArg1.Text = "";
                lblArgOp.Text = "";
                txtEnter.Text = "";
                txtEnter.Focus();
            }
    
            private void btnEnter_Click(object sender, RoutedEventArgs e)
            {
                if ((lblArg1.Text.Length > 0)  (lblArgOp.Text.Length > 0)  (txtEnter.Text.Length > 0))
                {
                    double arg2 = double.Parse(txtEnter.Text);
    
                    if ((Operation.DIV == oper)  (0 == arg2))
                    {
                        MessageBox.Show("Делить на ноль нельзя.");
                        txtEnter.Text = "";
                    }
                    else
                    {
                        arg1 = Count(arg2);
                        lblArg1.Text = arg1.ToString();
                        lblArgOp.Text = "";
                        txtEnter.Text = "";
                    }
                }
    
                txtEnter.Focus();
            }
    

    Напишем обработчики событий для текстового поля. Функция txtEnter_TextChanged() будет ограничивать введенные данные 16 символами. Функция txtEnter_SelectionChanged() будет устанавливать курсор в конец текстового поля.

          private void txtEnter_TextChanged(object sender, TextChangedEventArgs e)
            {
                if (txtEnter.Text.Length > 16)
                {
                    txtEnter.Text = txtEnter.Text.Substring(0, 16);
    
                    //установить кусор в конец
                    txtEnter.Select(16, 0);
                }
            }
    
            private void txtEnter_SelectionChanged(object sender, RoutedEventArgs e)
            {
                //если курсор стоит не в самом конце - поставить его туда
                if (txtEnter.SelectionStart != txtEnter.Text.Length)
                    txtEnter.Select(txtEnter.Text.Length, 0);
            }
    

    Для обеспечения перехода между страницами добавим в самый верх директиву:

     using System.Windows.Navigation;     
    

    Теперь определим обработчики нажатия на кнопки меню. В этих случаях мы должны обеспечить переход на другие страницы, при этом передать значение из текстового поля. Передача значений осуществляется по аналогии с GET-запросом из web-программирования (после адреса перехода ставится знак "?" и пишутся пары ключ-значение, разделенные символом ""):

          private void Menu1_Click(object sender, EventArgs e)
            {
                NavigationService.Navigate(new Uri("/PageEngineer.xaml?data=" +
                        Uri.EscapeDataString(txtEnter.Text),
                        UriKind.Relative));
            }
    
            private void Menu2_Click(object sender, EventArgs e)
            {
                NavigationService.Navigate(new Uri("/PageProgrammer.xaml?data=" +
                        Uri.EscapeDataString(txtEnter.Text),
                        UriKind.Relative));
            }
    

    Для приема данных от других страниц переопределим метод OnNavigatedTo(). Просто смотрим, есть ли в запросе ключ data и, если есть, берем его значение:

        protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                if (NavigationContext.QueryString.ContainsKey("data"))
                {
                    txtEnter.Text = NavigationContext.QueryString["data"].ToString();
                    txtEnter.Focus();
                }
            }
    

    Добавим в проект еще 2 страницы: PageEngineer.xaml и PageProgrammer.xaml. Разметка в них будет выглядеть аналогичным образом. Разве что, на странице PageProgrammer.xaml вместо кнопок поместим RadioButton для систем счисления dec, bin и hex.

    PageEngineer.xaml

        <!--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="page name" 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="120" />
                    <RowDefinition Height="90" />
                    <RowDefinition Height="90" />
                </Grid.RowDefinitions>
    
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition />
                    <ColumnDefinition />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
    
                <StackPanel Grid.ColumnSpan="4" Grid.Row="0" Grid.Column="0">
                    <TextBlock Name="lblArg1" Text="" TextAlignment="Right"
                     Height="30" Margin="15,0,15,0" />
                    <TextBlock Name="lblArgOp" Text="" TextAlignment="Right" 
                    Height="30" Margin="15,0,15,0" />
                    <TextBox Name="txtEnter" Text="" TextAlignment="Right" 
                    VerticalAlignment="Bottom" InputScope="Number" 
                    Height="70" TextChanged="txtEnter_TextChanged" 
                    SelectionChanged="txtEnter_SelectionChanged" />
                </StackPanel>
    
                <Button Content="^" Height="100" Width="100" Grid.Row="1" 
                Grid.Column="0" Click="btnDegree_Click" />
                <Button Content="v" Height="100" Width="100" Grid.Row="1" 
                Grid.Column="1" Click="btnRoot_Click" />
                <Button Content="ln" Height="100" Width="100" Grid.Row="1" 
                Grid.Column="2" Click="btnLn_Click" />
                <Button Content="log" Height="100" Width="100" Grid.Row="1" 
                Grid.Column="3" Click="btnLog_Click" />
    
                <Button Content="sin" Height="100" Width="100" Grid.Row="2" 
                Grid.Column="0" Click="btnSin_Click" />
                <Button Content="cos" Height="100" Width="100" Grid.Row="2"
                 Grid.Column="1" Click="btnCos_Click" />
                <Button Content="C" Height="100" Width="100" Grid.Row="2" 
                Grid.Column="2" Click="btnRes_Click" />
                <Button Content="=" Height="100" Width="100" Grid.Row="2" 
                Grid.Column="3" Click="btnEnter_Click" />
            </Grid>
        </Grid>
    
        <!--Sample code showing usage of ApplicationBar-->
        <phone:PhoneApplicationPage.ApplicationBar>
            <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" 
                Text="Обычный" Click="Menu1_Click" />
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" 
                Text="Программист" Click="Menu2_Click" />
    
                <!--shell:ApplicationBar.MenuItems>
                    <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                    <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
                </shell:ApplicationBar.MenuItems-->
            </shell:ApplicationBar>
        </phone:PhoneApplicationPage.ApplicationBar>
    

    PageProgrammer.xaml

        <!--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="page name" 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="80" />
                    <RowDefinition Height="70" />
                    <RowDefinition Height="70" />
                </Grid.RowDefinitions>
    
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
    
                <!--StackPanel>
                    <TextBlock Name="lblArg1" Text="" TextAlignment="Right" 
                    Height="30" Margin="15,0,15,0" />
                    <TextBlock Name="lblArgOp" Text="" TextAlignment="Right" 
                    Height="30" Margin="15,0,15,0" />
                    <TextBox Name="txtEnter" Text="" TextAlignment="Right" 
                    VerticalAlignment="Bottom" InputScope="Number" 
                    Height="70" TextChanged="txtEnter_TextChanged" 
                    SelectionChanged="txtEnter_SelectionChanged" />
                </StackPanel-->
    
                <TextBox Name="txtEnter" Text="" Grid.ColumnSpan="2" Grid.Row="0" Grid.Column="0" TextAlignment="Right" 
                VerticalAlignment="Bottom" InputScope="Number" Height="70" 
                TextChanged="txtEnter_TextChanged" SelectionChanged="txtEnter_SelectionChanged" />
    
                <RadioButton Name="radioDec"  GroupName="a1" HorizontalAlignment="Center" Content="Dec" Grid.Row="1"
                 Grid.Column="0" IsChecked="True" Checked="radioDec_Checked" />
                <RadioButton Name="radioBin" GroupName="a1" HorizontalAlignment="Center" Content="Bin" Grid.Row="2" 
                Grid.Column="0" Checked="radioBin_Checked" />
                <RadioButton Name="radioHex" GroupName="a1" HorizontalAlignment="Center" Content="Hex" Grid.Row="1" 
                Grid.Column="1" FlowDirection="RightToLeft" Checked="radioHex_Checked" />
                <Button Content="C" Height="70" Width="150" Grid.Row="2" Grid.Column="2" Click="btnRes_Click" />
            </Grid>
        </Grid>
    
        <!--Sample code showing usage of ApplicationBar-->
        <phone:PhoneApplicationPage.ApplicationBar>
            <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png"
                Text="Обычный" Click="Menu1_Click" />
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" 
                Text="Инженерный" Click="Menu2_Click" />
    
                <!--shell:ApplicationBar.MenuItems>
                    <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                    <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
                </shell:ApplicationBar.MenuItems-->
            </shell:ApplicationBar>
        </phone:PhoneApplicationPage.ApplicationBar>
    

    Теперь можно скомпилировать приложение, запустить на эмуляторе или телефоне и проверить его функциональность.

    Лабораторная работа №5. База паролей

    Задание

    Создать приложение "База паролей" для Windows Phone 7, которое позволяло бы хранить пароли для различных ресурсов и дополнять базу новыми паролями.

    Освоение

  • навигация между страницами
  • основные элементы управления и разметки (Grid, StackPanel, Canvas, TextBox, TextBlock, PasswordBox, ListBox, Button, Border)
  • события
  • меню приложения
  • Описание

    Создадим новый проект Silverlight for Windows Phone – Windows Phone Application.

    Приложение будет состоять из двух окон:

  • главное окно со списком ресурсов
  • окно создания нового ресурса (с паролем)
  • Откроем файл разметки главной страницы MainPage.xaml. В самом верху страницы разметки изменим выводимое название приложения, например, на "БАЗА ПАРОЛЕЙ". Заголовок страницы удалим или закомментируем с целью экономии места:

        <!--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="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/-->
            </StackPanel>
    

    Внутри элемента ContentPanel поместим список ресурсов. При выделении ресурса и нажатии на кнопку меню будем запрашивать код подтверждения пользователя (с целью дополнительной защиты данных), после чего будем выводить пароль.

    Для запроса код подтверждения пользователя добавим на страницу разметки специальные поля, которые будем отображать (свойство Visibility устанавливать в "Visible") при нажатии на кнопку меню и скрывать в противном случае (свойство Visibility устанавливать в "Collapsed"). Таким образом, создадим подобие MessageBox-а. Аналогичным образом будем выводить пароль для указанного ресурса.

    Итак, код ContentPanel станицы MainPage.xaml будем выглядеть примерно так:

        <!--ContentPanel - place additional content here-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" Canvas.ZIndex="0">
                <Canvas>
                    <ListBox Name="lstSources" Canvas.Left="0" Canvas.Top="0" SelectionChanged="lstSources_SelectionChanged">
                        <ListBoxItem>
                            <TextBlock Text="Элемент списка" FontSize="28" Margin="0,10,0,10" Width="450" />
                        </ListBoxItem>
                    </ListBox>
    
                    <Border Name="msgCode" Visibility="Collapsed" BorderThickness="4" BorderBrush="White"  
                    Canvas.Left="0" Canvas.Top="75" Canvas.ZIndex="2">
                        <StackPanel Width="442" Background="Black">
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="Введите код подтверждения:" FontSize="26" Width="372" Margin="10,10,10,10" />
                                <TextBlock Text="X" TextAlignment="Right" FontSize="26" Width="30" 
                                Margin="10,10,10,10" MouseEnter="lblCodeX_MouseEnter" />
                            </StackPanel>
                            <!--TextBox Name="txtPassword" Text="" InputScope="Password" /-->
                            <PasswordBox Name="pwdCodeBox" Password="" />
                            <!--StackPanel Orientation="Horizontal"-->
                                <Button Name="btnCodeApply" Content="Принять" Margin="0,0,5,0" Click="btnCodeApply_Click" />
                                <!--Button Name="btnCodeCancel" Content="Отмена" Width="220" Margin="5,0,0,0" />
                            </StackPanel-->
                        </StackPanel>
                    </Border>
    
                    <Border Name="msgPass" Visibility="Collapsed" BorderThickness="4" BorderBrush="White" 
                    Canvas.Left="0" Canvas.Top="75" Canvas.ZIndex="1">
                        <StackPanel Width="442" Background="Black">
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="Пароль:" FontSize="26" Width="372" Margin="10,10,10,10" />
                                <TextBlock Text="X" TextAlignment="Right" FontSize="26" Width="30" Margin="10,10,10,10" 
                                MouseEnter="lblPassX_MouseEnter" />
                            </StackPanel>
                            <TextBox Name="txtPass" IsReadOnly="True" />
                            <Button Name="btnPassShow" Content="Показать" Click="btnPassShow_Click" />
                        </StackPanel>
                    </Border>
                </Canvas>
            </Grid>
    

    В конце страницы раскомментируем фрагмент кода, отвечающий за меню приложения. Добавим еще одну кнопку. Объявим обработчики нажатия на кнопки меню и добавим значки. Значки можно найти в папке C:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.0\Icons (лучше всего брать из папки dark) или нарисовать самостоятельно. Добавим в проект папку "Images" и поместим в нее необходимые изображения. Для каждого из изображений в свойствах назначим полю Build Action значение Content (если этого не сделать, ApplicationBar не сможет найти изображения).

       <!--Sample code showing usage of ApplicationBar-->
        <phone:PhoneApplicationPage.ApplicationBar>
            <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
                <shell:ApplicationBarIconButton IconUri="Images/appbar.feature.search.rest.png" Text="Просмотр" 
                Click="ApplicationBarMenuShow_Click" />
                <shell:ApplicationBarIconButton IconUri="Images/appbar.add.rest.png" Text="Добавить" 
                Click="ApplicationBarMenuAdd_Click" />
                <shell:ApplicationBarIconButton IconUri="Images/appbar.cancel.rest.png" Text="Удалить"
                Click="ApplicationBarMenuRemove_Click" />
                
                <!--shell:ApplicationBar.MenuItems>
                    <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                    <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
                </shell:ApplicationBar.MenuItems-->
            </shell:ApplicationBar>
        </phone:PhoneApplicationPage.ApplicationBar>
    

    Перейдем к написанию кода. Откроем файл MainPage.xaml.cs. В самый верх для обеспечения перехода между страницами добавим директиву:

      using System.Windows.Navigation; 
    

    В класс MainPage добавим константу и 2 переменные:

         private const string m_Code = "qwe";
            private bool m_bHidePass = true;
            private string m_strSelected = "";
    

    Константа будет определять код подтверждения пользователя для просмотра паролей. Таким образом просмотр паролей будет доступен только если верно ввести код "qwe". Переменные пригодятся при выполнении кода приложения.

    Поскольку работать с локальной базой и файлами мы пока не умеем, для сохранения данных будем использовать статический класс MyDatabase. Создадим его. Он будет содержать список элементов типа MyElement, который нам также необходимо создать:

         public struct MyElement
        {
            public string Source;
            public string Password;
        }
    

    Кроме того статический класс будет содержать функции инициализации списка (несколько ресурсов зададим заранее в этой функции), вывода пароля для заданного ресурса и сокрытие пароля (осуществляет замену символов на "*" для дополнительной защиты):

         public static class MyDatabase
        {
            public static List<MyElement>
     Values;
    
            public static void Init()
            {
                Values = new List<MyElement>
    ();
    
                MyElement tmp;
                tmp.Source = "компьютер";
                tmp.Password = "4";
    
                Values.Add(tmp);
    
                tmp.Source = "почта";
                tmp.Password = "qwerty";
    
                Values.Add(tmp);
    
                tmp.Source = "аська";
                tmp.Password = "12345";
    
                Values.Add(tmp);
            }
    
            public static string GetPassword(string src)
            {
                string strRes = "";
    
                for (int i = 0; i < Values.Count; i++)
                {
                    if (Values[i].Source.Equals(src))
                    {
                        strRes = Values[i].Password;
                        break;
                    }
                }
    
                return strRes;
            }
    
            public static string HidePassword(string pwd)
            {
                string strRes = "";
    
                for (int i = 0; i < pwd.Length; i++)
                {
                    strRes += "*";
                }
    
                return strRes;
            }
        }
    

    Вернемся к коду главной страницы. Напишем обработчики нажатия на крестики у созданных нами окон:

        private void lblCodeX_MouseEnter(object sender, MouseEventArgs e)
            {
                msgCode.Visibility = System.Windows.Visibility.Collapsed;
                pwdCodeBox.Password = "";
                lstSources.IsEnabled = true;
                ApplicationBar.IsVisible = true;
            }
    
            private void lblPassX_MouseEnter(object sender, MouseEventArgs e)
            {
                msgPass.Visibility = System.Windows.Visibility.Collapsed;
                txtPass.Text = "";
                lstSources.IsEnabled = true;
                ApplicationBar.IsVisible = true;
            }
    

    Напишем обработчики нажатия на кнопки у созданных нами окон:

                private void btnPassShow_Click(object sender, RoutedEventArgs e)
            {
                if (m_bHidePass)
                {
                    //показать
                    if (!m_strSelected.Equals(""))
                    {
                        txtPass.Text = MyDatabase.GetPassword(m_strSelected);
                        btnPassShow.Content = "Скрыть";
                    }
                    else
                    {
                        MessageBox.Show("Элемент не выбран.");
                    }
                }
                else
                {
                    //скрыть
                    txtPass.Text = MyDatabase.HidePassword(txtPass.Text);
                    btnPassShow.Content = "Показать";
                }
    
                m_bHidePass = !m_bHidePass;
            }
    
            private void btnCodeApply_Click(object sender, RoutedEventArgs e)
            {
                if (pwdCodeBox.Password.Equals(m_Code))
                {
                    msgCode.Visibility = System.Windows.Visibility.Collapsed;
                    pwdCodeBox.Password = "";
                    msgPass.Visibility = System.Windows.Visibility.Visible;
    
                    txtPass.Text = MyDatabase.HidePassword(MyDatabase.GetPassword(m_strSelected));
                    m_bHidePass = true;
                }
                else
                {
                    MessageBox.Show("Код неверный.");
                    pwdCodeBox.Password = "";
                    pwdCodeBox.Focus();
                }
            }
    

    При выделении какого-нибудь элемента списка будем менять значение переменной m_strSelected :

        private void lstSources_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (-1 != lstSources.SelectedIndex)
                    m_strSelected = ((TextBlock)((ListBoxItem)lstSources.SelectedItem).Content).Text;
            }
    

    Напишем основные функции работы со списком: снятие выделения с элементов и вырисовка (добавление элементов списка из статического класса MyDatabase в список файла разметки ListBox с именем lstSources ).

        private void DeselectList()
            {
                //снять выделение с элементов
                lstSources.SelectedIndex = -1;
                m_strSelected = "";
            }
    
            private void DrawList()
            {
                lstSources.Items.Clear();
    
                for (int i = 0; i < MyDatabase.Values.Count; i++)
                {
                    ListBoxItem lstitNew = new ListBoxItem();
                    TextBlock txtSource = new TextBlock();
    
                    txtSource.Text = MyDatabase.Values[i].Source;
                    txtSource.FontSize = 28;
                    txtSource.Width = 450;
                    txtSource.Margin = new Thickness(0, 10, 0, 10);
    
                    lstitNew.Content = txtSource;
    
                    lstSources.Items.Add(lstitNew);
                }
    
                lstSources.SelectedIndex = lstSources.Items.Count - 1;
            }
    

    Изменим конструктор класса MainPage:

        // Constructor
            public MainPage()
            {
                InitializeComponent();
    
                MyDatabase.Init();
                DrawList();
            }
    

    При нажатии на кнопку меню "Просмотр", если есть выделенный элемент, будем отображать созданное нами окно запроса кода пользователя. При нажатии на кнопку меню "Добавить", будем переходить на страницу PageAdd.xaml, которую создадим чуть позже. При нажатии на кнопку меню "Удалить", если есть выделенный элемент, будем его удалять и перерисовывать список.

        // Меню - Просмотр
            private void ApplicationBarMenuShow_Click(object sender, EventArgs e)
            {
                if (!m_strSelected.Equals(""))
                {
                    lstSources.IsEnabled = false;
                    ApplicationBar.IsVisible = false;
                    msgCode.Visibility = System.Windows.Visibility.Visible;
                    pwdCodeBox.Focus();
                }
                else
                {
                    MessageBox.Show("Элемент не выбран.");
                }
            }
    
            // Меню - Добавить
            private void ApplicationBarMenuAdd_Click(object sender, EventArgs e)
            {
                NavigationService.Navigate(new Uri("/PageAdd.xaml", UriKind.Relative));
            }
    
            // Меню - Удалить
            private void ApplicationBarMenuRemove_Click(object sender, EventArgs e)
            {
                int nIndex = lstSources.SelectedIndex;
    
                if (-1 != nIndex)
                {
                    MyDatabase.Values.RemoveAt(nIndex);
                    DrawList();
                    DeselectList();
                }
                else
                {
                    MessageBox.Show("Элемент не выбран.");
                }
            }
    

    При переходе на текущую страницу будем просто перерисовывать список. Для этого переопределим стандартный метод OnNavigatedTo():

        protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                if (null != MyDatabase.Values)
                {
                    DrawList();
                }
            }
    

    С главной страницей закончено. Теперь добавим в проект приложения новую страницу – Windows Phone Portrait Page. Назовем ее PageAdd. В файле PageAdd.xaml определим разметку страницы. Она будет включать два текстовых поля – для названия ресурса и пароля – и две кнопки – "Принять" и "Отмена". Также не забудем про элементы TextBlock с пояснительными подписями к текстовым полям

        <!--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="page name" 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">
                <StackPanel Margin="5,5,5,5">
                    <Grid ShowGridLines="False" Margin="0,20,0,0">
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>
    
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="120" />
                            <ColumnDefinition Width="320" />
                        </Grid.ColumnDefinitions>
    
                        <TextBlock Text="Источник:" Grid.Column="0" Grid.Row="0" 
                        VerticalAlignment="Center" FontSize="24" />
                        <TextBlock Text="Пароль:" Grid.Column="0" Grid.Row="1" VerticalAlignment="Center" FontSize="24" />
                        <TextBox Name="txtSource" Text="Источник" Grid.Column="1" Grid.Row="0" />
                        <PasswordBox Name="pwdAdd" Password="Пароль" Grid.Column="1" Grid.Row="1" />
                    </Grid>
    
                    <StackPanel Orientation="Horizontal" Margin="0,20,0,0">
                        <Button Name="btnApply" Height="90" Width="220" Grid.Column="0" Grid.Row="0" 
                        Content="Принять" Click="btnApply_Click" />
                        <Button Name="btnCancel" Height="90" Width="220" Grid.Column="1" Grid.Row="0" 
                        Content="Отмена" Click="btnCancel_Click" />
                    </StackPanel>
                </StackPanel>
            </Grid>
    

    В коде страницы PageAdd.xaml.cs определим поведение:

       public partial class PageAdd : PhoneApplicationPage
        {
            public PageAdd()
            {
                InitializeComponent();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
    
                txtSource.Text = "";
                pwdAdd.Password = "";
    
                txtSource.Focus();
            }
    
            private void btnCancel_Click(object sender, RoutedEventArgs e)
            {
                MessageBoxResult result = MessageBox.Show("Изменения будут потеряны. Продолжить?", 
    "Отмена", MessageBoxButton.OKCancel);
                if (result == MessageBoxResult.OK)
                {
                    NavigationService.GoBack();
                }
            }
    
            private void btnApply_Click(object sender, RoutedEventArgs e)
            {
                if (txtSource.Text.Trim().Length > 0)
                {
                    if (pwdAdd.Password.Trim().Length > 0)
                    {
                        MyElement tmp;
                        tmp.Source = txtSource.Text;
                        tmp.Password = pwdAdd.Password;
                        MyDatabase.Values.Add(tmp);
    
                        NavigationService.GoBack();
                    }
                    else
                    {
                        MessageBox.Show("Поле пароля не может быть пустым.");
                        pwdAdd.Focus();
                    }
                }
                else
                {
                    MessageBox.Show("Поле источника не может быть пустым.");
                    txtSource.Focus();
                }
            }
        }
    

    Теперь можно скомпилировать приложение, запустить на эмуляторе или телефоне и проверить его функциональность.

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