Navigate between frames using Template 10 MVVM - xaml

In a UWP app using Template 10 we have an Admin page. The Admin page has 2 pages within a frame, AdminSettings1 and AdminSettings2. We wish to navigate between AdminSettings1 and AdminSettings2 in the frame, however we find we get to the target page, but lose the containing page.
How do we navigate between pages within a frame using Template 10 MVVM without losing the containing page?
The XAML (abbreviated):
<SplitView Grid.Row="1"
x:Name="AdminSplitView"
IsPaneOpen="True"
DisplayMode="Inline">
<SplitView.Pane>
<Grid>
<ListView SelectionMode="Single"
Name="AdminListBox">
<ListViewItem Name="AdminSettings1"
IsSelected="True"
Tapped="{x:Bind AdminViewModel.GoToAdminSettings1}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Settings1"/>
</StackPanel>
</ListViewItem>
<ListViewItem Name="AdminSettings2"
Tapped="{x:Bind AdminViewModel.GoToJobformSettings2}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Settings2"/>
</StackPanel>
</ListViewItem>
</ListView>
</Grid>
</SplitView.Pane>
<SplitView.Content>
<Frame Name="AdminFrame" />
</SplitView.Content>
</SplitView>
We arrive at AdminPage like this
GoToAdmin() => NavigationService.Navigate(typeof(Views.AdminPage));
In AdminPageViewModel we navigate to AdminPage2 like this
public void GoToAdmin2() =>
NavigationService.Navigate(typeof(Views.AdminPage2));
but this loses the containing Admin page
I referred to T10 documentation for Other examples of calling Navigate. This option navigates to the page bot loses the containing page
// from inside any window
var nav = WindowWrapper.Current().NavigationServices.FirstOrDefault();
nav.Navigate(typeof(Views.AdminPage2));
I was unable test this example in the documentation as I do not understand where MyFrame comes from
// from/with a reference to a Frame
var nav = WindowWrapper.Current(MyFrame).NavigationServices.FirstOrDefault();
nav.Navigate(typeof(Views.DetailPage), this.Value);
How do we navigate between pages within a frame using Template 10 MVVM?

You can use the page cache and use this solution: https://github.com/MyToolkit/MyToolkit/wiki/Paging-Overview
from this question: WinRT/UWP Frame and Page caching: How to create new page instance on Navigate() and keep the page instance on GoBack()
this.NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled;

Related

UWP Access MediaPlayerElement from other page

In my MainPage.xaml I have
<Grid>
<NavigationView x:Name="navView">
<NavigationView.MenuItems>
<NavigationViewItem x:Name="music" Content="My Music"/>
</NavigationView.MenuItems>
<Frame x:Name="myFrame">
<Frame.ContentTransitions>
<TransitionCollection>
<NavigationThemeTransition/>
</TransitionCollection>
</Frame.ContentTransitions>
</Frame>
</NavigationView>
<Grid Grid.Row="1">
<MediaPlayerElement x:Name="nowPlaying"
AreTransportControlsEnabled="True" x:FieldModifier="public">
<MediaPlayerElement.TransportControls>
...
</MediaPlayerElement.TransportControls>
</MediaPlayerElement>
</Grid>
</Grid>
I want to play music (pass Uri) from other Page (MyMusic) but I can't find a way to access the MediaPlayerElement. The other Page is opened in myFrame. And I want to keep the TransportControls.
You shouldn't rely on a UI element to play your media from another page. Instead, use the MediaPlayer class:
https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/play-audio-and-video-with-mediaplayer#use-mediaplayerelement-to-render-video-in-xaml
So specify your MediaPlayerElement (make sure to set AreTransportControlsEnabled value to what you need it to be):
<MediaPlayerElement x:Name="_mediaPlayerElement" AreTransportControlsEnabled="False" HorizontalAlignment="Stretch" Grid.Row="0"/>
Then you can link your element to the MediaPlayer object which you can reference in code:
_mediaPlayerElement.SetMediaPlayer(mediaPlayer);
Then play whatever you need:
_mediaPlayerElement.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/example_video.mkv"));
mediaPlayer = _mediaPlayerElement.MediaPlayer;
mediaPlayer.Play();

Issues with child page's display when using Frames

Problem
This is the layout of my main pane:
<Page
x:Class="Communities.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Communities"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" Loaded="Page_Loaded" DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="48" />
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
...
<SplitView Grid.Row="1" Name="hamburgerMenu" OpenPaneLength="200" PaneBackground="#F02A2A2A">
<SplitView.Pane>
<ListView ItemsSource="{Binding}" IsItemClickEnabled="True" ItemClick="HamburgerItemClick">
... </ListView>
</SplitView.Pane>
<Frame Name="frame" />
</SplitView>
<Grid Grid.RowSpan="3" Name="popupArea" />
</Grid>
</Page>
the frame is where I load all my pages, so that the layout is always consistant.
Now, in most of my child pages I have defined AppBar control and attached it to the BottomAppBar property of that child page:
PostView.xaml
...
<Page.BottomAppBar>
<CommandBar>
<AppBarButton Label="Back" Icon="Back" Click="TryGoBack" />
<AppBarButton Label="Refresh" Icon="Refresh" Click="TryRefreshComments" />
<AppBarButton Label="Go to Community" Icon="Go" Click="TryOpenCommunity" />
</CommandBar>
</Page.BottomAppBar>
...
Here's where the trouble starts. It works fine on PC, as the layout is mostly static on desktop. There are no software keyboards required most of the time etc. On mobile it's more problematic: Screenshots
My thoughts
It seems like the frame that is used to display the child page is causing all sorts of problems. When the AppBar is defined in the main page it positions correctly.
I'd like to avoid the keyboard covering the textbox as well as the AppBar but I don't want to get rid of the frame control. I'd also prefer it if the page got "squished" when the keyboard shows up, instead of getting pushed upwards, but I'm not sure how to display the keyboard on the frame level, instead of the entire MainPage, default level.
What would be the best way to solve this situation?
Cheers!
As you know, if we set the Page.BottomAppBar in the root of the Page, there is no issue with Touch keyboard. It seems it is the best way to add the Page.BottomAppBar.
If you want to add the Page.BottomAppBar in the other page in the Frame, you should be able to customize your UI. The UWP provides similar behavior on the appearance of the touch keyboard by handling the Showing and Hiding events exposed by the InputPane object.
We can use the InputPaneVisibilityEventArgs.OccludedRect to get the region of the application's window that the input pane is covering.
For example:
public PostView()
{
this.InitializeComponent();
InputPane.GetForCurrentView().Showing += PostView_Showing;
InputPane.GetForCurrentView().Hiding += PostView_Hiding;
}
private void PostView_Hiding(InputPane sender, InputPaneVisibilityEventArgs args)
{
MyTextBox.Margin = new Thickness(0, args.OccludedRect.Height, 0, 0);
}
private void PostView_Showing(InputPane sender, InputPaneVisibilityEventArgs args)
{
MyTextBox.Margin = new Thickness(0, 0, 0, args.OccludedRect.Height);
}

Common ToolBar in UWP c++

I am attempting to make a multipage app and would like to use a common navigation toolbar across all pages. The page includes:
<Page.TopAppBar>
<AppBar >
<StackPanel Orientation="Horizontal">
<Button />
</StackPanel>
</AppBar>
</Page.TopAppBar>
In App.xaml I can define the AppBar that goes into the Page.TopAppBar:
<Application.Resources>
<AppBar x:Key="CommonAppBar" x:Name="AppBarCommon">
<StackPanel Orientation="Horizontal">
<Button />
</StackPanel>
</AppBar>
</Application.Resources>
But how can I use this AppBar defination in the Page xaml?
You can use the Frame control on one page and show another your pages inside that frame. Then you can add an AppBar to this page.
By the way, the AppBarButton is the button that is used inside an AppBar, not StackPanel and Buttons (your approach will still work, but if you expect the same behaviour and look as in other UWP apps, it's easier to use AppBarButtons).

Load a Page into a ContentControl

I have a ContentControl where I want to load the page myPage2. My XAML Codefrom this page looks like this:
<Page x:Class="ExampleApp.myPage2">
<Grid x:Name="Content" Height="651" Width="941" Background="White">
...
...
</Grid>
</Page>
I know that I can load a resource from a page with this Code:
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
var contentControl = (ContentControl)container;
return (DataTemplate) contentControl.Resources[templateKey];
}
My problem now is that I can't load a page like above with this code. I have to write this:
<Page x:Class="ExampleApp.myPage2">
<Page.Resources>
<DataTemplate x:Key="Test">
<Grid x:Name="Content" Height="651" Width="941" Background="White">
...
...
</Grid>
</DataTemplate>
</Page.Resources>
</Page>
And then I can load the page with the same Code from above with templateKey="Test". But the main problem is that I want to use the first declaration of the page and do not want to use <Page.Resources> <DataTemplate x:Key="Test"> and so on. I want to load the site direcly from the first declaration (first code in this post). How can I create a DataTemplate directly from a page? Or is there an other way to load a page into a ContentControl?
There is no reason to use a Page within a ContentControl. A Page is a subclass of the UserControl class that adds support for being used within a Frame control to support navigation, back stack/history, etc. You should probably replace Page with UserControl in XAML and code behind, so you would end up with something like this:
<UserControl x:Class="ExampleApp.myControl2">
<Grid x:Name="Content" Height="651" Width="941" Background="White">
...
...
</Grid>
</UserControl>
You can put the UserControl itself in a DataTemplate if you want to use it as a DataTemplate in a ContentControl:
<ContentControl
xmlns:controls="using:ExampleApp">
<ContentControl.Resources>
<DataTemplate
x:Key="Test">
<controls:myControl2 />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>

Refresh custom control Xaml / lightswitch

I am creating an app in Lightswitch and I used this custom control.
The problem is when I change value of the control.
It's probably not possible to change control dynamically, it must be refreshed to get new value.
So I need to know how can I refresh just control or part of the screen.
This is how the control code look
<Grid x:Name="LayoutRoot" Background="White" Width="200" Height="200">
<GaugeControl:GaugeControl HorizontalAlignment="Left" Margin="10,10,10,10"
Name="gaugeControl1"
Maximum="25000" Minimum="0" VerticalAlignment="Top" />
</Grid>
This way is how I set binding to the value
public RadioGauge() {
InitializeComponent();
gaugeControl1.Value = Amount.amount; // where Amount is class and amount is int property
}
And this way I change the control property
SilverlightCustomControls.Amount.amount = 10000;
I couldnt find anything about refreshing or reloading XAML control or refreshing just part of lighswitch screen.. thx for any help
Lightswitch automatically refreshes components if they are data bound. Because you are just setting the value, the control is not being refreshed. Can you not bind the control to your property? Then when you change it in code the control should automatically refresh?
<Grid x:Name="LayoutRoot" Background="White" Width="200" Height="200">
<GaugeControl:GaugeControl HorizontalAlignment="Left" Margin="10,10,10,10"
Name="gaugeControl1"
Maximum="25000" Minimum="0"
VerticalAlignment="Top"
Value="{Binding Screen.SCREENDATASET.SelectedItem.Amount}" />
</Grid>