如何在具有棱镜的Xamarin表单中为contentview创建单独的视图模型?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在具有棱镜的Xamarin表单中为contentview创建单独的视图模型?相关的知识,希望对你有一定的参考价值。

问题陈述我想创建一个contentview用户控件,它有自己的视图模型,可以在多个内容页面中使用。

以下实现中的问题我已经扩展了我的App.xaml.cs,如下所述。但是,一旦导航在具有contentview用户控件的内容页面上工作,但如果我再次导航到该页面,则导航不起作用。只是为了添加它,view.Parent在下面的代码中也是null。

请帮忙。

using OEP.Views;
using Prism;
using Prism.Common;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Navigation;
using Prism.Unity;
using Unity.Resolution;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace OEP
{
    public partial class App : PrismApplication
    {
        public App() : this(null) { }

        public App(IPlatformInitializer initializer) : base(initializer) { }

        protected override async void OnInitialized()
        {
            InitializeComponent();
            //await NavigationService.NavigateAsync("NewOrderPage");
            await NavigationService.NavigateAsync("LoginPage");
            //await NavigationService.NavigateAsync("HomePage");
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation<LoginPage>();
            containerRegistry.RegisterForNavigation<ForgotPasswordPage>();
            containerRegistry.RegisterForNavigation<HomePage>();
            containerRegistry.RegisterForNavigation<CustomerDetailsPage>();
            containerRegistry.RegisterForNavigation<NewOrderPage>();
            //Container.Resolve<HomePageCustomersUserControl>("Customers");
            //containerRegistry.Register<HomePageCustomersUserControl, HomePageCustomersUserControlViewModel>();
            //ViewModelLocationProvider.Register<HomePageCustomersUserControl>(() => Container.Resolve<HomePageCustomersUserControlViewModel>());
        }

        protected override void ConfigureViewModelLocator()
        {
            ViewModelLocationProvider.SetDefaultViewModelFactory((view, type) =>
            {
                Page page = null;
                switch (view)
                {
                    case Page page1:
                        page = page1;
                        break;
                    case Element customView:
                        page = GetPageFromElement(customView);
                        // Existing parameter with the Page
                        break;
                }

                var navService = CreateNavigationService(page);
                ParameterOverrides overrides = new ParameterOverrides
                {
                        { "navigationService", navService }
                };
                return Container.GetContainer().Resolve(type, type.GetType().Name, overrides);

            });
        }

        // Currently exists
        protected INavigationService CreateNavigationService(Page page)
        {
            var navigationService = NavigationService;
            ((IPageAware)navigationService).Page = page;
            return navigationService;
        }

        protected INavigationService CreateNavigationService(object view)
        {
            switch (view)
            {
                case Page page:
                    return CreateNavigationService(page);
                case Element element:
                    var parentPage = GetPageFromElement(element);
                    if (parentPage == null)
                    {
                        return null;
                    }
                    return CreateNavigationService(parentPage);
                default:
                    return null;
            }
        }

        private Page GetPageFromElement(Element view)
        {
            switch (view.Parent)
            {
                case Page page:
                    return page;
                case null:
                    return null;
                default:
                    return GetPageFromElement(view.Parent);
            }
        }

        protected override void OnStart()
        {
            // Handle when your app starts
        }

        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }

        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}
答案

Prism 7.1支持此功能。以下内容直接取自Prism Unit Tests。如果您遵循命名约定,实际上不需要注册任何内容,您只需要将ViewModelLocator.AutowirePartialView设置为对父页面的引用。

<ContentView
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="Prism.DI.Forms.Tests.Mocks.Views.PartialView">
    <StackLayout>
        <Label Text="{Binding SomeText}" />
        <Button Command="{Binding NavigateCommand}"
                x:Name="navigateButton" />
    </StackLayout>
</ContentView>

<ContentPage
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:Prism.DI.Forms.Tests.Mocks.Views"
    xmlns:prism="clr-namespace:Prism.Ioc;assembly=Prism.Forms"
    xmlns:mvvm="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
    xmlns:converters="using:Prism.Forms.Tests.Mocks.Converters"
    Title="{Binding Title}"
    x:Name="xamlViewMock"
    x:Class="Prism.DI.Forms.Tests.Mocks.Views.XamlViewMock">
    <ContentPage.Resources>
        <ResourceDictionary>
            <prism:ContainerProvider x:TypeArguments="converters:MockValueConverter" x:Key="mockValueConverter" />
        </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout>
        <local:PartialView mvvm:ViewModelLocator.AutowirePartialView="{x:Reference xamlViewMock}" />
        <Entry x:Name="testEntry"
        Text="{Binding Test,Converter={StaticResource mockValueConverter}}" />
    </StackLayout>

</ContentPage>

如果您需要遵循一些自定义命名方案,您只需要调用:

ViewModelLocationProvider.Register<MyView, SomeViewModel>();
另一答案

我认为没有必要为ViewModel定义新的ContentView。你只需要在AutowirePartialView中使用Page属性,你在哪里使用ContentView。像这样

<DataTemplate>
    <ViewCell>
        <local:CardViewTemplatePage prism:ViewModelLocator.AutowirePartialView="true"/>
    </ViewCell>
</DataTemplate>

你的ContentView应该绑定这样的字段

 <StackLayout HorizontalOptions="Fill" VerticalOptions="Start">
    <Label TextColor="Denim" Text="{Binding Title}" />
    <Label TextColor="DimGray" Text="{Binding Description}" />
</StackLayout>

以上是关于如何在具有棱镜的Xamarin表单中为contentview创建单独的视图模型?的主要内容,如果未能解决你的问题,请参考以下文章

棱镜:贝壳之间的导航?

Xamarin表单 - 网格上的IsClipedToBounds不起作用。儿童的意见仍在削减

Xamarin 表单:显示和绑定具有多行和多列的列表/网格的数据

如何在 Xamarin 表单中将边距、填充、宽度和高度值转换为像素(px)?

具有绑定问题的 Xamarin 表单 FlyoutPage

如何在 Xamarin 中为 IconCode 构建字符串