Приложение одного экземпляра

34

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

Например, рассмотрим текстовый процессор Microsoft Word. Независимо от того, сколько документов открывается (и как они открываются), в каждый момент времени загружен только единственный экземпляр winword.exe. При открытии новых документов они появляются в новых окнах, но всеми окнами документов управляет единственное приложение. Такое решение представляет собой наилучший подход, когда требуется сократить накладные расходы, связанные с работой приложения, централизовать определенные средства (например, создать единый диспетчер очереди печати) либо интегрировать разнородные окна (например, предоставить средство, которое упорядочит все текущие открытые окна документов, расположив их рядом друг с другом).

В WPF не предусмотрено встроенного решения для приложений одного экземпляра, но можно воспользоваться несколькими обходными маневрами. Базовый прием заключается в проверке существования другого запущенного экземпляра приложения при возникновении события Application.Startup. Простейший путь сделать это состоит в использовании системного мьютекса (объекта синхронизации, предоставляемого операционной системой, позволяющей межпроцессное взаимодействие).

Этот подход прост, но ограничен — важнее всего то, что при этом не существует возможности взаимодействия нового экземпляра приложения с уже существующим. Это становится проблемой для приложений, основанных на документах, потому что новому экземпляру может понадобиться сообщить существующему экземпляру о необходимости открытия определенного документа, если он передан в командной строке. (Например, двойной щелчок на файле .doc в проводнике Windows при запущенном приложении Word должен приводить к загрузке в Word этого файла.) Это взаимодействие более сложно и обычно осуществляется через технологию Remoting или Windows Communication Foundation (WCF). Корректная реализация требует включения способа обнаружения удаленного сервера и его использования для передачи аргументов командной строки.

Однако простейший подход, рекомендованный для WPF, предусматривает применение встроенной поддержки, которая предоставляется в Windows Forms, и изначально предназначалась для приложений Visual Basic. Этот подход обрабатывает все запутанные детали "за кулисами".

Итак, каким образом можно воспользоваться средством, предназначенным для Windows Forms и Visual Basic, при управлении приложением WPF на C#? По сути, класс приложения старого стиля служит оболочкой для класса приложения WPF. Во время запуска приложения создается экземпляр класса приложения старого стиля, который затем создаст экземпляр класса приложения WPF. Класс приложения старого стиля занимается управлением экземплярами, в то время как класс приложения WPF обслуживает реальное приложение. На рисунке показано взаимодействие этих частей:

Упаковка приложения WPF в оболочку WindowsFormsApplicationBase

Создание оболочки для приложения одного экземпляра

Первый шаг заключается в добавлении ссылки на сборку Microsoft.VisualBasic.dll и наследовании специального класса от класса Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase. В этом классе определены три важных члена, которые используются для управления экземплярами:

Свойство IsSingleInstance

Позволяет создать приложение одного экземпляра. Это свойство устанавливается в true в конструкторе.

Метод OnStartup()

Инициируется при старте приложения. Этот метод переопределяется и в данной точке создается объект приложения WPF.

Метод OnStartupNextInstance()

Инициируется при запуске другого экземпляра приложения. Этот метод обеспечивает доступ к аргументам командной строки. В данной точке, скорее всего, будет вызван метод класса приложения WPF, чтобы отобразить новое окно, не создавая другого объекта приложения.

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