Caliburn Micro: как перемещаться в Windows phone silverlight

Я пытаюсь использовать Caliburn Micro в своем проекте Windows Phone 7. Но я получил исключение nullreferenceException при навигации по странице.

namespace Caliburn.Micro.HelloWP7 {
    public class MainPageViewModel {
        readonly INavigationService navigationService;

        public MainPageViewModel(INavigationService navigationService) {
            this.navigationService = navigationService;
        }

        public void GotoPageTwo() {
            /*navigationService.UriFor<PivotPageViewModel>()
                .WithParam(x => x.NumberOfTabs, 5)
                .Navigate();*/
            navigationService.UriFor<Page1ViewModel>().Navigate();
        }
    }
}

namespace Caliburn.Micro.HelloWP7
{
    public class Page1ViewModel
    {
         readonly INavigationService navigationService;

         public Page1ViewModel(INavigationService navigationService)
         {
            this.navigationService = navigationService;
        }
    }
}

может ли кто-нибудь сказать мне, в чем проблема моего кода? заранее спасибо.

вот загрузчик:

public class ScheduleBootstrapper : PhoneBootstrapper
{
    PhoneContainer container;

    protected override void Configure()
    {
        container = new PhoneContainer(RootFrame);

        container.RegisterPhoneServices();
        container.PerRequest<MainPageViewModel>();
        container.PerRequest<MainContentViewModel>();
        container.PerRequest<Page1ViewModel>();
        AddCustomConventions();
    }

    static void AddCustomConventions()
    {
        ConventionManager.AddElementConvention<Pivot>(Pivot.ItemsSourceProperty, "SelectedItem", "SelectionChanged").ApplyBinding =
            (viewModelType, path, property, element, convention) =>
            {
                if (ConventionManager
                    .GetElementConvention(typeof(ItemsControl))
                    .ApplyBinding(viewModelType, path, property, element, convention))
                {
                    ConventionManager
                        .ConfigureSelectedItem(element, Pivot.SelectedItemProperty, viewModelType, path);
                    ConventionManager
                        .ApplyHeaderTemplate(element, Pivot.HeaderTemplateProperty, viewModelType);
                    return true;
                }

                return false;
            };

        ConventionManager.AddElementConvention<Panorama>(Panorama.ItemsSourceProperty, "SelectedItem", "SelectionChanged").ApplyBinding =
            (viewModelType, path, property, element, convention) =>
            {
                if (ConventionManager
                    .GetElementConvention(typeof(ItemsControl))
                    .ApplyBinding(viewModelType, path, property, element, convention))
                {
                    ConventionManager
                        .ConfigureSelectedItem(element, Panorama.SelectedItemProperty, viewModelType, path);
                    ConventionManager
                        .ApplyHeaderTemplate(element, Panorama.HeaderTemplateProperty, viewModelType);
                    return true;
                }

                return false;
            };
    }

    protected override object GetInstance(Type service, string key)
    {
        return container.GetInstance(service, key);
    }

    protected override IEnumerable<object> GetAllInstances(Type service)
    {
        return container.GetAllInstances(service);
    }

    protected override void BuildUp(object instance)
    {
        container.BuildUp(instance);
    }
}

person Chris Cheung    schedule 14.06.2011    source источник
comment
Это выглядит правильно. Где происходит нулевая ссылка? Вы назвали свое представление Page1View?   -  person EisenbergEffect    schedule 14.06.2011
comment
нет, я считаю, что Page1 публичный частичный класс Page1 { public Page1() { InitializeComponent(); } }   -  person Chris Cheung    schedule 15.06.2011


Ответы (1)


У меня тоже было это, и я отследил это следующим образом:

Как вы знаете, Caliburn.Micro использует соглашение вместо конфигурации для поиска представлений для моделей представления и наоборот, что означает, что мы должны следовать соглашениям. Моя ошибка заключалась в том, что namespace несовместимы для View и ViewModel.

В моем случае у меня было

MyWP7App.DetailsViewModel и

MyWP7App.Views.DetailsView

--› Я переименовал пространство имен виртуальной машины в MyWP7App.ViewModels.DetailsViewModel, и все заработало. Думаю, я мог бы переместить представление в MyWP7App.DetailsView для получения хорошего результата...


Под одеялом

вызов Navigate() вызывает DeterminePageName(), который, в свою очередь, вызывает ViewLocator.LocateTypeForModelType

Это, как и остальную часть CM, можно переопределить, но реализация по умолчанию выглядит так:

public static Func<Type, DependencyObject, object, Type> LocateTypeForModelType = (modelType, displayLocation, context) => {
    var viewTypeName = modelType.FullName.Substring(
        0,
        modelType.FullName.IndexOf("`") < 0
            ? modelType.FullName.Length
            : modelType.FullName.IndexOf("`")
        );

    Func<string, string> getReplaceString;
    if (context == null) {
        getReplaceString = r => { return r; };
    }
    else {
        getReplaceString = r => {
            return Regex.Replace(r, Regex.IsMatch(r, "Page$") ? "Page$" : "View$", ContextSeparator + context);
        };
    }

    var viewTypeList = NameTransformer.Transform(viewTypeName, getReplaceString);
    var viewType = (from assembly in AssemblySource.Instance
                    from type in assembly.GetExportedTypes()
                    where viewTypeList.Contains(type.FullName)
                    select type).FirstOrDefault();

    return viewType;
};

Если вы проследите за отладчиком, вы получите коллекцию viewTypeList, содержащую MyWP7App.DetailsView, и тип, полное имя которого MyWP7App.Views.DetailsView, а возвращаемое viewType, следовательно, равно null... это причина исключения NullReferenceException.

Я на 99% уверен, что вызов NameTransformer.Transform выполнит сопоставление с шаблоном и преобразует ViewModels в пространстве имен виртуальной машины в Views в пространстве имен представления, которое он пытается найти...

person kiwipom    schedule 02.07.2011
comment
спасибо, это решает мою проблему. я отправил электронное письмо, чтобы спросить автора об этой проблеме, он сказал мне, что я могу назвать страницу просмотра как xxxView или xxxPage. в любом случае, большое спасибо. - person Chris Cheung; 02.07.2011