【问题标题】:How to create a separate view model for a contentview in Xamarin forms having prism?如何为具有棱镜的 Xamarin 表单中的内容视图创建单独的视图模型?
【发布时间】:2019-04-22 22:41:35
【问题描述】:

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

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

请帮忙。

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
        }
    }
}

【问题讨论】:

    标签: xamarin.forms prism


    【解决方案1】:

    Prism 7.1 支持此功能。以下内容直接取自 Prism 单元测试。如果您遵循命名约定,您实际上不需要注册任何内容,您只需设置 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>();
    

    更新

    Prism 8 将引入对区域导航的支持。因此,Prism 7.1 中引入的“局部视图”将被删除。您需要迁移才能使用区域。这很容易做到,尽管在如何将参数传递到区域方面会有一些根本性的差异。

    【讨论】:

    • 我认为部分视图和消费页面的链接被交换了
    • 有这方面的示例项目吗?我无法运行 Prism-master 的源代码,无论如何这似乎是一个被嘲笑的例子。我正在尝试使用部分视图和他们自己的命令工作的 Xamarin 应用程序。我能够正确设置视图模型,但没有调用我的命令。
    • 我已经开始工作了。原来我的按钮被一个看不见的视图覆盖了!请注意,如果您的 Views 文件夹中没有 ContentViews,那么 Prism 将不知道在哪里查找(如果它们是部分视图而不是页面,您为什么会知道?)。因此,您需要按照 Dan Siegel 的建议使用 ViewModelLocationProvider.Register&lt;MyView, SomeViewModel&gt;();
    【解决方案2】:

    我认为没有必要为ContentView 定义新的ViewModel。您只需要在使用ContentViewPage 中使用AutowirePartialView 属性。像这样

    <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>
    

    【讨论】:

      猜你喜欢
      • 2021-09-07
      • 2020-10-03
      • 2019-10-18
      • 2019-06-12
      • 1970-01-01
      • 2019-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多