Модель приложения

74

Любая страница XAML является шаблоном пользовательского класса, производного от System.Windows.UserControl. Аналогично этому файл App.xaml тоже является шаблоном пользовательского класса (по умолчанию он имеет имя App), производного от System.Windows.Application. Определение класса находится в файле App.xaml.cs:

public partial class App : Application 
{ ... }

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

Доступ к текущему приложению

Ссылку на объект приложения можно извлечь в любой момент времени в любой точке кода с помощью статического свойства Application.Current. Это свойство имеет тип объекта приложения System.Windows.Application. Для обращения к любому пользовательскому свойству или методу, принадлежащему производному классу приложения, необходимо привести ссылку к типу App.

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

Свойства приложения

Кроме упомянутого выше статического свойства Current, класс Application предоставляет ряд полезных свойств и методов, описанных в таблице ниже:

Свойства и методы класса Application
Имя Описание
Host Предоставляет возможность интерактивного взаимодействия с браузером и через него — с HTML-содержимым веб-страницы
Resources Доступ к коллекции ресурсов XAML, объявленных в файле App.xaml
RootVisual Доступ к корневому визуальному элементу приложения. Обычно им служит пользовательский элемент управления, создаваемый при первом запуске приложения. После установки свойства RootVisual корневой визуальный элемент не может быть изменен, однако можно манипулировать его содержимым, что позволяет управлять выводом страницы. Например, если корневым элементом служит объект Grid, можно удалить из него один или несколько дочерних элементов, добавив вместо них другие элементы управления
IsRunningOutOfBrowser и InstallState Эти свойства позволяют распознавать приложения, выполняющиеся за пределами браузера, и управлять ими. Булево свойство IsRunningOutOfBrowser сообщает, где выполняется приложение — за пределами браузера (значение true) или в окне браузера (значение false). Свойство InstallState предоставляет элемент перечисления InstallState: значение Installed означает, что приложение установлено на текущем компьютере, NotInstalled или InstallFailed — не установлено, Installing — в данный момент выполняется установка
ApplicationLifetimeObjects Коллекция служб расширения приложения. Объекты коллекции предоставляют дополнительные способы реакции на события приложения, аналогично обработчикам событий в коде класса Application. Разница между ними в том, что коды служб расширения помещены в отдельный класс; это облегчает повторное использование кода в других приложениях Silverlight
Install() и CheckAndDownloadUpdateAsync() Эти методы используются в приложениях, выполняющихся за пределами браузера. Метод Install() устанавливает текущее приложение Silverlight на клиентском компьютере; метод CheckAndDownloadUpdateAsync() запускает асинхронный процесс, проверяющий веб-службу обновлений. Если обновленная версия найдена, она загружается и применяется при следующем запуске приложения
GetResourceStream() Статический метод, используемый для извлечения ресурсов
LoadComponent() Статический метод, принимающий файл XAML и создающий экземпляры соответствующих элементов (эти операции Silverlight выполняет автоматически при создании класса страницы и вызове метода InitializeComponent() конструктором страницы)

Кроме предоставления перечисленных свойств, объект Application генерирует события в разные моменты жизненного цикла приложения.

События приложения

Ниже приведен краткий обзор этапов, из которых состоит сеанс приложения:

  1. Пользователь запрашивает входную страницу HTML.

  2. Загружается надстройка Silverlight, которая загружает файл ХАР приложения.

  3. Надстройка Silverlight извлекает из архива ХАР файл AppManifest.xml, чтобы выяснить, какие сборки используются в приложении. Затем надстройка создает среду времени выполнения и загружает сборку приложения и все зависимые файлы и сборки.

  4. Надстройка Silverlight создает экземпляр пользовательского класса приложения, определенного в файлах App.xaml и App.xaml.cs

  5. Установленный по умолчанию конструктор класса приложения генерирует событие Startup.

  6. Приложение обрабатывает событие Startup и создает пользовательский интерфейс.

С этого момента начинает выполняться код приложения. Код выполняется, пока не произойдет необработанная ошибка UnhandledException или событие завершения приложения Exit. Класс приложения Application предоставляет три базовых события: Startup, UnhandledException и Exit. Кроме того, класс Application поддерживает события InstallStateChanged и CheckAndDownloadUpdateCompleted, используемые в приложениях, которые выполняются за пределами браузера.

Программа Visual Studio добавляет в конструктор приложения приведенный ниже код, который подключает обработчики ко всем трем событиям приложения:

public App()
{
         this.Startup += this.Application_Startup;
         this.Exit += this.Application_Exit;
         this.UnhandledException += this.Application_UnhandledException;

         InitializeComponent();
}

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

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

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

Запуск приложения

По умолчанию обработчик Application_Startup создает первую страницу и устанавливает ее свойство Application.RootVisual, создавая таким образом элемент верхнего уровня приложения (визуальный корневой элемент):

private void Application_Startup(object sender, StartupEventArgs e)
{
      this.RootVisual = new MainPage();
}

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

Инициализационные параметры

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

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

Предположим, нужно передать приложению параметр ViewMode, содержащий перечисление значений Customer (Клиент) и Employee (Сотрудник). На основе переданной информации можно изменить поведение приложения. Поэтому имеет смысл хранить ее в месте, доступном в любой точке кода. Логично будет добавить для этого свойство в пользовательский класс приложения:

public enum ViewMode
{
    Customer, Employee
}

public partial class App : Application
{
    private ViewMode viewMode = ViewMode.Customer;
    public ViewMode ViewMode
    {
        get { return viewMode; }
    }
  ...

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

Для передачи параметра в приложение Silverlight нужно добавить элемент <param> в разметку области содержимого Silverlight. Элемент <param> должен называться initParams. Его значением служит список пар "имя-значение", разделенный запятыми. Например, для добавления параметра viewMode можно добавить следующую разметку:

<div id="silverlightControlHost">
        <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" 
        width="100%" height="100%">
		  <param name="source" value="SilverlightTest.xap"/>
		  <param name="onError" value="onSilverlightError" />
		  <param name="background" value="white" />
		  <param name="minRuntimeVersion" value="5.0.61118.0" />
		  <param name="autoUpgrade" value="true" />
          <param name="initParams" value="viewMode=Customer" />
          ...

После этого параметр можно извлечь из коллекции StartupEventArgs.InitParams, но сначала нужно проверить, существует ли параметр:

private void Application_Startup(object sender, StartupEventArgs e)
{
            // Проверка существования и сохранения параметра
            // в свойстве приложения
            if (e.InitParams.ContainsKey("viewMode"))
            {
                string view = e.InitParams["viewMode"];
                if (view == "Employee")
                    this.viewMode = ViewMode.Employee;
            }
            this.RootVisual = new MainPage();
}

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

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

txtInfo.Text = "Текущий режим приложения: " +
     (Application.Current as App).ViewMode.ToString();
Вывод иниииализационноео параметра

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

<param name="initParams" value="startPage=SomePage, viewMode=Customer" />

Обработчик события Startup может извлечь значение StartPage и применить его для выбора корневой страницы приложения.

Необработанные исключения

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

Событие Application.UnhandledException предоставляет последний шанс отреагировать на исключение прежде, чем оно достигнет надстройки Silverlight и приведет к закрытию приложения. Код обработки этого события существенно отличается от кода JavaScript, добавляемого на страницу, потому что он имеет возможность отметить исключение как обработанное. Использование этого метода позволяет эффективно нейтрализовать исключение.

Приведенный ниже код проверяет тип исключения и решает, позволить ли приложению продолжить выполнение:

private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
      if (e.ExceptionObject is System.IO.FileNotFoundException)
      {
         // Подавление исключения и разрешение приложению продолжить выполнение
         e.Handled = true;
      }
}

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

О необходимости изменить обработчик ошибки Application.UnhandledException легко забыть, потому что он подключается, только когда приложение Silverlight выполняется без отладчика. При тестировании приложения в среде Visual Studio обработчик не вызывается, а необработанное исключение немедленно завершает приложение.

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