locked
Навигация в Windows 8 приложениях RRS feed

  • Общие обсуждения

  • Начнем с того, что создадим приложение Metro Style. Для этого необходимо в Windows 8 запустить Visual Studio 2012 и выбрать необходимый тип проекта: Windows Metro Style -> Blank App (XAML).

    В свежесозданном приложении будет целая одна страница - MainPage.xaml (нет будет еще App.xaml, манифест и т.д., но страница одна).
    Для простоты демонстрации примеров, на главной странице, я заменю Grid на StackPanel и для каждого примера буду кидать в него еще один StackPanel с горизонтальной ориентацией.
    Для первого примера простой навигации нам понадобиться только кнопка, для того, чтобы перейти на страницу с информацией о приложении (т.е. просто переход на другую страницу, с возвратом на исходную).
    Итак StackPanel будет иметь вот такой вид:

    <StackPanel Orientation="Horizontal">
        <TextBlock Text="Пример простого перехода" Margin="5" VerticalAlignment="Center" />
        <Button Content="О программе" x:Name="btAbout" Click="btAbout_Click_1" />
    </StackPanel>

    Добавим еще одну страницу в проект (правый клик на проекте, добавить новый элемент, в левом дереве выбираем Windows Metro Style и в списке кликаем на BlankPage, не забываем переименовать страницу в AboutPage. Заменяем Grid на вот такой StackPanel:

    <StackPanel Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Margin="5" Text="Демонстрационное приложение для показа возможностей навигации в Windows 8 приложениях" />
        <Button Content="На главную" x:Name="btBack" Click="btBack_Click_1" />
    </StackPanel>

    Все, возвращаемся в файл кода главной страницы (MainPage.xaml.cs) и добавляем в обработчик клика на кнопке вот такой код:

    private void btAbout_Click_1(object sender, RoutedEventArgs e)
    {
        this.Frame.Navigate(typeof(AboutPage));
    }

    Как видим, наша страница знает про некий Frame и передаем мы ему для навигации не объект новой страницы, а тип, на основе которого он сам создаст страницу. Кстати, у Frame есть еще два полезных метода: GoBack и GoForward. В принципе, именно первым нам и необходимо воспользоваться на странице о программе. Это нам позволит показывать ее не только с главной формы, но и с любой другой, а возврат будет осуществляться на вызвавшею форму. Код обработчика будет иметь вид:

    private void btBack_Click_1(object sender, RoutedEventArgs e)
    {
        this.Frame.GoBack();
    }

    Все, если мы запустим приложение, кликнем на кнопку "О программе", то увидим нашу вторую, информационную страницу. Кликнув на кнопку "На главную", благодаря методу GoBack мы вернемся к предыдущей странице. 

    Второй пример, с передачей параметров, заставит наше предложение поприветствовать нас по имени. В главном окне, мы введем свое имя, а нажав на второй странице, мы должны увидеть "Здравствуй, <введенное имя>".

    На MainPage добавляем очередной StackPanel с вот таким кодом:

    <StackPanel Orientation="Horizontal">
        <TextBlock Text="Пример передачи параметр. Введите свое имя:" Margin="5" VerticalAlignment="Center" />
        <TextBox x:Name="tbName" Margin="5" MinWidth="200" />
        <Button Content="Привет!" x:Name="btHello" Click="btHello_Click_1" />
    </StackPanel>

    Добавляем в наш проект еще одну страницу с именем HelloPage, на ней также заменим Grid на StackPanel вот с таким кодом:

    <StackPanel Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock x:Name="tbHello" />
        <Button Content="Назад" x:Name="btBack" Click="btBack_Click_1" />
    </StackPanel>

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

    private void btHello_Click_1(object sender, RoutedEventArgs e)
    {
        this.Frame.Navigate(typeof(HelloPage), tbName.Text);
    }

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

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        tbHello.Text = string.Format("Здравствуй, {0}", e.Parameter);
    }

    Все, запускаем приложение, вводим имя, нажимаем кнопку "Привет!" и видим:  "Здравствуй, Алексей"

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

    public MainPage()
    {
        this.InitializeComponent();
        this.NavigationCacheMode = NavigationCacheMode.Enabled;
    }

    Все, теперь при переходе с главной страницы на страницу с приветствием и обратно, мы будем на главной форме видеть введенный ранее текст.
    Ну и последний, четвертый пример, в котором мы попробуем передать объект и воспользоваться Binding-ом. Для этого в наш проект добавим вот такой класс:

    class Person : DependencyObject
    {
        public string FirstName
        {
            get { return (string)GetValue(FirstNameProperty); }
            set { SetValue(FirstNameProperty, value); }
        }
        // Using a DependencyProperty as the backing store for FirstName.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FirstNameProperty =
            DependencyProperty.Register("FirstName", typeof(string), typeof(Person), new PropertyMetadata(""));
        public string LastName
        {
            get { return (string)GetValue(LastNameProperty); }
            set { SetValue(LastNameProperty, value); }
        }
        // Using a DependencyProperty as the backing store for LastName.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty LastNameProperty =
            DependencyProperty.Register("LastName", typeof(string), typeof(Person), new PropertyMetadata(""));
    }

    На главной форме, добавим в конструктор создание объекта такого класса с помещением его в DataContext нашей страницы:

    <StackPanel Orientation="Horizontal" >
        <TextBlock Text="Передача объекта и Binding. Имя:" Margin="5" VerticalAlignment="Center" />
        <TextBlock Text="{Binding FirstName}" Margin="5" MinWidth="200" />
        <TextBlock Text="Фамилия:" Margin="5" VerticalAlignment="Center" />
        <TextBlock Text="{Binding LastName}" Margin="5" MinWidth="200" />
        <Button Content="Редактирование в отдельном окне" x:Name="btEdit" Click="btEdit_Click_1" />
    </StackPanel>

    Добавляем в проект страницу EditPage:

    <StackPanel Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <TextBlock Text="Имя:" Margin="5" />
        <TextBox Text="{Binding FirstName}" Margin="5" />
        <TextBlock Text="Фамилия:" Margin="5" />
        <TextBox Text="{Binding LastName}" Margin="5" />
        <Button Content="Назад" x:Name="btBack" Click="btBack_Click_1" />
    </StackPanel>

    В ее коде нам нудно только обработчик кнопки задать (GoBack) и присвоение переданного параметра в DataContext:

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        this.DataContext = e.Parameter;
    }

    Обратили внимание, что в рамках этой формы мы даже не знаем про класс Person? Все, осталось добавить передачу параметра при переходе по кнопке "Редактирование в отдельном окне":

    Person person = new Person() { FirstName = "Иван", LastName = "Иванов" };
    private void btEdit_Click_1(object sender, RoutedEventArgs e)
    {
        this.Frame.Navigate(typeof(EditPage), person);
    }

    Запускаем приложение и видим:

    Кликаем на кнопке и видим:

    Заменяем на Петр Петров, жмем "Назад" и увидим Иван Иванов.

    Да, да, вы не ошиблись, опять Иван Иванов. Привет наследие Silverlight, все поля по умолчанию используют тип биндинга: OneWay, придется заменить на TwoWay. Заменяем, запускаем, редактируем, возвращаемся... Не помогает. Придется на главную страницу не просто возвращаться с передачей параметра. На странице редактирования в обработчик кнопки пишем:

    private void btBack_Click_1(object sender, RoutedEventArgs e)
    {
        this.Frame.Navigate(typeof(MainPage), this.DataContext);
    }

    На главной форме в OnNavigateTo, добавляем перезапись DataContext:

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        if (e.Parameter != null)
        {
            this.DataContext = e.Parameter;
        }
    }

    Все, теперь будет Петр Петров.

    Источник: losev-al.blogspot.com

    • Перемещено Yubo. Zhang 14 сентября 2012 г. 9:13 (От:Приложения Windows в стиле Metro)
    9 июня 2012 г. 17:26
    Отвечающий

Все ответы

  • Четвертый пример, внутри класса public string FirstName { get { return (string)GetValue(FirstNameProperty); } set { SetValue(FirstNameProperty, value); } } Элемент getValue и SetValue не существуют в текущем контексте... Как исправить ошибку?
    3 июля 2012 г. 15:59
  • У вас класс потомок DependencyObject? Должно быть так:

    class Person : DependencyObject
    

    3 июля 2012 г. 16:01
    Отвечающий
  • Ошибка 1 Не удалось найти имя типа или пространства имен "DependencyObject" (пропущена директива using или ссылка на сборку?) C:\Users\Erkebulan\Documents\Visual Studio 2012\Projects\App4\App4\Person.cs 9 20 App4


    3 июля 2012 г. 16:12
  • Вариантов решения два:

    1. Тыкнуть мышкой на DependencyObject. Слева, под именем типа появится синенький прямоугольничек, навести мышку на него, открыть меню и добавить через меню пространство имен:

    2. Прописать в начале файла, рядом с остальными вот такую строчку:

    using System.Windows;

    3 июля 2012 г. 16:42
    Отвечающий