Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Osnovy_razrabotki_prilozheny_besprovodnykh_ustr...docx
Скачиваний:
1
Добавлен:
01.04.2025
Размер:
784.07 Кб
Скачать

Лабораторная работа №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.  Клавиатура для ввода значений

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

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

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

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]