Ресурсы и стили
Последнее обновление: 31.10.2015
Ресурсы позволяют определить объекты, которые могут многократно использоваться в приложении в различных его частях. Итак, определим пару ресурсов и используем их:
<Page x:Class="HelloApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:HelloApp" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Page.Resources> <SolidColorBrush x:Key="darkRedBrush" Color="DarkRed" /> <SolidColorBrush x:Key="grayBrush" Color="DarkGray" /> </Page.Resources> <Grid> <Button x:Name="button1" Background="{StaticResource grayBrush}" Foreground="{StaticResource darkRedBrush}" Content="Кнопка" VerticalAlignment="Top" /> </Grid> </Page>
Получится такая кнопка:
Ресурсы определяются в свойстве Resources, которое есть у компонентов визуального интерфейса. В данном случае ресурсы определены
как ресурсы элемента Page внутри тегов <Page.Resources> </Page.Resources>
.
Каждый ресурс должен иметь уникальный идентификатор, которым выступает свойство x:Key.
Чтобы задать ресурс в качестве значения свойство, используется выражение {StaticResource ключ_ресурса}
В качестве ресурсов можно определить и более сложное содержимое, например:
<Page x:Class="HelloApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:HelloApp" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Page.Resources> <SolidColorBrush x:Key="darkRedBrush" Color="DarkRed" /> <SolidColorBrush x:Key="grayBrush" Color="DarkGray" /> <StackPanel x:Key="R2D2Button" Orientation="Horizontal"> <Ellipse Fill="Red" Width="30" Height="30" Stroke="Black" /> <TextBlock Text="Record" FontSize="22" Width="100" Height="30" Margin="8" /> </StackPanel> </Page.Resources> <Grid> <Button Background="{StaticResource grayBrush}" VerticalAlignment="Top" Foreground="{StaticResource darkRedBrush}" Content="{StaticResource R2D2Button}" /> </Grid> </Page>
Если у нас в проекте несколько страниц Page, и нам надо использовать одинаковые ресурсы на каждой из них, то мы можем определить данные ресурсы в качестве ресурсов всего
приложении. Для этого откроем файл App.xaml и добавим в него определение ресурсов:
<Application x:Class="HelloApp.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:HelloApp"> <Application.Resources> <SolidColorBrush x:Key="darkRedBrush" Color="DarkRed" /> <SolidColorBrush x:Key="grayBrush" Color="DarkGray" /> <StackPanel x:Key="R2D2Button" Orientation="Horizontal"> <Ellipse Fill="Red" Width="30" Height="30" Stroke="Black" /> <TextBlock Text="Record" FontSize="22" Width="100" Height="30" Margin="8" /> </StackPanel> </Application.Resources> </Application>
В этом случае данные ресурсы будут доступны из любого места приложения.
Темы
Кроме подключения ресурсов через StaticResource в разметке по умолчанию можно увидеть в определении Page такое выражение
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
. ThemeResource позволяет подключить ранее созданную тему для
приложения. Подобных тем существует довольно много для разных типов элементов:
In previous tutorials, we learned about application resources, the MAT (Multilingual App Toolkit), and how to test a localized app. In this tutorial, we will not only sum it all up in an easier way, but also create a localized application bar that you can use anywhere in your application.
Developers often have to use the same application bar on several pages in their project and they usually end up copying and pasting the XAML and C# code, which isn’t recommended.
In this tutorial, you will learn how to use app resources and how to add localization and globalization to your apps. You will also learn to use the App.xaml and App.xaml.cs files to build a localized application bar that you can use anywhere in your Windows Phone app.
1. Why Build a Localized App?
Windows Phone users are not all native English speakers. In fact, only 34% of them speak English. This means that 66% speak a language other than English and that is why it’s important to build localized apps.
One effective strategy to increase app downloads is by making your app more suitable for Windows Phone customers that don’t speak English. The more languages your app supports, the more downloads it will get and the better the ratings of your app will be. By supporting French, German, Arabic, and Spanish, you support about 75% of the Windows Phone market.
In this tutorial, we will be translating all of our app resources into French and Arabic. Here are some quick tips to keep in mind before we start:
- Make sure to name all the resources you’ll be using with meaningful names, because we will be referring to string resources by their name, not their value. Try to give each resource a unique name that makes sense.
- Try to gather all of your string resources in AppResources.resx, including button titles and error messages.
- Enable multiline support and text wrap in controls.
- Always save your work and make sure to rebuild your project often to implement the changes you make to AppResources.resx.
2. Culture & Language Support
Currencies, numbers, date, time, and region formats differ from culture to culture. Fortunately, the CultureInfo
class takes care of these details for each language. Actually, you can even retrieve the current cultural data of the phone and show its information in a MessageBox
using a single line of code:
1 |
MessageBox.Show(CultureInfo.CurrentCulture.Name); |
However, the InitializeLanguage()
function in App.xaml.cs does the work automatically each time the app is launched and sets RootFrame.Language
based on the value of the AppResources.ResourceLanguage
resource. Note that if your app doesn’t support any language other than en-US (English, United States), the app uses the neutral and default AppResources.resx file of the project.
3. Localizing Your App
Step 1: Adding Resources and Binding Text Elements
In this tutorial, we will build a one-page app that will show the user some wise, old sayings. To start, in MainPage.xaml, we’ll add a few TextBlock
elements without specifying their content by adding the following two lines of code in the parent ContentPanel
grid:
1 |
<TextBlock TextWrapping="Wrap" FontSize="30"></TextBlock> |
2 |
<TextBlock TextWrapping="Wrap" FontSize="30"></TextBlock> |
We also make the following changes in the default AppResources.resx file:
- changing the
ApplicationTitle
string value - adding two strings as shown in the following screenshot
Let’s now go back to MainPage.xaml. After adding the strings we’ll need in our app, we set the Text
property of the TextBlock
control to specify the content of each TextBlock
.
Instead of showing «MY APPLICATION» as the title, we use the string «My Localized App». We can accomplish this by using a binding that makes the reference to the app resources, binding the value of the string. To make this reference, we won’t be using the string value itself but its attribute (name), ApplicationTitle
.
1 |
Text="{Binding Path=LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}" |
Each of the two TextBlock
elements will have a saying as well. We’ll just use the same line of code, replacing the ApplicationTitle
attribute with our saying’s attribute. This is what your code should look like:
1 |
<StackPanel>
|
2 |
<TextBlock TextWrapping="Wrap" Text="{Binding Path=LocalizedResources.HappinessSaying, Source={StaticResource LocalizedStrings}}" FontSize="30"></TextBlock> |
3 |
<TextBlock TextWrapping="Wrap" Text="{Binding Path=LocalizedResources.NelsonMandelaSaying, Source={StaticResource LocalizedStrings}}" FontSize="30"></TextBlock> |
4 |
</StackPanel>
|
This is what the result looks like:
We now only need to add other languages and translate.
Step 2: Adding Other Languages
To add another language, go to the project’s properties by right-clicking the project in the Solution Explorer window. Make sure to access the project’s properties, not the properties of the solution.
In the Application Tab you should see the Supported Languages section. Select the language that you want to support. As mentioned earlier in this tutorial, we will add French and Arabic. As you can see in the list, you can even select the culture depending on the region, such as French (France), French (Belgium). For this tutorial, we’ll just choose the general one, ignoring dialect and region.
Once you save the changes, you’ll notice that Visual Studio has automatically generated two new .resx files:
- AppResources.ar.resx for Arabic
- AppResources.fr.resx for French
Note that the newly generated files have the same content as AppResources.resx. You shouldn’t change the attributes (names). You only need to translate the values.
3. Using the Multilingual App Toolkit
The Multilingual App Toolkit is very helpful for translating string resources. It is integrated into Visual Studio, providing support for building localized Windows and Windows Phone apps, and helping with translating app resources. The Multilingual App Toolkit makes adding other languages easier and you can import and export translation files easily.
You can download the Multilingual App Toolkit as a Visual Studio extension from Microsoft’s developer website. After installing the toolkit, select Enable Multilingual App Toolkit from the Tools menu.
After enabling the MAT, Visual Studio generates new .xlf files for each of the supported languages you added earlier. This means that you can generate machine translations by right-clicking an .xlf file and choosing Generate machine translations. You can also modify the translated string resources in the target tag in all the .xlf files.
4. How to Test a Localized App?
You can test a localized app using the emulator.
- Debug your project and go to Emulator Settings.
- Navigate to the Language tab and add a new language. It’s important to not restart your phone.
- Navigate to the Region tab and choose your region.
- Restart the phone.
When the phone restarts, Visual Studio may throw an error, losing the connection with the emulator. After restarting the phone, debug the project again. This is what the app looks like for Arabic:
Now that we’re done with string resources, we’ll add a localized application bar to our app.
5. Creating a Localized Application Bar
Step 1: Creating the Application Bar
In this step, we’ll create an application bar that we can use anywhere in our app. To do so, we’ll make use of the App.xaml file, in which we define global XAML styles and resources that will be used across the application.
In the ApplicationResources
tag in App.xaml, we add an application bar with only an icon and a menu item. Don’t forget to give a name to the application bar using the x:key
attribute so that we can reference it later.
1 |
<shell:ApplicationBar x:Key="myAppBar" IsVisible="True" IsMenuEnabled="True" > |
2 |
<shell:ApplicationBarIconButton IconUri="/Assets/AppBar/questionmark.png" Text="test" Click="Help_Click" /> |
3 |
<shell:ApplicationBar.MenuItems>
|
4 |
<shell:ApplicationBarMenuItem Text="Rate and review" Click="RateReview_Click" /> |
5 |
</shell:ApplicationBar.MenuItems>
|
6 |
</shell:ApplicationBar>
|
In the RateReview_Click
event handler, we use one of the phone tasks to navigate users to the store if they want to leave a review or rate the app. As for the Help_Click
event handler, we just add some C# code to navigate between the different pages. Note that I added a new XAML page, AboutTheApp.xaml, in which we show information about our app.
In App.xamls.cs, add the following statement so that we can benefit from the phone tasks class:
1 |
using Microsoft.Phone.Shell; |
When the user taps the rate and review menu item, the app will open the store on a page where the user can rate and/or review the app. We use a MarketPlaceReviewTask
like this:
1 |
MarketplaceReviewTask review = new MarketplaceReviewTask(); |
2 |
review.Show(); |
As for the Help_Click
event handler, the following code snippet takes care of navigating between the two pages:
1 |
(Application.Current.RootVisual as PhoneApplicationFrame).Navigate(new Uri("/AboutTheApp.xaml", UriKind.RelativeOrAbsolute)); |
Step 2: Referencing the Application Bar
After creating the application bar that we want to use, we add a new instance of the application bar using the below code snippet in MainPage.xaml.cs and then we make it refer to the one in App.xaml.
1 |
InitializeComponent(); |
2 |
ApplicationBar = new ApplicationBar(); |
3 |
ApplicationBar = ((ApplicationBar)Application.Current.Resources["myAppBar"]); |
We haven’t used the AppResources at all for building the application bar, which means that text properties are already set independently from the phone’s culture. Actually, we can’t really use bindings when dealing with application bars.
This is why we’ll reference the application bar we created earlier in App.xaml.cs and change the strings value, using a simple block of a code just after the InitializeComponent()
method. The strings used are also added to AppResources.resx.
1 |
// Standard XAML initialization
|
2 |
InitializeComponent(); |
3 |
var appBar = App.Current.Resources["myAppBar"] as ApplicationBar; |
4 |
((ApplicationBarIconButton)appBar.Buttons[0]).Text = AppResources.AboutAppBarIconText; |
5 |
((ApplicationBarMenuItem)appBar.MenuItems[0]).Text = AppResources.RateAppBarMenuItemText; |
After adding the string resources, translate them and rebuild the project. Finally, add the information of the AboutTheApp.xaml page. This is what the result looks like:
Conclusion
In this tutorial, we learned about phone culture, how to use app resources, how to build a localized application and application bar, and how to build an app bar that we can reuse anywhere in our application. We also learned how to make a reference to a string value in the AppResources files using bindings.
And finally, we got to know the way we use phone tasks to help users rate and review the app in the store. Feel free to download the sample project and ask any question that crosses your mind in the comments below.
День пятый. Темы и расцветка
Вступление
По умолчанию все телефоны под управлением Windows Phone 7 используют черные цвета. Это не прихоть разработчиков, а необходимая мера для продления работы телефона. Дело в том, что AMOLED-экраны, используемые в телефонах Windows Phone 7, имеют такую особенность, что при черном цвете потребление заряда батареи гораздо ниже, чем при светлом экране. Но, пользователь может изменить по своему желанию используемую тему на другую, более подходящему собственному вкусу.
Согласованный внешний вид и соблюдение рекомендаций дизайна Metro крайне важны для Windows Phone приложений. На следующем изображении показаны примеры различных основных цветов (accent colors), а также светлая и тёмная темы.
Цветовые темы
Сначала несколько слов о том, как поменять цветовую тему. На стартовом экране коснитесь правой стрелки в верхнем правом углу и перейдите к странице Settings (Настройки). Здесь вы можете выбрать визуальную тему: темную (светлый текст на темном фоне, используется по умолчанию) и светлую (темный текст на светлом фоне). Если выбрать новую тему и запустить примеры из прошлых уроков, то увидим, что цвета темы изменяются автоматически. Обратите внимание, что при смене темы меняется только цвет. Другие ресурсы (шрифты, размеры элементов) не меняются.
По своей сути тема — это набор ресурсов, используемых для персонализации визуальных элементов Windows Phone. Вы можете создавать свои приложения, которые будут выглядеть как родные системные приложения. Стилевые свойства включают в себя фоновые цвета и расцветку.
Таким образом, тема Windows Phone является комбинацией фона и расцветки. Цвет фона — это общий цвет для всей поверхности страницы, а цвет расцветки — это цвет, используемый в элементах управления и других визуальных элементах. Для фона есть два варианта: Dark и Light, для расцветки используются 10 вариантов.
Расцветка
Кроме выбора темы (темной или светлой) система позволяет также выбрать расцветку из десяти различных цветов, которые будут использоваться в используемых темах. Выбранная расцветка позволит раскрасить нужным цветом значки, плитки, ссылки и т.д. Список возможных цветов: Magenta, Purple, Teal, Lime, Brown, Pink, Orange, Blue, Red, Green
Производитель телефона может добавить еще свой одинадцатый цвет, но вам стоит избегать использования такого цвета в коде, так как нет возможности убедиться, что данный цвет используется на целевом устройстве, что вызовет ошибку.
Используем системные цвета
Вы, конечно, можете использовать свои цвета в приложении, чтобы подчеркнуть свою индивидуальность. Но, когда вы меняете цвета, подумайте, как будет выглядеть интерфейс в другой теме и при другой расцветке. Для серьезных программ предпочтительнее использовать системные цвета, не прописывая жестко цветовые значения. Обратите внимание, что встроенные элементы управления по умолчанию подстраиваются под тему и расцветку. Вот как меняет свой цвет элемент Slider (Слайдер) при двух разных выбранных расцветках.
Вот как выглядит приложение в разных вариантах расцветки (выбраны светлая и темная тема, а также цвета Brown, Teal и Purple).
Использование встроенных стилей
Также, как и каскадные таблицы стилей (CSS) совместно с HTML, XAML позволяет вам применять те же настройки для свойств элементов управления, используя специальный синтаксис, называемый расширением разметки. С помощью стилей и ресурсов вы можете повторно использовать настройки и создать для вашего приложения согласованный внешний вид.
Существует множество встроенных стилей и ресурсов для использования в Windows Phone проектах, которые соответствуют требованиям дизайна Metro и подходят как для светлой, так и для тёмной темы. Эти ресурсы включают кисти, цвета, шрифты, стили текста и темы.
Необходимые ресурсы подключаются к приложению при запуске. Вы можете установить ресурсы в дизайнере при помощи свойств, а также в XAML при помощи элемента разметки {StaticResource}.
В следующем примере показано, как привязать к фону (background) элемента управления Button кисть, являющуюся встроенным в Windows Phone ресурсом, с помощью расширения разметки.
<Button Content="Button" Height="72" Background="{StaticResource PhoneAccentBrush}" Width="160" />
В данном коде мы присвоили цвет кнопки через разметку StaticResource, задав кисть с именем PhoneAccentBrush. Если пользователь выберет в настройках телефона другую расцветку, то цвет кнопки в вашем приложении также изменится на выбранный цвет. Таки образом ваше приложение будет соответствовать цветовым предпочтениям пользователя.
На следующем изображении показано, как привязать к фону (background) элемента управления Button кисть, являющуюся встроенным в Windows Phone ресурсом, с помощью окна Properties.
Поскольку фон предыдущего примера имеет значение PhoneAccentBrush, цвет кнопки будет основываться на текущем основном цвете (accent color), выбранном пользователем. На следующем изображении показано, как кнопка выглядит, когда пользователь выбирает в качестве основного цвета синий или зеленый.
Рекомендация по проектированию интерфейса: Если основной или фоновый цвет элемента управления задан явно, убедитесь, что его содержание одинаково хорошо видно как при темной, так и при светлой теме оформления. Если указанного цвета не видно, также явно задайте фон или основной цвет, чтобы он был достаточно контрастным или выберите более подходящий цвет.
Также можно использовать ресурсы, связанные со шрифтами: имя шрифта, его размер и т.п.
<TextBlock Height="45"
HorizontalAlignment="Left"
Margin="20,154,0,0"
Name="textBlock1"
Text="TextBlock"
VerticalAlignment="Top"
Width="213"
FontFamily="{StaticResource PhoneFontFamilySemiLight}"
FontSize="{StaticResource PhoneFontSizeLarge}"/>
Если вам нужно динамически изменять стили, то можно это сделать через код следующим образом:
Color backgroundColor = (Color)Application.Current.Resources["PhoneBackgroundColor"];
Если вам интересно посмотреть, как устроена реализация тем, то найдите в папке %programfiles%\Microsoft SDKs\Windows Phone\v7.0\Design файл ThemeResources.xaml и откройте его текстовым редактором.
Кстати, дизайн приложений, использующих другие цвета, удобнее делать в программе Expression Blend 4, который специально предназначен как раз для дизайнеров. Откройте ваш проект в Expression Blend. Для этого щелкните правой кнопкой мыши на имени проекта в Solution Explorer и выберите команду Open In Expression Blend….
В открывшейся программе найдите вкладку Device (в верхней части окна) и перейдите на нее.
Вкладка позволяет увидеть, как будет выглядеть приложение с различными темами и расцветкой.
Color Resources
Перейдем теперь на вкладку Color Resources, которую можно найти внутри вкладки Properties, выбрав какой-либо элемент управления. Window Phone 7 имеет множество стандартных цветов, которые вы можете использовать в своих приложениях. Например, на картинке можно увидеть, что предлагаемые Expression Blend стандартные цвета PhoneAccentColor и PhoneBackgroundColor меняются в зависимости от темы, выбранной на вкладке «Device». На первой картинке выбрана тёмная тема и синяя расцветка, а на второй светлая тема и оранжевая расцветка.
Выбирая эти цвета для нашего приложения, вы подключаете предопределенные системные значения цветов. И когда пользователь будет менять тему или расцветку, то наше приложение также подстроится под новые настройки. Пример такого подхода продемонстрирован ниже. Добавим в приложение из прошлого занятия прямоугольник с градиентной заливкой, начиная со цвета PhoneBackgroundColor и заканчивая цветом PhoneAccentColor. Кроме того цвет заголовка страницы также использует выбранную расцветку.
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Stroke="Black" Grid.RowSpan="2">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="{StaticResource PhoneBackgroundColor}" Offset="0"/>
<GradientStop Color="{StaticResource PhoneAccentColor}" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<!--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}">
<TextBlock.Foreground>
<SolidColorBrush Color="{StaticResource PhoneAccentColor}"/>
</TextBlock.Foreground>
</TextBlock>
Теперь, когда пользователь будет менять тему или расцветку на своем устройстве, наше приложение также будет использовать выбранные цвета. Обратите внимание, что заголовок приложения (слово Котики) выводится цветом Lime, который я установил в настройках телефона.
При разработке собственных элементов также придерживайтесь подобного стиля — используйте стандартные значения цветов PhoneBackgroundColor, PhoneAccentColor и т.п.
Создание собственных стилей
Если вы хотите создать свой собственный стиль, как правило, вы должны объявить стиль как ресурс страницы или панели и применить его в качестве статического ресурса с помощью расширения разметки. Каждый стиль, как правило, имеет ключ (key), который используется для ссылки на него в дальнейшем, и целевой тип (target type), который указывает, к какому типу элементов управления он может быть применен. Основная часть стиля — это коллекция объектов Setter, которые содержат параметры Property (свойство) и Value (значение). Вы можете создавать стили в Visual Studio, указывая их прямо в коде XAML или вы можете использовать Expression Blend, который позволяет создавать стили более визуализированным способом. При создании ресурсов, которые устанавливают цвета, вы должны убедиться, что ваш выбор цветов одинаково хорошо выглядит как в светлой, так и в тёмной темах.
Реклама
Today I’ll show you how to share resources across Windows Phone application.
Maybe it’s not the best approach, but it’s the basics.
First of all let’s review the resource dictionaries hierarchy in Windows Phone application.
All visual elements have their own resource dictionary.
The algorithm of finding appropriate resource is the following:
check the current element dictionary then it’s parent then it’s parent and it’s parent depend on how many parents it’s have of course:) The last place where it checks is App.xaml file. I mean the resource dictionary defined in application object. Let’s call it top-level resource dictionary.
If you define the top-level resources then override them in control or page, this item will use the dictionary which was defined inside it.
By the way, the pre-defined WindowsPhone StaticResources like PhoneForegroundBrush are injected in the application when it starts.
Let’s see how to define top-level resources in example.
Now We’ll place our ResourceDictionary to the right place. The App.xaml file will look like this:
<Application ...> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Themes/Generic.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> ... <!--Other elements are here--> </Application>
We can add to the top level resource dictionary styles which we need to access around the application.
Can be background colors, brushes, gradients or converters. In our example, let’s place BitmapImage with Uri.
Our resource dictionary will look like this:
<ResourceDictionary ...> <BitmapImage x:Key="SharedImageSource" UriSource="../Images/SharedImage.png" /> <!--Other styles are here--> </ResourceDictionary>
Now you can use all you’ve added to your top-level resource dictionary across the application.
<ImageBrush ImageSource="{StaticResource SharedImageSource}"/>
Thank you for reading!
- Posted by in .NET, windows phone
- Tagged: .net, windows phone
8.5. Навигация по страницам приложения
До сих пор все рассмотренные примеры программ использовали только одну страницу Silverlight. Однако, большинство приложений содержат несколько страниц. В нашем примере необходима дополнительная страница для вывода и редактирования информации о выбранном клиенте.
Для добавление новой страницы в приложение нужно выбрать в главном меню Visual Studio пункт Проект -> Добавить новый элемент…. Откроется окно со списком шаблонов, которые можно добавить в проект. Выберем в списке пункт Страница Windows Phone в книжной ориентации и укажем имя новой страницы CustomerDetailPage.xaml. После нажатия на кнопку Добавить в проект будет добавлена новая страница приложения Windows Phone. Работа с новой страницей ничем не отличается от работы со страницей MainPage.
Навигация по страницам
Модель перемещения по страницам Silverlight больше похожа на навигацию в Интернете, чем на приложение Windows Forms. У каждой страница есть свой адрес, который указывается в виде URI (универсальный идентификатор ресурса). Объект NavigationService предоставляет методы для навигации.
// перемещение к странице CustomerDetailPage.xaml NavigationService.Navigate(new Uri("/CustomerDetailPage.xaml", UriKind.RelativeOrAbsolute));
Этот код вызовет переход приложения на страницу CustomerDetailPage. Обратите внимание, что метод Navigate принимает значение URI, которое содержит название страницы и тип URI.
При задании URI необходимо выбрать, будет указан относительный или абсолютный адрес. Установка типа в значение RelativeOrAbsolute обеспечивает гибкость, при загрузке ресурсов. Значение URI является обычной строкой, поэтому необходимо внимательно следить за правильностью указания ее значения, чтобы избежать ошибок во время выполнения программы.
Использование кнопки Назад. Пользователи Windows Phone ожидают, что при нажатии на аппаратную кнопку Назад произойдет переход к предыдущей странице. Эта функциональность автоматически поддерживается во всех приложениях для Windows Phone. Если пользователь нажмет кнопку Назад на странице MainPage, то приложение завершит работу.
Иногда необходимо переопределить это поведение, например, чтобы пользователь не переходил на другую страницу, если не сохранил введенные данные. Переопределить поведение кнопки Назад можно в обработчике события BackKeyPress, в котором можно при необходимости отменить переход:
private void PhoneApplicationPage_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e) { e.Cancel = true; }
Этот метод-обработчик события BackKeyPress отменяет переход к предыдущей странице при нажатии на кнопку Назад.
Если нужно, чтобы пользователь подтвердил намерение перейти на другую страницу, можно использовать класс MessageBox:
private void PhoneApplicationPage_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e) { if (MessageBox.Show("Вы действительно хотите перейти на другую страницу?", "Подтверждение перехода", MessageBoxButton.OKCancel) != MessageBoxResult.OK) { e.Cancel = true; } }
Этот код выводит на экран окно сообщения и спрашивает пользователя, действительно ли он хочет покинуть страницу. Если пользователь нажмет кнопку отмена, переход будет отменен.
Передача данных между страницами
Каждая страница Silverlight работает независимо других страниц, и данные каждой страницы приложения недоступны другим страницам. Но иногда нужно передавать данные из одной страницы в другую. Если данные являются простой строкой текста, самый простой способ передачи — добавить строку к URI целевой страницы. Этот метод похож на отправку запросов на веб-сервер.
В нашей программе для работы с клиентами при выборе пользователем клиента из списка нужно передать его имя и адрес на страницу редактирования.
private void customerList_SelectionChanged(object sender, SelectionChangedEventArgs e) { // получение информации о выбранном клиенте Customer selectedCustomer = customerList.SelectedItem as Customer; // формирование строки адреса с информацией о клиенте NavigationService.Navigate(new Uri("/CustomerDetailPage.xaml?name=" + selectedCustomer.Name + "&address=" + selectedCustomer.Address, UriKind.Relative)); }
Этот метод вызывается, когда пользователь выбирает клиента. Метод получает информацию о выбранном клиенте и формирует URI целевой страницы, в который добавляет информацию о выбранном клиенте. Часть запроса после символа «?» состоит из двух записей вида имя=значение, разделенных символом «&».
Теперь рассмотрим, как целевая страница может получить и использовать переданную информацию. Для этого необходимо изучить события, возникающие при навигации по страницам Silverlight.
Использование событий при навигации по страницам. При переходе на страницу Silverlight происходит событие OnNavigatedTo, а при уходе со страницы — событие OnNavigatingFrom. Для получения управления при возникновении этих событий нужно переопределить соответствующие методы в программном коде страницы.
Для того чтобы приложение получило управление при перемещении пользователя к странице, нужно переопределить OnNavigatedTo:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { string name, address; if (NavigationContext.QueryString.TryGetValue("name", out name)) nameTextBlock.Text = name; if (NavigationContext.QueryString.TryGetValue("address", out address)) addressTextBlock.Text = address; }
Этот метод пытается получить из свойства QueryString объекта NavigationContext значения переданных в строке адреса параметров. Каждый раз, когда пользователь переходит к этой странице, этот метод вызывается и выводит на страницу переданные значения параметров. Можно использовать событие OnNavigatedTo для настройки страницы, когда пользователь переходит к ней. При переходе на страницу можно передавать любое количество параметров.
Если запрашиваемый на странице параметр отсутствует, то программа выполняется дальше без возникновения ошибки. Поскольку параметры передаются в виде обычного текста, нужно внимательно следить за тем, чтобы имена параметров при передаче данных и их считывании совпадали.
Приведенный выше код можно использовать при создании приложения, состоящего из двух страниц, которое позволяет пользователю при выборе клиента выполнить переход на страницу с подробной информацией об этом клиенте.
Однако, в этом коде есть проблема, которая возникает при выполнении следующей последовательности действий:
- Выбор элемента в списке.
- Переход к странице с подробной информацией.
- Нажатие кнопки Назад для возврата к списку.
- Выбор того же самого элемента в списке.
При выполнении этой последовательности действий на странице не будет отображаться информация о том же самом клиенте. Для этого нужно выбрать другого клиента, и затем выбрать первого еще раз. Причина такого поведения состоит в том, что программа использует для перехода событие SelectionChanged, которое не происходит при повторном выборе того же самого клиента. Можно устранить эту проблему, сбрасывая выбор элемента при переходе к этой странице:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { customerList.SelectedItem = null; }
Теперь при повторном выборе того же самого элемента он будет считаться «новым» выбранным элементом. Однако, установка значения выбранного элемента в null также расценивается как выбор элемента, и при попытке обращения к значению этого свойство возникнет исключение. Избежать этого можно, добавив в обработчик события проверку, был ли выбран элемент:
private void customerList_SelectionChanged(object sender, SelectionChangedEventArgs e) { // отмена вызова, если элемент не выбран if (customerList.SelectedItem == null) return; // код метода }
Совместное использование объектов несколькими страницами
Часто требуется, чтобы страницы совместно использовали объекты, содержащие структурированные данные. В нашем приложении было бы удобнее передать на страницу подробной информации экземпляр объекта.
Можно легко предоставить совместный доступ к объектам для всех страниц приложения. Для этого используется страница App.xaml, которая автоматически создается при создании проекта приложения. Ее можно считать контейнером для приложения Windows Phone. Эта страница не выводится на экран, но файл App.xaml.cs содержит методы, которые выполняются при запуске приложения.
Можно изменить файл App.xaml.cs и добавить в него свой код. Если нужно хранить какие-либо глобальные данные, которые должны быть доступны всем страницам приложения, их объявления можно разместить здесь.
public partial class App : Application { // объект используется другими страницами приложения public Customer ActiveCustomer; }
Этот код содержит объявление объекта ActiveCustomer, который будет доступен всем страницам. Объект содержит ссылку на информацию о выбранном клиенте.
Любая страница Silverlight может получить ссылку на объект, размещенный на странице App:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { base.OnNavigatedTo(e); // получение ссылки на страницу с информацией о текущем клиенте App thisApp = Application.Current as App; // установка контекста данных для отображения в элементе Grid customerDisplayGrid.DataContext = thisApp.ActiveCustomer; }
Свойство Current класса Application является ссылкой, по которой можно обратиться к объектам в классе Application. При запуске приложения ей присваивается значение адреса текущей страницы.
Класс App.xaml.cs определяет дочерний класс App, который расширяет родительский класс Application. Чтобы получить объекты, определенные в классе App, нужно получить значение свойства Current класса Application и привести ее к типу App. Приведенный выше код запускается на странице customerDetailsPage, когда к ней происходит переход. При этом вызывается объект ActiveCustomer, который устанавливается в качестве контекста данных объекта customerDisplayGrid для обращения к выбранному клиенту.
Все объекты приложения, которые должны быть доступны другим страницам, имеет смысл помещать в класс App.xaml.cs. Здесь также можно добавить код, который при запуске программы будет загружать данные в эти объекты из хранилища.
8.6. Использование классов ViewModel
На текущий момент наша программа может отображать информацию о клиенте, но не позволяет редактировать эту информацию. Пользователь может изменить текст в полях страницы, но изменения не будут сохраняться в программе.
Чтобы внесенные на странице изменения обновляли данные в списке клиентов, можно использовать привязку данных. При этом, привязка текста в элементе TextBox должна быть двусторонней, чтобы при изменении данных на экране приложения автоматически обновлялось связанное с элементом свойство:
<TextBox Name="nameTextBox" Text="{Binding Name, Mode=TwoWay}" />
После этого можно добавить код к классу Customer классу для управления связанными событиями. Этот код при изменении имени клиента должен изменяться текст на экране, и если текст элемента TextBox изменится, то связанное с элементом также должно изменяться автоматически. Но можно сделать это немного иначе, использовав модель, известную под названием Model—View—ViewModel.
Создание класса ViewModel
Можно добавить привязку данных с классом Customer, но есть некоторые причины, почему это не является хорошей идеей. Существует правило проектирования программного обеспечения: обычно класс должен выполнять одно действие, и только одно. Класс Customer должен хранить данные о клиентах, но не должен участвовать в процессе редактирования. При хранении или передаче данных о клиентах мы не должны создавать методы, которые касаются редактирования данных. При передаче объекта, представляющего клиента, на другое устройство или при осуществлении привязки данных любое дополнительное свойство или метод будет лишней тратой пространства, так как не будет использоваться в этом контексте.
Возможность преобразования и проверки допустимости данных. В идеале, при вводе данных пользователем всегда должна осуществляться проверка соответствия вводимых данных определенным правилам. Например, должно соблюдаться правило: «Имя должно содержать только буквы и пробелы». Можно поместить эти правила в класс Customer, но будет намного проще указать их непосредственно в процессе ввода данных, так как они должны использоваться только при вводе данных. Также полезна возможность выполнять преобразование некоторых входных значений, например даты и времени, из текстового формата, в котором они вводятся и выводятся, в формат, в котором значения хранятся.
Возможность отмены действия. Практически всегда при проектировании формы для редактирования каких-либо значений рекомендуется предусмотреть возможность отмены сделанных пользователем, но еще не сохраненных изменений. Обычно в таких формах присутствуют кнопки сохранить и отмена. При использовании привязки данных это может оказаться проблемой, поскольку в этом случае объект данных сразу изменяется. Чтобы отследить изменения, внесенные пользователем, необходимо создать копию данных при открытии формы, и при отмене изменений использовать ее, что очень неудобно и требует создания дополнительного кода.
Создание класса ViewModel. Можно избежать этих проблем, создав класс ViewModel. Этот класс предназначен для представления данных и связывания с компонентами формы и также может выполнять необходимые проверки допустимости данных.
Создадим класс ViewModel для представления действий, которые нужно выполнить в пользовательском интерфейсе. Этот класс соединяет пользовательский интерфейс с объектами данных, содержит свойства, которые будут использоваться в пользовательском интерфейсе:
public class CustomerView : INotifyPropertyChanged { private string name; public string Name { get { return name; } set { name = value; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("name")); } } } // свойство Address создается таким же образом private int id; public int ID { get { return id; } } public event PropertyChangedEventHandler PropertyChanged; public void Load(Customer cust) { Name = cust.Name; Address = cust.Address; id = cust.ID; } public void Save(Customer cust) { cust.Name = Name; cust.Address = Address; } }
Этот класс генерирует события при изменении свойств в программе, и элементы Silverlight могут устанавливать новые значения свойств в классе при их изменении пользователем. Обратите внимание, что свойство ID доступно только для чтения, и пользователь не может изменить его значение. Это позволяет обеспечить уникальность идентификатора клиента.
Работа с данными в классе ViewModel. Класс CustomerView также содержит методы Load и Save, предназначенные для взаимодействия программы с содержимым класса ViewModel. Следующий код выполняется перед началом редактирования информации о клиенте:
// создание экземпляра класса ViewModel для страницы редактирования CustomerView view = new CustomerView(); protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { // получить ссылку на страницу, содержащую информацию об активном клиенте App thisApp = Application.Current as App; // загрузить объект с информацией об активном клиенте в класс ViewModel view.Load(thisApp.ActiveCustomer); // установить контекст данных для отображения customerDisplayGrid.DataContext = view; }
Когда программа переходит на страницу для редактирования информации о клиенте, Silverlight вызывает метод OnNavigatedTo для настройки страницы. Этот метод получает информацию о выбранном клиенте и загружает ее в экземпляр класса CustomerView.
Когда пользователь нажимает кнопку сохранить, программа должна выгрузить содержимое класса ViewModel в редактируемое свойство Customer:
private void saveButton_Click(object sender, RoutedEventArgs e) { // получить ссылку на страницу, содержащую информацию об активном клиенте App thisApp = Application.Current as App; // скопировать данные из класса ViewModel в свойство ActiveCustomer view.Save(thisApp.ActiveCustomer); // вернуться на предыдущую страницу NavigationService.GoBack(); }
Навигация по страницам с использованием метода GoBack
Класс NavigationService содержит метод GoBack, который переносит пользователя к предыдущей странице. Это эффективнее, чем использование URI, потому что при этом страница не обновляется. Если перейти на страницу, используя метод Navigate класса NavigationService, будет создана новая страница, и она будет создаваться каждый раз при переходе на нее. Это может замедлить работу приложения и привести к созданию и освобождению большого количества элементов Silverlight. Кроме того, неудобно при каждом переходе на страницу со списком прокручивать ее вниз, поскольку в этом случае при переходе на страницу будет отображаться начало списка.
Однако, использование метода GoBack для перехода к предыдущей странице приводит к возникновению некоторых проблем. Трудность состоит в том, что предыдущая страница не будет содержать изменения данных, которые внесет пользователь. Например, пользователь выполняет следующие действия:
- Выбор клиента из списка.
- Изменение имени клиента.
- Нажатие кнопки сохранить для выполнения изменений.
- Возврат к предыдущей странице.
После выполнения этих действий в списке будут содержаться первоначальные значения без учета сделанных пользователем изменений. Проблема состоит в том, что элемент ListBox не знает, что содержимое одной из записей в списке изменилось, поскольку при выводе списка на экран создается его копия, и при изменении данных эта копия обновляться не будет. Решение этой проблемы основано на использовании наблюдаемых коллекций ObservableCollection.
Наблюдаемые коллекции
Класс ObservableCollection используется для хранения коллекции элементов и предоставляет поддержку уведомлений так, чтобы при изменении коллекции элемент ListBox можно было связать с событием изменения. Для создания наблюдаемой коллекции можно использовать имеющийся список:
ObservableCollection<Customer> observableCustomers; private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e) { // получить ссылку на страницу, содержащую список клиентов App thisApp = Application.Current as App; // создать наблюдаемую коллекцию этих клиентов observableCustomers = new ObservableCollection<Customer>( thisApp.ActiveCustomerList.CustomerList); // отображение элементов наблюдаемой коллекции customerList.ItemsSource = observableCustomers; }
Этот код выполняется при запуске главной страницы приложения. Он создает новый список observableCustomers на основе имеющегося списка клиентов и устанавливает этот список в качестве источника данных элемента customerList. Теперь, при изменении значения элементов в списке эти изменения будут отображаться на экране.
Однако, если пользователь обновит имя клиента, это изменение не будет отражено на экране, потому что ObservableCollection реагирует на изменение содержимого списка, но не на изменение данных в элементе списка. Это является очень серьезным недостатком, приводящим к неправильной работе программы.
Чтобы исправить эту ошибку, нужно как-то внести изменения в список, чтобы он обновлялся на экране. Один из способов вызвать обновление заключается в том, чтобы удалить элемент из списка и снова его добавить. Изменения содержимого наблюдаемой коллекции генерируют события, которые обрабатывает элемент ListBox, который выводит список на экран.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { // получить ссылку на страницу, содержащую список клиентов App thisApp = Application.Current as App; if (thisApp.ActiveCustomer != null) { // найти нужного клиента в списке int pos = observableCustomers.IndexOf(thisApp.ActiveCustomer); // удалить клиента observableCustomers.RemoveAt(pos); // вернуть клиента назад observableCustomers.Insert(pos, thisApp.ActiveCustomer); } }
Этот код выполняется, когда пользователь переходит назад к главной странице. Если выбран какой-нибудь клиент, метод удаляет этого клиента из списка и затем добавляет его на то же самое место. Это вызывает изменение списка, и пользователь будет видеть сделанные изменения. При обновлении всего одного элемента обновление будет выполняться довольно быстро. Это особенно важно, если список содержит несколько тысяч элементов.
При использовании класса ViewModel для редактирования информации о клиенте мы создавали методы для загрузки и сохранения информации, которые заносили информацию о клиенте в класс CustomerView и затем возвращали обновленные значения. При использовании класса ObservableCollection необходимо сделать что-то похожее. К счастью, существует много способов получения списка данных из класса ObservableCollection. Например, можно использовать расширяющий метод ToList:
thisApp.ActiveCustomerList.CustomerList = observableCustomers.ToList<Customer>();
Использование наблюдаемых коллекций не приводят к повышению расхода памяти, поскольку содержат набор ссылок на уже существующие объекты. Соответственно, требуется лишь небольшой объем памяти для хранения дополнительных ссылок на объекты. Однако, наблюдаемые коллекции не имеет смысла использовать, если программа только выводит список на экран, но не изменяет его.
Краткие итоги
- Программы могут изменять значения свойств элементов Silverlight для управления отображением элементов на экране. К числу свойств относятся положение элемента на экране и его цвет.
- Большинство свойств элементов удобнее задавать, редактируя напрямую XAML-код. XAML-описание элемента имеет определенную структуру, в которой одни свойства могут вкладываться в другие.
- В элементе TextBox есть набор свойств, которые задают тип клавиатуры, которая будет использоваться для ввода данных. Можно использовать для ввода специальную клавиатуру для ввода чисел вместо клавиатуры для ввода произвольного текста.
- Windows Phone может выводить на экран окно с сообщением для пользователя. Текст сообщения может состоять из нескольких строк. Сообщения могут также использоваться для подтверждения или отмены действий пользователя.
- Ресурсы могут быть добавлены в приложение для Windows Phone как часть содержимого или как внедренные ресурсы. Элемент содержимого копируется в каталог приложения в отдельный файл, который может использоваться программой. Внедренный ресурс встраивается в файл сборки приложения. Элементы содержимого не замедляют загрузку сборки, но могут медленнее загружаться во время работы программы. Внедренные ресурсы загружаются быстрее, но увеличивают размер сборки программы.
- Элементы Silverlight могут генерировать события в ответ на действия пользователя. Например, событие TextChanged элемента TextBox происходит при изменении текста элемента.
- Silverlight предоставляет привязку данных, с помощью которой свойства программного объекта могут быть соединены со свойствами визуального элемента Silverlight. Привязка может быть однонаправленной, когда визуальный элемент используется только для вывода значения объекта программы, или двунаправленной, когда изменение свойства визуального элемента приводит к обновлению связанного свойства класса.
- Можно связать коллекцию элементов с элементом ListBox для отображения списка элементов. Шаблон данных используется для описания того, как отдельные свойства каждого элемента должны выводиться на экран.
- Приложения Silverlight могут состоять из нескольких страниц. Навигация по страницам выполняется в классе Navigate, который использует URI страницы. Простые строковые значения можно передавать между страницами, разместив их в строке запроса, присоединенной к URI.
- Страницы могут получать события при перемещении к ним и от них. Событие OnNavigatedFrom предоставляет возможность отмены перехода на другую страницу, если нужно чтобы пользователь подтвердил переход.
- Большие объекты данных могут совместно использовать несколько страниц приложения с помощью класса App, который является частью приложения Windows Phone. Любая страница приложения Silverlight может получить ссылку на объект приложения, который является частью этого приложения.
- Программисты могут создать классы ViewModel, которые связывают редактируемые данные с элементами на странице Silverlight.
- Механизм ObservableCollection позволяет отразить на экране изменения в коллекции элементов.
Вопросы
- Как в программе можно обработать ошибку, если пользователь введет вместо числа произвольный текст?
- Как во время работы программы изменить цвет текста?
- Что нужно сделать, чтобы при выборе пользователем текстового поля выводилась специальная клавиатура для ввода чисел?
- Как при создании программы можно изменить свойства элемента Silverlight?
- Как вывести на экран сообщение, чтобы приложение могло получить ответ от пользователя?
- Какие настройки можно задать при добавлении в проект ресурса?
- В чем разница между элементом контента и внедренным ресурсом?
- Что нужно сделать, чтобы добавить к программу код, который должен выполняться, когда происходит определенное событие?
- Для чего используется привязка данных?
- Как выполнить привязку объекта данных к визуальному элементу Silverlight?
- В чем разница между однонаправленной и двунаправленной привязкой данных?
- Как можно указать поддерживаемый страницей приложения тип ориентации?
- Для чего предназначены объекты-контейнеры?
- Как можно вывести в приложение список данных?
- Как осуществить переход к другой странице приложения?
- Как можно передать данные другой странице приложения?
- Как создать и использовать в приложении класс ViewModel?
- Для чего используются наблюдаемые коллекции?
Упражнения
Упражнение 1. Добавление обработки ошибок
Существующая версия программа Калькулятор времени работает при вводе правильных числовых значений, но выдает исключение, если пользователь введет значения, лежащие вне диапазона, или произвольный текст, который не является числом. Необходимо добавить в программу код для обработки следующих ошибок:
- ввод произвольного текста вместо чисел;
- ввод значения часа, которое больше 23 или меньше 0;
- ввод значения минут, которое больше 59 или меньше 0;
- ввод времени начала, которое больше времени окончания.
В этом упражнении Вы улучшите версию программы, созданную другим программистом.
- Откройте в Visual Studio проект TimeCalculator в папке Lab4 TimeCalculator.
- Запустите программу. Введите значения Начало: 0a:00 и Окончание: 00:00 и нажмите кнопку вычислить.
- Приложение сгенерирует исключение, поскольку значение 0a не может быть преобразовано в число.
Измените код программы, чтобы учесть приведенные выше замечания.
- Используйте метод TryParse для преобразования текста в число, чтобы программа могла обнаружить недопустимые значения.
- Выделите на экран недопустимые значения красным цветом, а допустимые значения — цветом текста по умолчанию.
- Выведите на экран окно с сообщением, если время начала и окончания события недопустимо.
Упражнение 2. Улучшение пользовательского интерфейса
Элементы TextBox в приложении могут генерировать событие TextChanged, когда пользователь вводит новые значения. Связанный с этими событиями код может автоматически обновлять значения на экране.
- Добавьте обработчик события TextChanged так, чтобы не нужно было использовать кнопку вычислить.
- Удалите кнопку вычислить.
Лучший способ это сделать заключается в том, чтобы создать один метод, который будет вызываться для отображения нового значения результата при изменении любого текстового поля. Этот метод можно использовать в обработчиках элементов TextBox.
Упражнение 3. Использование привязки данных
Другой программист создал класс TimeClass для приложения. В классе пять свойств:
- StartHour
- StartMinute
- EndHour
- EndMinute
- MinuteDifference
Вам нужно выполнить привязку данных для связывания элементов на экране с этими свойствами. Первые четыре свойства будут использовать двунаправленную привязку, а пятое свойство является выходным значением, которое используется для вывода на экран результата.
Добавление класса TimeClass в качестве ресурса
Сначала нужно добавить TimeClass в проект так, чтобы его могли использовать элементы Silverlight.
- Откройте в Visual Studio проект TimeCalculator в Lab4 Data Binding TimeCalculator.
- Откройте страницу MainPage.xaml.
- Сначала нужно добавить пространство имен к ресурсам страницы MainPage. После строки, которая начинается на
xmlns:mc = "http://schemas.openxmlformats....
добавьте строку
xmlns:local = "clr-namespace:TimeCalculator"
- Теперь нужно добавить связь к классом, который мы хотим использовать. После строки
shell:SystemTray.IsVisible="True">
добавьте строки
<phone:PhoneApplicationPage.Resources> <local:TimeClass x:Key="TimeClass" /> </phone:PhoneApplicationPage.Resources>
- Теперь можно добавить ресурс к элементу Grid, который содержит элементы Silverlight пользовательского интерфейса приложения. В элемент Grid с именем LayoutRoot добавьте следующий атрибут:
DataContext = "{StaticResource TimeClass}"
Связывание данных со свойствами элементов
- В редакторе Visual Studio щелкните по элементу startHourTextBox. В области свойств будут отображаться свойства этого элемента.
- Щелкните правой кнопкой мыши по свойству Text, и выберите в контекстном меню пункт Применить привязку данных…. Появится список доступных свойств.
- Дважды щелкните по элементу StartHour. Обратите внимание, что в параметрах задан режим TwoWay.
- Повторите эти действия для привязки свойств StartMin, EndHour и Endmin к соответствующим элементам.
- В настройках привязки элемента resultTextBlock к свойству MinuteDifference установите режим привязки OneWay.
- Запустите программу и введите значение времени окончания. Проверьте, что значение результата обновляется, когда пользователь переходит к другому элементу.
Теперь программа использует привязку данных, но часть обработка ошибок при вводе не выполняется. Попробуйте добавить в программу код для обработки ошибок. Для этого можно добавить в класс TimeClass свойства с сообщениями об ошибке и связать их с визуальными элементами.
Упражнение 4. Связывание данных со списками
Вашему начальнику нужно приложение для работы с информацией о клиентах, которое может выводить на экран список встреч с каждым клиентом. Программист начал писать эту программу, но не закончил ее. Вам поручено дописать программу.
Класс Session
Этот класс содержит текстовое описание встречи и ее продолжительность в минутах.
public class Session { public string Description { get; set; } public int LengthInMins { get; set; } public Session(string inDescription, int inLength) { Description = inDescription; LengthInMins = inLength; } }
Класс Customer содержит список встреч с клиентом.
public List<Session> Sessions;
Программа создает тестовый набор встреч для каждого клиента, но Ваш начальник считает, что этого недостаточно.
Увеличение количества тестовых данных
Для начала нужно изменить метод MakeTestCustomers класса Customers, чтобы создать больше тестовых данных.
- Откройте в Visual Studio проект CustomerManager в папке Lab4 CustomerManager.
- Откройте файл Customers.cs.
- Найдите в классе Customers метод MakeTestCustomers. Этот метод создает тестовый набор клиентов, и для каждого клиента создается несколько тестовых встреч. Количество встреч для каждого клиента определяется случайным образом, но диапазон значений является слишком маленьким.
- Найдите строку
int noOfSessions = sessionRand.Next(1,4);
Метод Next возвращает случайное значение из диапазона 1—3, что позволит создать максимум 3 тестовых встречи с одним клиентом.
- Измените параметры метода так, чтобы для каждого клиента было создано 20—30 встреч. Это позволит проверить, что выводимый на экран список клиентов можно прокручивать.
Добавление навигации по страницам
Страница с информацией о клиенте теперь содержит кнопку встречи, которая используется для просмотра встреч с клиентом. Но пока кнопке не назначен обработчик событий, и при ее нажатии ничего не происходит. Необходимо создать обработчик нажатия на кнопку и добавить код для перехода к странице встреч.
- Откройте в редакторе Visual Studio страницу CustomerDetailPage.xaml.
- Дважды щелкните по кнопке встречи, чтобы создать обработчик событий и перейти к файлу кода CustomerDetailPage.xaml.cs.
- В созданный метод sessionButton_Click добавьте следующий код для выполнения перехода на страницу.
NavigationService.Navigate(new Uri("/SessionDetailPage.xaml", UriKind.RelativeOrAbsolute));
- Запустите программу. Выберите клиента и нажмите на кнопку встречи. Произойдет переход на страницу встреч, но на экран ничего не будет выводиться, потому что к странице не привязаны никакие данные.
Добавление привязки данных на страницу Sessions
- Откройте в Visual Studio файл с исходным кодом SessionDetailPage.xaml.cs.
- Переместите курсор в класс сразу после закрывающей фигурной скобки конструктора SessionDetailsPage. Введите слово override и нажмите пробел.
- Intellisense выведет на экран список методов, которые могут быть переопределены в этом классе. Выберите метод OnNavigatedTo и нажмите Enter.
- Добавьте следующий код в метод OnNavigatedTo.
// получить ссылку на страницу, содержащую информацию о выбранном клиенте App thisApp = Application.Current as App; CustomerName.DataContext = thisApp.ActiveCustomer; SessionList.ItemsSource = thisApp.ActiveCustomer.Sessions;
- Запустите программу. Выберите клиента и нажмите на кнопку встречи. На экран будет выведен список встреч для выбранного клиента. При нажатии на кнопку Назад произойдет переход на страницу информации о клиенте. Если нажать кнопку Назад еще раз, откроется страница со списком клиентов.