Опубликован: 12.02.2013 | Доступ: свободный | Студентов: 791 / 47 | Длительность: 17:51:00
Специальности: Программист
Лекция 5:

Создание приложений Silverlight

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 для настройки страницы, когда пользователь переходит к ней. При переходе на страницу можно передавать любое количество параметров.

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

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

Однако, в этом коде есть проблема, которая возникает при выполнении следующей последовательности действий:

  1. Выбор элемента в списке.
  2. Переход к странице с подробной информацией.
  3. Нажатие кнопки Назад для возврата к списку.
  4. Выбор того же самого элемента в списке.

При выполнении этой последовательности действий на странице не будет отображаться информация о том же самом клиенте. Для этого нужно выбрать другого клиента, и затем выбрать первого еще раз. Причина такого поведения состоит в том, что программа использует для перехода событие 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 для перехода к предыдущей странице приводит к возникновению некоторых проблем. Трудность состоит в том, что предыдущая страница не будет содержать изменения данных, которые внесет пользователь. Например, пользователь выполняет следующие действия:

  1. Выбор клиента из списка.
  2. Изменение имени клиента.
  3. Нажатие кнопки сохранить для выполнения изменений.
  4. Возврат к предыдущей странице.

После выполнения этих действий в списке будут содержаться первоначальные значения без учета сделанных пользователем изменений. Проблема состоит в том, что элемент 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>();

Использование наблюдаемых коллекций не приводят к повышению расхода памяти, поскольку содержат набор ссылок на уже существующие объекты. Соответственно, требуется лишь небольшой объем памяти для хранения дополнительных ссылок на объекты. Однако, наблюдаемые коллекции не имеет смысла использовать, если программа только выводит список на экран, но не изменяет его.

Краткие итоги

  1. Программы могут изменять значения свойств элементов Silverlight для управления отображением элементов на экране. К числу свойств относятся положение элемента на экране и его цвет.
  2. Большинство свойств элементов удобнее задавать, редактируя напрямую XAML-код. XAML-описание элемента имеет определенную структуру, в которой одни свойства могут вкладываться в другие.
  3. В элементе TextBox есть набор свойств, которые задают тип клавиатуры, которая будет использоваться для ввода данных. Можно использовать для ввода специальную клавиатуру для ввода чисел вместо клавиатуры для ввода произвольного текста.
  4. Windows Phone может выводить на экран окно с сообщением для пользователя. Текст сообщения может состоять из нескольких строк. Сообщения могут также использоваться для подтверждения или отмены действий пользователя.
  5. Ресурсы могут быть добавлены в приложение для Windows Phone как часть содержимого или как внедренные ресурсы. Элемент содержимого копируется в каталог приложения в отдельный файл, который может использоваться программой. Внедренный ресурс встраивается в файл сборки приложения. Элементы содержимого не замедляют загрузку сборки, но могут медленнее загружаться во время работы программы. Внедренные ресурсы загружаются быстрее, но увеличивают размер сборки программы.
  6. Элементы Silverlight могут генерировать события в ответ на действия пользователя. Например, событие TextChanged элемента TextBox происходит при изменении текста элемента.
  7. Silverlight предоставляет привязку данных, с помощью которой свойства программного объекта могут быть соединены со свойствами визуального элемента Silverlight. Привязка может быть однонаправленной, когда визуальный элемент используется только для вывода значения объекта программы, или двунаправленной, когда изменение свойства визуального элемента приводит к обновлению связанного свойства класса.
  8. Можно связать коллекцию элементов с элементом ListBox для отображения списка элементов. Шаблон данных используется для описания того, как отдельные свойства каждого элемента должны выводиться на экран.
  9. Приложения Silverlight могут состоять из нескольких страниц. Навигация по страницам выполняется в классе Navigate, который использует URI страницы. Простые строковые значения можно передавать между страницами, разместив их в строке запроса, присоединенной к URI.
  10. Страницы могут получать события при перемещении к ним и от них. Событие OnNavigatedFrom предоставляет возможность отмены перехода на другую страницу, если нужно чтобы пользователь подтвердил переход.
  11. Большие объекты данных могут совместно использовать несколько страниц приложения с помощью класса App, который является частью приложения Windows Phone. Любая страница приложения Silverlight может получить ссылку на объект приложения, который является частью этого приложения.
  12. Программисты могут создать классы ViewModel, которые связывают редактируемые данные с элементами на странице Silverlight.
  13. Механизм ObservableCollection позволяет отразить на экране изменения в коллекции элементов.

Вопросы

  1. Как в программе можно обработать ошибку, если пользователь введет вместо числа произвольный текст?
  2. Как во время работы программы изменить цвет текста?
  3. Что нужно сделать, чтобы при выборе пользователем текстового поля выводилась специальная клавиатура для ввода чисел?
  4. Как при создании программы можно изменить свойства элемента Silverlight?
  5. Как вывести на экран сообщение, чтобы приложение могло получить ответ от пользователя?
  6. Какие настройки можно задать при добавлении в проект ресурса?
  7. В чем разница между элементом контента и внедренным ресурсом?
  8. Что нужно сделать, чтобы добавить к программу код, который должен выполняться, когда происходит определенное событие?
  9. Для чего используется привязка данных?
  10. Как выполнить привязку объекта данных к визуальному элементу Silverlight?
  11. В чем разница между однонаправленной и двунаправленной привязкой данных?
  12. Как можно указать поддерживаемый страницей приложения тип ориентации?
  13. Для чего предназначены объекты-контейнеры?
  14. Как можно вывести в приложение список данных?
  15. Как осуществить переход к другой странице приложения?
  16. Как можно передать данные другой странице приложения?
  17. Как создать и использовать в приложении класс ViewModel?
  18. Для чего используются наблюдаемые коллекции?

Упражнения

Упражнение 1. Добавление обработки ошибок

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

  • ввод произвольного текста вместо чисел;
  • ввод значения часа, которое больше 23 или меньше 0;
  • ввод значения минут, которое больше 59 или меньше 0;
  • ввод времени начала, которое больше времени окончания.

В этом упражнении Вы улучшите версию программы, созданную другим программистом.

  1. Откройте в Visual Studio проект TimeCalculator в папке Lab4 TimeCalculator.
  2. Запустите программу. Введите значения Начало: 0a:00 и Окончание: 00:00 и нажмите кнопку вычислить.
  3. Приложение сгенерирует исключение, поскольку значение 0a не может быть преобразовано в число.

Измените код программы, чтобы учесть приведенные выше замечания.

  • Используйте метод TryParse для преобразования текста в число, чтобы программа могла обнаружить недопустимые значения.
  • Выделите на экран недопустимые значения красным цветом, а допустимые значения — цветом текста по умолчанию.
  • Выведите на экран окно с сообщением, если время начала и окончания события недопустимо.

Упражнение 2. Улучшение пользовательского интерфейса

Элементы TextBox в приложении могут генерировать событие TextChanged, когда пользователь вводит новые значения. Связанный с этими событиями код может автоматически обновлять значения на экране.

  1. Добавьте обработчик события TextChanged так, чтобы не нужно было использовать кнопку вычислить.
  2. Удалите кнопку вычислить.

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

Упражнение 3. Использование привязки данных

Другой программист создал класс TimeClass для приложения. В классе пять свойств:

  1. StartHour
  2. StartMinute
  3. EndHour
  4. EndMinute
  5. MinuteDifference

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

Добавление класса TimeClass в качестве ресурса

Сначала нужно добавить TimeClass в проект так, чтобы его могли использовать элементы Silverlight.

  1. Откройте в Visual Studio проект TimeCalculator в Lab4 Data Binding TimeCalculator.
  2. Откройте страницу MainPage.xaml.
  3. Сначала нужно добавить пространство имен к ресурсам страницы MainPage. После строки, которая начинается на
    xmlns:mc = "http://schemas.openxmlformats....
    

    добавьте строку

    xmlns:local = "clr-namespace:TimeCalculator"
  4. Теперь нужно добавить связь к классом, который мы хотим использовать. После строки
    shell:SystemTray.IsVisible="True">
    

    добавьте строки

    <phone:PhoneApplicationPage.Resources>
      <local:TimeClass x:Key="TimeClass" />
    </phone:PhoneApplicationPage.Resources>
    
  5. Теперь можно добавить ресурс к элементу Grid, который содержит элементы Silverlight пользовательского интерфейса приложения. В элемент Grid с именем LayoutRoot добавьте следующий атрибут:
    DataContext = "{StaticResource TimeClass}"

Связывание данных со свойствами элементов

  1. В редакторе Visual Studio щелкните по элементу startHourTextBox. В области свойств будут отображаться свойства этого элемента.
  2. Щелкните правой кнопкой мыши по свойству Text, и выберите в контекстном меню пункт Применить привязку данных…. Появится список доступных свойств.
  3. Дважды щелкните по элементу StartHour. Обратите внимание, что в параметрах задан режим TwoWay.
  4. Повторите эти действия для привязки свойств StartMin, EndHour и Endmin к соответствующим элементам.
  5. В настройках привязки элемента resultTextBlock к свойству MinuteDifference установите режим привязки OneWay.
  6. Запустите программу и введите значение времени окончания. Проверьте, что значение результата обновляется, когда пользователь переходит к другому элементу.

Теперь программа использует привязку данных, но часть обработка ошибок при вводе не выполняется. Попробуйте добавить в программу код для обработки ошибок. Для этого можно добавить в класс 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, чтобы создать больше тестовых данных.

  1. Откройте в Visual Studio проект CustomerManager в папке Lab4 CustomerManager.
  2. Откройте файл Customers.cs.
  3. Найдите в классе Customers метод MakeTestCustomers. Этот метод создает тестовый набор клиентов, и для каждого клиента создается несколько тестовых встреч. Количество встреч для каждого клиента определяется случайным образом, но диапазон значений является слишком маленьким.
  4. Найдите строку
    int noOfSessions = sessionRand.Next(1,4);
    
    Метод Next возвращает случайное значение из диапазона 1—3, что позволит создать максимум 3 тестовых встречи с одним клиентом.
  5. Измените параметры метода так, чтобы для каждого клиента было создано 20—30 встреч. Это позволит проверить, что выводимый на экран список клиентов можно прокручивать.

Добавление навигации по страницам

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

  1. Откройте в редакторе Visual Studio страницу CustomerDetailPage.xaml.
  2. Дважды щелкните по кнопке встречи, чтобы создать обработчик событий и перейти к файлу кода CustomerDetailPage.xaml.cs.
  3. В созданный метод sessionButton_Click добавьте следующий код для выполнения перехода на страницу.
    NavigationService.Navigate(new Uri("/SessionDetailPage.xaml",
        UriKind.RelativeOrAbsolute));
    
  4. Запустите программу. Выберите клиента и нажмите на кнопку встречи. Произойдет переход на страницу встреч, но на экран ничего не будет выводиться, потому что к странице не привязаны никакие данные.

Добавление привязки данных на страницу Sessions

  1. Откройте в Visual Studio файл с исходным кодом SessionDetailPage.xaml.cs.
  2. Переместите курсор в класс сразу после закрывающей фигурной скобки конструктора SessionDetailsPage. Введите слово override и нажмите пробел.
  3. Intellisense выведет на экран список методов, которые могут быть переопределены в этом классе. Выберите метод OnNavigatedTo и нажмите Enter.
  4. Добавьте следующий код в метод OnNavigatedTo.
    // получить ссылку на страницу, содержащую информацию о выбранном клиенте
    App thisApp = Application.Current as App;
    
    CustomerName.DataContext = thisApp.ActiveCustomer;
    SessionList.ItemsSource = thisApp.ActiveCustomer.Sessions;
    
  5. Запустите программу. Выберите клиента и нажмите на кнопку встречи. На экран будет выведен список встреч для выбранного клиента. При нажатии на кнопку Назад произойдет переход на страницу информации о клиенте. Если нажать кнопку Назад еще раз, откроется страница со списком клиентов.