带有MVVM的XAML主/模板页面

时间:2017-04-02 10:10:57

标签: xaml mvvm uwp

有没有办法在XAML中创建主/模板页面(对于UWP应用程序)?

我想解决的问题:
我有一个有很多类似网站的应用程序,其中只有内容略有改变,但没有按钮和布局。例如:

<Page
    DataContext="{Binding WebpageViewModel, Source={StaticResource Locator}}">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0" Text="Edit Webpage" Style="{StaticResource BigTexBlock}" />
            <ScrollViewer  Style="{StaticResource ContentScrollViewer}" Grid.Row="1" VerticalScrollMode="Enabled">
                <StackPanel Margin="10,0">
                    <webpage:EditWebpage DataContext="{Binding }" />
                </StackPanel>
            </ScrollViewer>
        </Grid>
    </Grid>

    <Page.BottomAppBar>
        <CommandBar>
            <CommandBar.PrimaryCommands>
                <!-- more buttons -->
                <AppBarButton IsCompact="True" Command="{Binding SaveEntryCommand}" Icon="Save" Label="Save" />
            </CommandBar.PrimaryCommands>
        </CommandBar>
    </Page.BottomAppBar>
</Page>

此模板只有三部分会改变; DataContext中的ViewModel,TextBlock的文本以及包含可编辑字段的UserControl

由于这是一个使用简单实体进行大量CRUD的应用程序,如果我继续“解决”这样的问题,那么一遍又一遍地重复的代码量就会很多。在分离的业务逻辑中,我可以通过继承避免这个问题,但我很难在XAML中找到一个优雅的解决方案。

有没有办法重构这个,所以我可能有一个“模板页面”?
我喜欢twig如何解决这个问题:http://twig.sensiolabs.org/。您可以定义主/模板页面并覆盖子模板中的部分内容。

对我来说很重要的是

  • 我没有打破MVVM模式。
  • 我不想在一个“主”XAML中隐藏/显示UserControl,因为不同实体的数量可能会变得很大
  • 我希望在用户看到预期动画的页面之间进行导航,并且它不会破坏我已经拥有的分离视图代码

2 个答案:

答案 0 :(得分:2)

没有其他技术(如MVC)具有的母版页或模板机制。但是你可以使用框架和导航来做你正在寻找的东西。

您可以按照当前的方式定义页面。页面上的所有固定元素都在布局中。现在,不要将UserControl用于特定的编辑UI,而是将其替换为框架。

<StackPanel Margin="10,0">
    <Frame Name="EditFrame" DataContext="{Binding }" />
</StackPanel>

现在,当您导航到“主编辑”页面时,还会在框架中传递所需视图的类型。然后在主页面的OnNavigatedTo覆盖上,您可以将框架导航到视图类型作为参数。

您还可以使用EditFrame来浏览多个编辑页面,例如,如果您有一个带有“下一个”和“上一个”按钮的向导UI,而不离开主页面。

您可以在OnNavigatedTo方法中执行此操作,也可以修改NavigationService以便能够处理此行为。

答案 1 :(得分:1)

我已使用https://stackoverflow.com/a/43170663

建议的方法解决了这个问题

我的NavigationService

Frame

我的xaml(我的“母版页”)现在看起来像这样(现在使用<Page x:Class="Famoser.Bookmarked.Presentation.Universal.Pages.Entry.Webpage.AddEntryPage" mc:Ignorable="d" d:DataContext="{Binding WebpageViewModel, Source={StaticResource Locator}}"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <TextBlock x:Name="Title" Grid.Row="0" Text="Add "/> <ScrollViewer Grid.Row="1"> <StackPanel Margin="10,0"> <Frame x:Name="EntryFrame" /> </StackPanel> </ScrollViewer> </Grid> <Page.BottomAppBar> <CommandBar> <CommandBar.PrimaryCommands> <!-- more app buttons --> <AppBarButton IsCompact="True" Command="{Binding SaveEntryCommand}" Icon="Save" Label="Save" /> </CommandBar.PrimaryCommands> </CommandBar> </Page.BottomAppBar> </Page> ):

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);
    if (e.Parameter is NavigationParameter pm)
    {
        DataContext = SimpleIoc.Default.GetInstance(pm.ViewModelType);
        Title.Text = "Add " + pm.Name;
        EntryFrame.Navigate(pm.EditFrameType);
    }
}

并在导航事件后面的代码中设置了我的NavigationService传递的属性

null

github上的完整项目:https://github.com/famoser/Bookmarked