Whilst using the InkCanvas in an app I'm currently developing I found after moving between pages that had InkCanvases on them the app would crash with a Xaml Parse Exception. It seemed random, however I created a simple app to get rid of as many variables that could be causing this. I added 2 pages to move between with multiple (10) InkCanvases on the second page. The app consistently crashes after moving back and forth between the pages 10 or more times. Below I have added my simple test pages.
Page 1:
<Page>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Content="Navigate"
Click="ButtonBase_OnClick"/>
</Grid>
</Page>
Page 1 Code behind:
public sealed partial class MainPage : Page {
private Frame rootFrame;
public MainPage() {
this.InitializeComponent();
rootFrame = Window.Current.Content as Frame;
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e) {
rootFrame.Navigate(typeof (PageTwo));
}
}
Page 2:
<Page>
<StackPanel>
<TextBlock Text="Sign 1"/>
<InkCanvas Width="100"
Height="100"/>
<TextBlock Text="Sign 2"/>
<InkCanvas Width="100"
Height="100"/>
<!-- Another 8 InkCanvases -->
</StackPanel>
</Page>
I checked the memory profiler to see if the InkCanvases or pages were being held onto in memory but from what I could see they weren't.
Has anyone else experienced this issue? Or is there any known workaround?
Just set the NavigationCacheMode of pagetwo to Required or Enabled as follows:
public Page2()
{
this.NavigationCacheMode = NavigationCacheMode.Required;
this.InitializeComponent();
}
I have tested your code , navigate to pagetwo from pageoneand then navigate from pagetwo to pageone , after about thirteen rounds, the app crashes and throw the exception:
Cannot create instance of type 'Windows.UI.Xaml.Controls.InkCanvas'
So it seems the instance size of InkCanvas for the frame is exceeded. Every time you navigate you will create ten instances for the InkCanvas. So we set the NavigationCacheMode to require , it means
The page is cached and the cached instance is reused for every visit regardless of the cache size for the frame.
You also can set it to Enabled.It depends on your requirements.
More details about instance cache, please see NavigationCacheMode
Related
I have a UWP app, with two Pages: MainPage and EventPage. On both of these there is a splitView, and at the top of this a GridView with two buttons - one to navigate to MainPage, and one to navigate to EventPage. The XAML for the buttons looks like this:
<Button Content="Browse by system"
HorizontalAlignment="Center"
Margin="0,0,0,0"
VerticalAlignment="Top"
Width="250"
Click="SystemButtonClick"/>
However, when i press the "Browse by system" button, the app crashes. Here is the constructor for the page:
public EventPage()
{
this.InitializeComponent();
var systemList = SystemClass.GetSystems();
systemList.Sort();
Systems = new ObservableCollection<string> (systemList);
}
It passes the constructor fine, and instead crashes when exiting the eventhandler for the button click:
private void SystemButtonClick(object sender, RoutedEventArgs e)
{
this.Frame.Navigate(typeof(EventPage));
}
I've modeled this after the Peer-to-peer navigation tutorial from microsoft, and can't find any significant differences. The only similar issue I could find here was this, but that seemed to be due to the Template10 package which I'm not using.
When the crash does occur, it goes to the App.g.i.cs file and complains that the debugger isn't configured to debug this unhandled exception.
Does anyone have any idea why this might be happening?
EDIT: To add, if I click the button to move to the current page, it reloads fine. I also just tried starting the program to the EventPage, which also prompted a crash.
EDIT2: After some further testing, it seems I've located the source of the crash, though I don't understand it.
At the beginning of my EventPage class, I have a few variables:
public sealed partial class EventPage : Page
{
private ObservableCollection<EventBin> EventCollection;
private ObservableCollection<String> Systems;
public EventPage()
{
this.InitializeComponent();
Systems = SystemClass.GetSystems();
}
It seems that the crass occurs when I assign the Systems variable. This doesn't occur with my identical operation for the other page, with a different variable. The only difference being that in the MainPage, it's an ObservableCollection of a custom class rather than of strings.
If I re-initialize the System variable like this:
var Systems = SystemClass.GetSystems();
It runs, but doesn't connect to my bindings in the XAML.
So, it turned out that the issue was that I had bound a custom type to the list in my data template, and then tried feeding it plain strings.
<DataTemplate x:Key="System_DefaultItemTemplate"
x:DataType="local:SystemClass">
<StackPanel>
<TextBlock Text="{x:Bind Name}"/>
<TextBlock Text="{x:Bind Site}"/>
</StackPanel>
</DataTemplate>
Since the strings obviously didn't have any Name or Site properties, it crashed.
The question is, when a XAML page is used inside another XAML page, how can I load saved states of both pages?
Details
To make my ProfilePage.xaml simple and reusable, I've created it separately and use it inside pivot of the MainPage.xaml (is that a good approach?)
<Grid>
<Pivot>
<PivotItem>
<Grid/>
</PivotItem>
<PivotItem>
<Frame x:Name="ProfileFrame"/>
</PivotItem>
</Pivot>
</Grid>
When MainPage is loaded, ProfileFrame navigates to ProfilePage.xaml:
this.ProfileFrame.Navigate(typeof(ProfilePage), parameter);
Each page saves state normally using NavigationHelper
private void NavigationHelper_SaveState(object sender, SaveStateEventArgs e)
{
e.PageState["collection"] = collection;
}
The problem is that the MainPage saves state, and then when come back again to the MainPage, ProfilePage needs to be created new, without loading the old saved data.
How can I load state of ProfilePage.xaml when it is used inside frame control of the MainPage.xaml?
I am working on a UWP app and encountered an issue with the background image changing when I navigate to different pages.
In my RootPage.xaml file I have this layout
<Grid x:Name="Root">
<Grid.Background>
<ImageBrush
ImageSource="{Binding ImageSource}"
Stretch="UniformToFill" />
</Grid.Background>
<SplitView Name="Splitter" IsPaneOpen="False" DisplayMode="Overlay" PaneBackground="Transparent">
<SplitView.Pane>
<Grid>
<!-- list view -->
</Grid>
</SplitView.Pane>
<Frame Name="MainFrame"></Frame>
</SplitView>
</Grid>
In my code behind I handle changes in the selection changed event like so
private void SectionList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// code to get the navigation item page the event args
// then navigate like so
MainFrame.Navigate(item.DestinationPage);
}
But when I navigate to the one of the other pages my background image that was set on the grid is lost. It just turns black.
I am missing something here, I have been watching a ton of tutorials but must have missed something. I just want the page content where frame is, and replace that depending on where the user navigated to. But leave the split view navigation stuff to live on every page.
Once you navigate to your "DestinationPage" you will see whatever background is set on the root element of that page (default is: {ThemeResource ApplicationPageBackgroundThemeBrush} ).
If you want the page to be transparent, so that the user will see the background image of the root Grid, you can set Background="Transparent" on your page's root element.
Hope this helps - thanks!
Stefan Wick
I'm porting an iOS app to a UWP project and there is something I'd love to do to save a bit of repetition but not sure how to do it.
On iOS I would embed a UINavigationController inside a UIContainerView and be able to push/pop only a section of the screen instead of pushing a full page on top of another.
Is there any way to do something similar on a UWP project? I effectively want to have a Page within a Page, and on the Inner page, be able to push a new page on top of that page.
Example: Have 3 navigation buttons along the top of the page. They are 'Tabs' which load 1 page per button into the area below it. It's a highly customised TabBar. The buttons would be nice to have in their own page with the content for each 3 pages in it's own page.
Currently I'm, doing this by either re-using the buttons along the top in multiple pages. Or I can swap out multiple UserControls manually based on which button is pressed. One UserControl for each page.
Any help on the preferred method for this would be grand!
Cheers,
Dave.
Is there any way to do something similar on a UWP project? I effectively want to have a Page within a Page
If I didn't understand it wrong, you can use Frame.
For Example: On MainPage.Xaml you can define one Frame with three Buttons:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<Button Name="btnPageOne" Content="Page One" Click="btnPageOne_Click"></Button>
<Button Name="btnPageTwo" Content="Page Two" Click="btnPageTwo_Click"></Button>
<Button Name="btnPageThree" Content="Page Three" Click="btnPageThree_Click"></Button>
<Frame Name="MyFrame" Width="500" Height="600"></Frame>
</StackPanel>
</Grid>
And on the click events of three buttons you can navigate the Frame to three pages:
private void btnPageOne_Click(object sender, RoutedEventArgs e)
{
MyFrame.Navigate(typeof(PageOne));
}
private void btnPageTwo_Click(object sender, RoutedEventArgs e)
{
MyFrame.Navigate(typeof(PageTwo));
}
private void btnPageThree_Click(object sender, RoutedEventArgs e)
{
MyFrame.Navigate(typeof(PageThree));
}
and on the Inner page, be able to push a new page on top of that page.
You can define a button on PageOne inside a StackPanel like below:
<Grid Name="rootGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Name="myStackPanel">
<Button Name="myBtn" Click="myBtn_Click">Click Me to add Page</Button>
</StackPanel>
</Grid>
And in the Click event add new Frames to that StackPanel:
private void myBtn_Click(object sender, RoutedEventArgs e)
{
Frame newFrame = new Frame{
Width=100,
Height=100
};
myStackPanel.Children.Add(newFrame);
newFrame.Navigate(typeof(SubPageOne));
}
Here is the basic Demo that I made: FrameNavigationSample
I'm fighting with little problem on WP8.1 - it took some time, but finally I've managed to localize it - let say that we have a button with a flyout:
<Grid x:Name="LayoutRoot">
<Button Content="reset" VerticalAlignment="Center">
<Button.Flyout>
<MenuFlyout Placement="Top">
<MenuFlyoutItem Text="first item"/>
<MenuFlyoutItem Text="second item"/>
</MenuFlyout>
</Button.Flyout>
</Button>
</Grid>
It works fine, but if we set the DataContext of a page:
public MainPage()
{
this.InitializeComponent();
this.DataContext = this; // without this works fine every button click
}
then there is a problem - the first time we click our button - works fine, but when we click it the second time, along with flyout, the page's theme changes to Light (the changed theme persists after we dismiss the flyout, you will have to reload the page). It looks more or less like in the images below:
Does anybody know what can cause the problem? Any workarounds?
If somebody wants to try - here is a sample code.
I don't know why it's happening, but you can force your page's RequestedTheme when the page is loaded:
XAML
<Page
...
x:Name="myPage">
C#
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
if (App.Current.RequestedTheme == ApplicationTheme.Dark)
{
myPage.RequestedTheme = ElementTheme.Dark;
}
else
{
myPage.RequestedTheme = ElementTheme.Light;
}
}