Средства приложений вне браузера

198

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

В данной статье рассматриваются три таких исключения, применимых ко всем приложениям вне браузера, независимо от уровня доверительности. Сначала будет рассмотрен класс WebBrowser, позволяющий внедрить HTML-содержимое в приложение Silverlight. Затем будет изучен вывод сообщения в отдельном всплывающем окне. И наконец, мы перейдем к способам взаимодействия с главным окном приложения с целью изменения его позиции, размеров или состояния.

Элемент управления WebBrowser

В обычном приложении Silverlight можно использовать средства интеграции с браузером для взаимодействия с кодами HTML и JavaScript хостирующей страницы. Это означает, что приложение может изменять HTML-содержимое и вызывать функции JavaScript. Для приложения вне браузера ни одно из этих средств недоступно, потому что у него нет хостирующей веб-страницы, которую можно конфигурировать.

Для устранения этого потенциального недостатка в приложении вне браузера можно использовать элемент управления WebBrowser, который хостирует HTML-содержимое. Однако как средства взаимодействия с браузером применимы только в приложениях, выполняющихся в браузере, так и класс WebBrowser применим только в приложениях, выполняющихся вне браузера. Если вставить объект WebBrowser в обычное приложение Silverlight, отобразится пустой прямоугольник и сообщение о том, что WebBrowser не подключен.

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

Ниже показан пример использования элемента WebBrowser:

<Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <TextBox x:Name="txtUrl" Margin="5,5,1,5" Text="http://www.professorweb.ru"></TextBox>
        <Button Grid.Column="1" Click="cmdGo_Click" Content="Go" Margin="1,5,5,5"></Button>
        <Border Grid.Row="1" Grid.ColumnSpan="2" Margin="5" BorderBrush="Black" BorderThickness="1">
            <WebBrowser x:Name="browser"></WebBrowser>
        </Border>
</Grid>
private void cmdGo_Click(object sender, RoutedEventArgs e)
{
            try
            {
                browser.Navigate(new Uri(txtUrl.Text));
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message, err.GetType().Name, MessageBoxButton.OK);
            }
}
Использование класса WebBrowser

Отображение HTML-содержимого

При использовании класса WebBrowser задать отображаемое содержимое можно одним из трех способов.

Наиболее прямолинейный подход состоит в вызове метода NavigateToString() и передаче ему строки HTML-содержимого, которое нужно отобразить. Данный способ позволяет использовать WebBrowser для отображения любого статического содержимого, в том числе полученного от веб-службы. Обычно в строку вставляют полный HTML-документ, но можно вставлять также отдельные фрагменты разметки:

browser.NavigateToString(
     "<h1 style=\"color:red;\">Тестирование класса WebBrowser</h1>");

Второй подход — вызов метода Navigate() и передача ему полностью квалифицированного или относительного адреса URI, указывающего на содержимое, которое нужно отобразить, как показано в примере выше.

Третий подход состоит в присвоении свойству Source объекта WebBrowser полностью квалифицированного или относительного URI. В сущности, результат будет тем же, что и при вызове метода Navigate().

В методе Navigate() или свойстве Source нельзя использовать URI приложения. Иными словами, WebBrowser не может загрузить HTML-файл, который внедрен в файл ХАР. Впрочем, можно вручную обратиться к ресурсу, загрузить строку и вызвать метод NavigateToString().

Чтобы протестировать приложение Silverlight, которое загружает веб-страницы в WebBrowser, вы должны включить веб-сайт ASP.NET в решение. Данное требование не должно стать для вас неожиданностью, потому что оно встречается при использовании многих сетевых средств Silverlight, включая веб-службы и средства работы в сетях.

Класс WebBrowser подвержен некоторым неизбежным ограничениям. В отличие от средств взаимодействия с HTML, класс WebBrowser не представляет HTML-документ как коллекцию объектов HtmlElement, поэтому не существует программных способов анализа структуры документа. Однако в любой момент можно получить весь HTML-документ как строку путем вызова метода WebBrowser.SaveToString().

Кисть WebBrowserBrush

Класс WebBrowser не интегрирован в систему визуализации Silverlight. Из-за этого невозможно, например, применить эффекты раскрашивания пикселей или процедуры преобразования для изменения внешнего вида веб-страницы.

Однако Silverlight предоставляет удобный трюк для разработчиков, которым это необходимо. Визуальное содержимое окна WebBrowser можно вывести в другой элемент (например, Rectangle) путем его прорисовки с помощью кисти WebBrowserBrush. Рассмотрим пример, в котором элементы WebBrowser и Rectangle размещены в одной ячейке контейнера Grid. Объект Rectangle находится сверху, но сквозь него видно содержимое окна WebBrowser:

<Grid>
      <WebBrowser x:Name="browser" Source="http://www.professorweb.ru"/>
      <Rectangle>
            <Rectangle.Fill>
                  <WebBrowserBrush SourceName="browser"/>
            </Rectangle.Fill>
      </Rectangle>
</Grid>

Единственное ограничение состоит в том, что нарисованная копия содержимого не может быть интерактивной для пользователя. Например, если нарисовать в объекте Rectangle что-нибудь с помощью кисти WebBrowserBrush, пользователь не сможет прокручивать страницу или щелкнуть на гиперссылке.

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

Взаимодействие с кодом JavaScript

Этот метод используется редко, но все же полезно знать о нем. С помощью элемента управления WebBrowser можно обеспечить взаимодействие приложения Silverlight с кодом JavaScript. Для вызова функции JavaScript, приведенной в текущем загруженном HTML-документе, можно применить метод InvokeScript():

browser.InvokeScript("MyJavaScriptFunction");

Через необязательный второй параметр метод InvokeScript() может принимать массив строковых значений, которое он передает функции. Кроме того, метод возвращает значение функции JavaScript как собственное возвращаемое значение:

object result = browser.InvokeScript("MyJavaScriptFunction", 
                                      new String[] {"1", "2"});

Для реагирования на функцию JavaScript можно обработать событие WebBrowser.ScriptNotify. Оно генерируется, когда код JavaScript вызывает функцию window.external.notify().

Окна уведомлений

Окно уведомления отображается в нижнем правом углу экрана, аналогично всплывающим окнам программы Outlook, извещающим о входящих письмах, или программы Messenger, извещающим о новых экземплярах сообщений. В операционной системе Mac окна уведомлений появляются в верхней части экрана.

В Silverlight базовое окно уведомления представляет собой ничем не примечательный пустой прямоугольник размером 400x100 пикселей. Его размеры можно уменьшить, но не увеличить. Для отображения окна уведомлений нужно создать экземпляр класса NotificationWindow. Чтобы поместить в это окно содержимое, нужно всего лишь присвоить его свойству Content.

Если нужно, чтобы окно уведомления содержало что-то более сложное, чем объект TextBlock, создайте для его содержимого пользовательский элемент управления. После этого присвойте его экземпляр свойству NotificationWindow.Content. В приведенном ниже примере в качестве содержимого окна уведомления применяется контейнер Grid, состоящий из двух строк. В верхней строке находится строка заголовка, а в нижней — элемент TextBlock, отображающий сообщения, получаемые от приложения. Элемент TextBlock отображается на фоне многоцветного градиента:

<UserControl x:Class="OutOfBrowser.NotificationControl"
    ...>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>

        <Border Background="LightGray" Height="20">
            <TextBlock Margin="3" FontSize="10" Text="Уведомление от приложения"></TextBlock>
        </Border>

        <Border Grid.Row="1">
            <Border.Background>
                <LinearGradientBrush>
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Color="DarkOrange"></GradientStop>
                        <GradientStop Color="Crimson" Offset="0.3"></GradientStop>
                        <GradientStop Color="DeepPink" Offset="0.5"></GradientStop>
                        <GradientStop Color="DarkOrange" Offset="0.7"></GradientStop>
                        <GradientStop Color="Crimson" Offset="1"></GradientStop>
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
            </Border.Background>
            <TextBlock x:Name="lblMessage" Margin="10" FontWeight="Bold" FontSize="16" Foreground="White" TextWrapping="Wrap"
                   HorizontalAlignment="Center" VerticalAlignment="Center">Здесь находится уведомление.</TextBlock>
        </Border>
    </Grid>
</UserControl>

Ниже приведен код установки TextBlock в NotificationControl посредством свойства Message:

public string Message
{
            get
            {
                return lblMessage.Text;
            }
            set
            {
                lblMessage.Text = value;
            }
}

Для отображения окна уведомлений нужно создать экземпляр класса NotificationControl, поместить его в экземпляр класса NotificationWindow, предоставленного инфраструктурой, и вызвать метод NotificationWindow.Show(), который выводит уведомление:

private NotificationWindow window = new NotificationWindow();
private void cmdGo_Click(object sender, RoutedEventArgs e)
{
     if (Application.Current.HasElevatedPermissions)
     {
         NotificationControl notification = new NotificationControl();
         notification.Message = "Новое уведомление от приложения. Время получения "
             + DateTime.Now.ToLongTimeString() + ".";
         window.Content = notification;

         window.Close();
         window.Show(5000);
     }
     else
     {
         MessageBox.Show("Эта функция недоступна, если вы работаете в браузере с низким доверием.");
     }
}
 Пользовательское окно уведомления

Пользователь не может перемещать окно уведомления. Однако можно добавить в окно уведомления кнопку, вызывающую метод NotificationWindow.Close(), который закроет окно до истечения срока его существования.

В данном примере предполагается, что используется стандартная ширина окна уведомления (400x100 пикселей). Чтобы сделать окно меньше, нужно жестко закодировать свойства Width и Height пользовательского элемента управления. Затем, при создании экземпляра NotificationWindow, извлеките значения Width и Height пользовательского элемента управления и присвойте их экземпляру NotificationWindow. Тогда при редактировании пользовательского элемента управления вы будете видеть реальное окно уведомления и сможете изменить его размеры в любой момент, изменив для этого лишь один файл — файл разметки XAML пользовательского элемента управления.

Управление главным окном

Обычное приложение Silverlight выполняется в окне браузера. Реализовать взаимодействие с окном можно только посредством кода JavaScript. Однако в приложении, выполняющемся вне браузера, используется отдельное окно. С ним можно взаимодействовать как с объектом Window посредством статического свойства Application.MainWindow.

Класс Window предоставляет небольшой набор свойств, приведенных в таблице ниже. Читать значения этих свойств можно в любой момент. Можно также изменять большинство из них (за исключением свойств Тор и Left, которые обязательно должны быть установлены в обработчике Application.Startup) в ответ на события, инициированные пользователем, и в обработчике события Application.Startup.

Свойства класса Window
Свойство Описание
Height и Width Размеры главного окна в пикселях. Присвоить значения этим свойствам можно в обработчике события Application.Startup или в ответ на событие, инициированное пользователем
Тор и Left Расстояние между краями окна и экрана в пикселях. Присвоить значения этим свойствам можно только в обработчике события Application.Startup и только если начальные координаты запуска были заданы в окне Out-of-Browser Settings (Параметры приложения вне браузера)
WindowState Содержит значения типа перечисления WindowState. Возможные значения: Normal (Обычное), Minimized (Свернутое) и Maximised (Развернутое). Присвоить значение этому свойству можно в обработчике события Application.Startup или в ответ на событие, инициированное пользователем
TopMost Если это свойство равно true, окно всегда видимое (т.е. отображается поверх окон всех других приложений). Присвоить значение этому свойству можно в обработчике события Application.Startup или в ответ на событие, инициированное пользователем

Наилучший способ установки начальных размеров и позиции главного окна состоит в использовании окна Out-of-Browser Settings. Свойства объекта Window полезны, когда нужно изменять размеры динамически во время выполнения, например для того, чтобы адаптировать размеры окна к размерам содержимого.

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

// App.xaml.cs
using System.IO;
using System.IO.IsolatedStorage;
...

   private void Application_Startup(object sender, StartupEventArgs e)
   {
            try
            {
                IsolatedStorageFile store =
                  IsolatedStorageFile.GetUserStoreForApplication();

                if (store.FileExists("window.Settings"))
                {
                    using (IsolatedStorageFileStream fs = store.OpenFile("window.Settings", FileMode.Open))
                    {
                        BinaryReader r = new BinaryReader(fs);
                        Application.Current.MainWindow.Top = r.ReadDouble();
                        Application.Current.MainWindow.Left = r.ReadDouble();
                        Application.Current.MainWindow.Width = r.ReadDouble();
                        Application.Current.MainWindow.Height = r.ReadDouble();
                        r.Close();
                    }
                }
            }
            catch
            {
                // Восстановить параметры окна невозможно
                // сообщать об ошибке нет необходимости
            }
            this.RootVisual = new MainPage();
   }

   private void Application_Exit(object sender, EventArgs e)
   {
            if (Application.Current.IsRunningOutOfBrowser)
            {
                // Сохранение состояния окна          
                try
                {
                    IsolatedStorageFile store =
                      IsolatedStorageFile.GetUserStoreForApplication();

                    using (IsolatedStorageFileStream fs = store.CreateFile("window.Settings"))
                    {
                        BinaryWriter w = new BinaryWriter(fs);
                        w.Write(Application.Current.MainWindow.Top);
                        w.Write(Application.Current.MainWindow.Left);
                        w.Write(Application.Current.MainWindow.Width);
                        w.Write(Application.Current.MainWindow.Height);
                        w.Close();
                    }
                }
                catch
                {
                    // Сохранить параметры окна невозможно
                    // сообщать об ошибке нет необходимости
                }
            }
   }

Не забывайте, что для того, чтобы можно было устанавливать свойства Тор и Left главного окна, в окне Out-of-Browser Settings (Параметры приложения вне браузера) должен быть установлен флажок Set window location manually (Устанавливать положение окна вручную).

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

Кроме рассмотренных выше свойств, класс Window предоставляет небольшой набор методов. Наиболее полезным является метод Close(), который закрывает главное окно (в ответ на действие, инициированное пользователем). Методы DragMove(), DragResize(), Activate() и ряд других предназначены для приложений с повышенной доверительностью. Эти методы особенно полезны при создании настраиваемого фрейма.

Пройди тесты
Лучший чат для C# программистов