Использование Caliburn в WP7 UserControl вызывает исключение

Я пытаюсь создать UserControl для приложения Windows Phone, используя Caliburn Micro внутри элемента управления. Загрузчик обычно настраивается в ресурсах приложения.

  <Application.Resources>
     <local:AppBootstrapper x:Key="bootstrapper" />
  </Application.Resources>

Я пытаюсь сделать это в Xaml пользовательского элемента управления.

 <UserControl.Resources>
     <local:AppBootstrapper x:Key="bootstrapper" />
 </UserControl.Resources>

Но это вызывает исключение во время инициализации, когда компонент загружен. Вызов LoadComponent вызывает исключение: «Первое случайное исключение типа 'System.InvalidOperationException' произошло в Microsoft.Phone.ni.dll»

Где и когда следует инициализировать загрузчик?


person Frank    schedule 19.12.2012    source источник


Ответы (2)


Он не предназначен для использования в ресурсах UserControl, поэтому я не могу гарантировать хорошее или плохое поведение. Загрузчик следует использовать в ресурсах приложения, или вы можете создать его экземпляр непосредственно в коде. Попробуйте создать его в ctor пользовательского элемента управления сразу после вызова InitializeComponent.

person EisenbergEffect    schedule 19.12.2012
comment
Я попробовал AppBootstrapper bootstrapper = new AppBootstrapper (); в событии Loaded элемента управления, но вызывает то же исключение. - person Frank; 19.12.2012
comment
Какое внутреннее исключение? Что говорит нижняя часть стека исключений? - person Charleh; 19.12.2012
comment
Исключение: System.InvalidOperationException: создание нескольких экземпляров PhoneApplicationService не поддерживается. \ R \ n в Microsoft.Phone.Shell.PhoneApplicationService..ctor () \ r \ n в Caliburn.Micro.PhoneBootstrapper.PrepareApplication () \ r \ n в Caliburn.Micro.BootstrapperBase.StartRuntime () \ r \ n в Caliburn.Micro.BootstrapperBase.Start () \ r \ n в Caliburn.Micro.Bootstrapper..ctor (Boolean useApplication) \ r \ n в Caliburn.Micro .PhoneBootstrapper..ctor () \ r \ n в CloudStorage.AppBootstrapper..ctor () \ r \ n в CloudStorage.UIControl.UI_Loaded (отправитель объекта, RoutedEventArgs e) - person Frank; 19.12.2012

Поскольку вы размещаете загрузчик в UserControl, кажется, что PhoneApplicationService, вероятно, уже создан - пробовали ли вы поместить загрузчик в раздел ресурсов приложения?

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

Есть ли причина, по которой вы не можете использовать ускоритель стандартным способом (в ресурсах приложения)? Содержит ли ваш App.xaml инициализатор для PhoneApplicationService?

Редактировать:

Источник CM, в котором возникает ошибка, находится в PrepareApplication. например

protected override void PrepareApplication() {
        base.PrepareApplication();

            phoneService = new PhoneApplicationService();
            phoneService.Activated += OnActivate;
            phoneService.Deactivated += OnDeactivate;
            phoneService.Launching += OnLaunch;
            phoneService.Closing += OnClose;

            Application.ApplicationLifetimeObjects.Add(phoneService);

            if (phoneApplicationInitialized) {
                return;
            }

            RootFrame = CreatePhoneApplicationFrame();
            RootFrame.Navigated += OnNavigated;

            phoneApplicationInitialized = true;
        }

Вероятно, вы могли бы просто создать подкласс этого и избежать создания нового PhoneApplicationService, а повторно использовать существующий:

    /// <summary>
    /// A custom bootstrapper designed to setup phone applications.
    /// </summary>
    public class CustomPhoneBootstrapper : Bootstrapper {
    bool phoneApplicationInitialized;
    PhoneApplicationService phoneService;

    /// <summary>
    /// The root frame used for navigation.
    /// </summary>
    public PhoneApplicationFrame RootFrame { get; private set; }

    /// <summary>
    /// Provides an opportunity to hook into the application object.
    /// </summary>
    protected override void PrepareApplication(PhoneApplicationService phoneAppService, PhoneApplicationFrame rootFrame) {
        base.PrepareApplication();

        phoneService = phoneAppService;
        phoneService.Activated += OnActivate;
        phoneService.Deactivated += OnDeactivate;
        phoneService.Launching += OnLaunch;
        phoneService.Closing += OnClose;

        Application.ApplicationLifetimeObjects.Add(phoneService);

        if (phoneApplicationInitialized) {
            return;
        }

        RootFrame = rootFrame;
        RootFrame.Navigated += OnNavigated;

        phoneApplicationInitialized = true;
    }

    void OnNavigated(object sender, NavigationEventArgs e) {
        if (Application.RootVisual != RootFrame) {
            Application.RootVisual = RootFrame;
        }
    }

    /// <summary>
    /// Occurs when a fresh instance of the application is launching.
    /// </summary>
    protected virtual void OnLaunch(object sender, LaunchingEventArgs e) { }

    /// <summary>
    /// Occurs when a previously tombstoned or paused application is resurrected/resumed.
    /// </summary>
    protected virtual void OnActivate(object sender, ActivatedEventArgs e) { }

    /// <summary>
    /// Occurs when the application is being tombstoned or paused.
    /// </summary>
    protected virtual void OnDeactivate(object sender, DeactivatedEventArgs e) { }

    /// <summary>
    /// Occurs when the application is closing.
    /// </summary>
    protected virtual void OnClose(object sender, ClosingEventArgs e) { }
}

Отказ от ответственности: не уверен, что что-то из этого сработает, поскольку я никогда не разрабатывал для Windows Phone, но, насколько я понимаю, это должно делать то же, что и исходный загрузчик, но пропустить создание приложения и корневого фрейма. Вам просто нужно предоставить приложение и корневой фрейм (или, может быть, только приложение, если вы можете получить корневой фрейм из объекта приложения - как я уже сказал, понятия не имею, что возможно)

person Charleh    schedule 20.12.2012
comment
В приложении WP7 пользовательский элемент управления не имеет app.xaml. И я не могу поместить загрузчик в приложение, потому что пользовательский элемент управления не должен зависеть от приложений, которые его используют. Обычно у приложений есть PhoneApplicationService самостоятельно. Полагаю, это не сработает? - person Frank; 20.12.2012
comment
Все, что делает Boostrapper, - это инициализирует ваше приложение - если вам не нужно инициализировать приложение, может быть другой способ заставить CM применить его соглашения к вашему UC, не пытаясь повторно инициализировать приложение. Самый простой способ - это DL-источник CM и внести в код небольшую модификацию. Я опубликую подробности в своем ответе - person Charleh; 20.12.2012
comment
Я добавил ответ - поскольку PhoneBootstrapper является общедоступным, вы можете просто подклассифицировать его и немного изменить то, что происходит (вместо создания нового класса PhoneApp, просто используйте существующий и позвольте CM выполнять свои перехватчики и т. Д.). Я не уверен насчет ссылки Frame, но попробуйте - person Charleh; 20.12.2012