Опубликован: 11.01.2013 | Доступ: свободный | Студентов: 623 / 124 | Длительность: 12:06:00
Лекция 3:

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

< Лекция 2 || Лекция 3: 12345 || Лекция 4 >

Лабораторная работа №8. Веб-браузер

Задание

Создать простой веб-браузер для Windows Phone 7 с адресной строкой, историей посещений и сохранением истории в изолированном хранилище.

Освоение

  • элемент управления WebBrowser
  • изолированное хранилище

Описание

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

Откроем файл разметки главной страницы MainPage.xaml. Добавим текстовое поле (для адресной строки), кнопку (при нажатии на нее будет происходить переход) и элемент WebBrowser. Обратите внимание, что браузер находится в пространстве имен "phone", т.о. не требуется подключение дополнительных библиотек. В меню добавим 3 кнопки для навигации по истории (вперед, назад и просмотр). При нажатии на кнопку просмотра истории будем переходить на другую страницу, где в списке будем выводить посещенные страницы.

Полностью разметка главной страницы примет следующий вид:

 <phone:PhoneApplicationPage 
    x:Class="Wp7IUSLab11.HistoryPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="696" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True">

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

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="ОБОЗРЕВАТЕЛЬ (история)" 
            Style="{StaticResource PhoneTextNormalStyle}"/>
            <!--TextBlock x:Name="PageTitle" Text="page name" Margin="9,-7,0,0" 
            Style="{StaticResource PhoneTextTitle1Style}"/-->
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <ListBox Name="lstHistory">
                
            </ListBox>
        </Grid>
    </Grid>
 
    <!--Sample code showing usage of ApplicationBar-->
    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/Images/appbar.back.rest.png" 
            Text="назад" Click="Menu1_Click" />
            <shell:ApplicationBarIconButton IconUri="/Images/appbar.cancel.rest.png" 
            Text="очистить" Click="Menu2_Click" />
            <shell:ApplicationBarIconButton IconUri="/Images/appbar.next.rest.png" 
            Text="перейти" Click="Menu3_Click" />
            
            <!--shell:ApplicationBar.MenuItems>
                <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
            </shell:ApplicationBar.MenuItems-->
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>

</phone:PhoneApplicationPage>

Разметка второй страницы будет состоять только из пустого списка (мы будем заполнять его динамически в коде страницы). Меню будет состоять из 3 кнопок (назад, перейти по выделенной ссылке и очистить историю).

 <phone:PhoneApplicationPage 
    x:Class="Wp7IUSLab11.HistoryPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    mc:Ignorable="d" d:DesignHeight="696" d:DesignWidth="480"
    shell:SystemTray.IsVisible="True">

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

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="ОБОЗРЕВАТЕЛЬ (история)" 
            Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="page name" Margin="9,-7,0,0" 
            Style="{StaticResource PhoneTextTitle1Style}"/-->
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <ListBox Name="lstHistory" />
        </Grid>
    </Grid>
 
    <!--Sample code showing usage of ApplicationBar-->
    <phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/Images/appbar.back.rest.png" 
            Text="назад" Click="Menu1_Click" />
            <shell:ApplicationBarIconButton IconUri="/Images/appbar.cancel.rest.png" 
            Text="очистить" Click="Menu2_Click" />
            <shell:ApplicationBarIconButton IconUri="/Images/appbar.next.rest.png" 
            Text="перейти" Click="Menu3_Click" />
            
            <!--shell:ApplicationBar.MenuItems>
                <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
            </shell:ApplicationBar.MenuItems-->
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>

</phone:PhoneApplicationPage>

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

 public static class History
    {
        public static List<Uri> listHistory;
        public static int nCurHistoryPos;

        public static void Init()
        {
            listHistory = new List<Uri>();
            nCurHistoryPos = 0;
        }

        public static string ListToString()
        {
            string strRes = "";

            for (int i = 0; i < listHistory.Count; i++)
            {
                if (i != 0)
                {
                    strRes += "|";
                }

                strRes += listHistory[i].ToString();
            }

            return strRes;
        }

        public static void StringToList(string strHist)
        {
            string[] strMas = strHist.Split( '|');

            for (int i = 0; i < strMas.GetLength(0); i++)
            {
                listHistory.Add(new Uri(strMas[i]));
            }
        }
    }

Вернемся к файлу MainPage.xaml.cs. При нажатии на кнопку btnRun будем осуществлять загрузку в браузере страницы, адрес которой указан в текстовом поле. При этом в случае если ссылка не содержит "http://", то его обязательно будем добавлять:

 private void btnRun_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                //убираем пробелы и приводим к нижнему регистру
                txtAddress.Text = txtAddress.Text.Trim().ToLower();

                //добавляем, если надо, "http://"
                if (txtAddress.Text.Length < 7)
                {
                    txtAddress.Text = "http://" + txtAddress.Text;
                }
                else
                {
                    if (!txtAddress.Text.Substring(0, 7).Equals("http://"))
                    {
                        txtAddress.Text = "http://" + txtAddress.Text;
                    }
                }

                //переходим
                Uri url = new Uri(txtAddress.Text);
                wBrowser.Navigate(url);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

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

private void wBrowser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
        {
            //если мы движемся не по истории
            if (!bHistoryNavigate)
            {
                if (History.listHistory.Count > 0)
                {
                    //в случае, если бродили по истории - подтираем ее до текущей позиции
                    History.listHistory.RemoveRange(0, History.nCurHistoryPos);

                    if (!History.listHistory[0].Equals(wBrowser.Source))
                    {
                        AddToHistoryUri();
                    }
                }
                else
                {
                    AddToHistoryUri();
                }
            }
            else
            {
                //устанавливаем флаг назад в фолс
                bHistoryNavigate = false;
            }

            txtAddress.Text = wBrowser.Source.AbsoluteUri;
        }

При добавлении ссылки в историю будем сохранять всю историю в изолированном хранилище:

private void AddToHistoryUri()
        {
            if (History.listHistory.Count >= MAX_HISTORY_LEN)
            {
                History.listHistory.RemoveAt(History.listHistory.Count - 1);
            }

            History.listHistory.Insert(0, wBrowser.Source);

            string strHistoryText = History.ListToString();
            SaveToIsolatedStorage(strHistoryText);
        }

Создадим константу для хранения имени файла, в который будем сохранять историю:

private const string strIStorageName = "Wp7IUSLab11.txt";

В конструкторе класса будем загружать историю из изолированного хранилища - файла (в случае, если файл существует):

// Constructor
        public MainPage()
        {
            InitializeComponent();

            History.Init();

            if (IsIsolatedStorageExist())
            {
                string strText = LoadFromIsolatedStorage();
                History.StringToList(strText);

                if (History.listHistory.Count > 0)
                {
                    txtAddress.Text = "идет загрузка...";
                    wBrowser.Navigate(History.listHistory[0]);
                }
            }
        }

        private void SaveToIsolatedStorage(string histText)
        {
            IsolatedStorageFile fileStorage = IsolatedStorageFile.GetUserStoreForApplication();
            IsolatedStorageFileStream fileStream = fileStorage.CreateFile(strIStorageName);

            StreamWriter sw = new StreamWriter(fileStream);
            sw.Write(histText);
            sw.Close();

            fileStream.Close();
        }

        private string LoadFromIsolatedStorage()
        {
            IsolatedStorageFile fileStorage = IsolatedStorageFile.GetUserStoreForApplication();
            IsolatedStorageFileStream fileStream = fileStorage.OpenFile(strIStorageName, System.IO.FileMode.Open);

            StreamReader sr = new StreamReader(fileStream);
            string strRes = sr.ReadToEnd();
            sr.Close();
            fileStream.Close();

            return strRes;
        }

        private bool IsIsolatedStorageExist()
        {
            IsolatedStorageFile sileStorage = IsolatedStorageFile.GetUserStoreForApplication();
            return sileStorage.FileExists(strIStorageName);
        }

        private void RemoveIsolatedStorage()
        {
            if (IsIsolatedStorageExist())
            {
                IsolatedStorageFile fileStorage = IsolatedStorageFile.GetUserStoreForApplication();
                fileStorage.DeleteFile(strIStorageName);
            }
        }

Для работы с изолированным хранилищем в код необходимо добавить директивы:

using System.IO.IsolatedStorage;
using System.IO;

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

protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            if (NavigationContext.QueryString.ContainsKey("hist"))
            {
                History.nCurHistoryPos = int.Parse(NavigationContext.QueryString["hist"].ToString());
                bHistoryNavigate = true;
                wBrowser.Navigate(History.listHistory[History.nCurHistoryPos]);
            }
            else
            {
                if (0 == History.listHistory.Count)
                {
                    RemoveIsolatedStorage();
                }
            }
        }

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

< Лекция 2 || Лекция 3: 12345 || Лекция 4 >