0

I'm an Android developer trying to learning UWP development, and attempting to use the Prism Library and Windows Template Studio to help me with the boilerplate functionality.

My goal is to have a ProgressCircle control that is accessible by all views, so that whenever I'm performing an async call, I can pop up the ProgressCircle. In an attempt to keep things DRY I don't want to have a ProgressCircle in each view. How can I achieve this?

As I understand it (Prism) as built by the Windows Template Studio has a ShellPage view that houses all of the other views within it and it has it's own viewModel. This seems somewhat similar to Androids Activity/Fragment model. My initial idea was to place the ProgressCircle in the ShellPage view, and then call it from my child view (MainPage) when needed. However I have not figured out how to call another views viewModel methods from a child/other view/viewModel. Is this the correct approach and if so how can I accomplish this?

My other idea is to create a Progress app service that can be added to the viewModel base class, but I haven't learned about app services just yet.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
szaske
  • 1,887
  • 22
  • 32
  • 2
    *"In an attempt to keep things DRY I don't want to have a ProgressCircle in each view"* - this is sounds to me like "I don't want to have `TextBox` in each view". If you make a custom control it should be fine to use everywhere. – Sinatr Mar 15 '19 at 14:48
  • I was thinking of a singleton control, so I don't get in the situation of showing 2 ProgressCircles at the same time. The Android way to do this would be to have a single control (in the Activity) that all fragments would have access to from the fragment...which would be provided in the base class. – szaske Mar 15 '19 at 16:35
  • Hmm, I just read about the Prism IEventAggregator interface, would this be the correct way to accomplish this or overkill? – szaske Mar 15 '19 at 18:41

1 Answers1

1

Ok, so I'm not sure if it is any different with Prism as I'm using the code behing pattern (I don't know anything about it, but as far as I could see, it wasn't that different). Anyways, the Shell Page created by Windows Template Studio should look similar to this :

<Page
    x:Class="MyProject.Views.ShellPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:i="using:Microsoft.Xaml.Interactivity"
    xmlns:behaviors="using:armada_vpn.Behaviors"
    xmlns:winui="using:Microsoft.UI.Xaml.Controls"
    xmlns:helpers="using:MyProject.Helpers"
    xmlns:views="using:MyProject.Views"
    Loaded="OnLoaded"
    mc:Ignorable="d" Background="Black">

    <winui:NavigationView
        x:Name="navigationView"
        IsBackButtonVisible="Visible"
        IsBackEnabled="{x:Bind IsBackEnabled, Mode=OneWay}"
        SelectedItem="{x:Bind Selected, Mode=OneWay}"
        ItemInvoked="OnItemInvoked"
        IsSettingsVisible="False"
        Background="White" RequestedTheme="Light"
        OpenPaneLength="200">

        <winui:NavigationView.MenuItems>
            <!--
            TODO WTS: Change the symbols for each item as appropriate for your app
            More on Segoe UI Symbol icons: https://learn.microsoft.com/windows/uwp/style/segoe-ui-symbol-font
            Or to use an IconElement instead of a Symbol see https://github.com/Microsoft/WindowsTemplateStudio/blob/master/docs/projectTypes/navigationpane.md
            Edit String/en-US/Resources.resw: Add a menu item title for each page
            -->

            <winui:NavigationViewItem x:Uid="Shell_Main" Icon="Home" helpers:NavHelper.NavigateTo="views:MainPage" />
        </winui:NavigationView.MenuItems>
        <i:Interaction.Behaviors>
            <behaviors:NavigationViewHeaderBehavior
                x:Name="navigationViewHeaderBehavior"
                DefaultHeader="{x:Bind ViewModel.Selected.Content, Mode=OneWay}">
                <behaviors:NavigationViewHeaderBehavior.DefaultHeaderTemplate>
                    <DataTemplate>
                        <Grid>
                            <TextBlock
                                Text="{Binding}"
                                Style="{ThemeResource TitleTextBlockStyle}"
                                Margin="{StaticResource SmallLeftRightMargin}" />
                        </Grid>
                    </DataTemplate>
                </behaviors:NavigationViewHeaderBehavior.DefaultHeaderTemplate>
            </behaviors:NavigationViewHeaderBehavior>
            <ic:EventTriggerBehavior EventName="ItemInvoked">
                <ic:InvokeCommandAction Command="{x:Bind ViewModel.ItemInvokedCommand}" />
            </ic:EventTriggerBehavior>
        </i:Interaction.Behaviors>
        <Grid> #This here is important for you
            <Frame x:Name="shellFrame"/>
        </Grid>
    </winui:NavigationView>
</Page>

The grid area designated in the page XAML is where your different views will be shown as the ShellPage controls what is shown in this frame.

Anyways, what you want to do, is add your Progress Ring on top of this frame (and with a transparent background). For this, you can specify a ZIndex for both elements (the element with the highest ZIndex will be shown on top :

<Grid>
    <ProgressRing x:Name="ProgressRing" Canvas.ZIndex="2" Background="Transparent"/>
    <Frame x:Name="shellFrame" Canvas.ZIndex="1"/>
</Grid>

Or, you can simply define the ProgressRing as the last element here (as, without any ZIndex specified, the rendering order is from top to bottom) :

<Grid>
    <Frame x:Name="shellFrame"/>
    <ProgressRing x:Name="ProgressRing" Background="Transparent"/>
</Grid>

Then, this can be accessed in your ShellPage with the name you've given your ProgressRing, but accessing this from your other views can be tricky as you would need to access the ShellPage instance directly from them. One thing you could do is implement events for activating and deactivating the ProgressRing that could be raised from anywhere in your code, and implement handlers that would subscribe to these events in your ShellPage class.

Hope it helps.

Olivier Samson
  • 609
  • 4
  • 13
  • Thanks Olivier for your well written response. Looks like I have two options. This one is nice, but seems a bit overkill to use an Event aggregator for this. Luckily Prism has Event Agreggation built in. The other option is explained here: https://stackoverflow.com/questions/55228547/how-can-i-show-a-progressring-control-only-on-top-of-overlaying-my-current-page – szaske Mar 29 '19 at 17:10
  • Hi, an event aggregator certainly is overkill for this, you can just set up simple event. If the popup option is not right for you, I could edit my answer to explain how to do it. – Olivier Samson Mar 29 '19 at 19:56