I have a window with a Main frame which contains a Page. And I have another Page that contains the first Page. And I want to move between this two Pages. Here is the first page:

And the second one:

Everything is ok for the first time when I run the app. But when I come back to the first Page and then to the second, the first Page in the second Page's frame disappears:

Here is the MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public static TestPage testPage = new TestPage();
public static CombinedPage combinedPage = new CombinedPage();
public MainWindow()
{
InitializeComponent();
}
private void Butt1_Click(object sender, RoutedEventArgs e)
{
combinedPage.TimerFrame.Content = null;
Main.Content = testPage;
}
private void Butt2_Click(object sender, RoutedEventArgs e)
{
Main.Content = null;
combinedPage.Call();
Main.Content = combinedPage;
}
}
MainWindow.xaml:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80 px"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70 px" ></ColumnDefinition>
<ColumnDefinition Width="*" ></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Orientation="Vertical" VerticalAlignment="Top" HorizontalAlignment="Left" Grid.RowSpan="2">
<Button x:Name="Butt1" Height="50" Width="50" Click="Butt1_Click" />
<Button x:Name="Butt2" Height="50" Width="50" Click="Butt2_Click" />
</StackPanel>
<Frame NavigationUIVisibility="Hidden" x:Name="Main" Grid.Row="1" Grid.Column="1"/>
</Grid>
CombinedPage.xaml.cs:
public partial class CombinedPage : Page
{
public CombinedPage()
{
InitializeComponent();
}
public void Call()
{
TimerFrame.Content = MainWindow.testPage;
}
}
CombinedPage.xaml:
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<GridSplitter Grid.Column="1" Grid.RowSpan="3" Width="5" Background="Black"
VerticalAlignment="Stretch" HorizontalAlignment="Center" />
<GridSplitter Grid.Row="1" Grid.ColumnSpan="3" Height="5" Background="Black"
VerticalAlignment="Center" HorizontalAlignment="Stretch" />
<Frame NavigationUIVisibility="Hidden" x:Name="TimerFrame" Grid.Row="0" Grid.Column="0"/>
</Grid>
So the final question is - Why does the first Page disappear when I move between pages?
CodePudding user response:
I'm actuall using the Frame quiet rarily. It's a very heavy control that is only recommended when you want to display web content.
I highly recommend to use a ContentControl and a DataTemplate for each page/view.
See this example:
(Source: Microsoft Docs: Navigation Overview)
As you can learn from the diagramm, setting the Frame.Source or Frame.Content results in a series of events that ends with the LoadCompleted event.
You are currently navigating to pages too early. The testPage is still loaded in the recent Frame and is therefore not able to be displayed in the next Frame.
The special problem with your scenario is that you want to load the same Page instance in different Frame instances. Since the Page instance can only be rendered once, you must unload the Page instance from the recent Frame in order to show it in the next Frame.
To fix your problem you have two options:
Handle the
LoadCompletedevent after thenullassignment/Framereset and set the newPagefrom the handler.Use the
Dispatcherwith a priority of at leastDispatcherPriority.Backgroundto defer the assignment after thenullassignment/Framereset. For example:Dispatcher.InvokeAsync(() => Main.Navigate(testPage), DispatcherPriority.Background);
I recommend handling the LoadCompleted event as the behavior is definitely more deterministic:
private void Butt1_Click(object sender, RoutedEventArgs e)
{
combinedPage.TimerFrame.LoadCompleted = SetMainFrame_OnLoadCompleted;
combinedPage.TimerFrame.Navigate(null);
}
private void SetMainFrame_OnLoadCompleted(object sender, NavigationEventArgs e)
{
combinedPage.TimerFrame.LoadCompleted -= SetMainFrame_OnLoadCompleted;
Main.Navigate(testPage);
}
private void Butt2_Click(object sender, RoutedEventArgs e)
{
Main.LoadCompleted = SetFrameContents_OnLoadCompleted;
Main.Navigate(null);
}
private void SetFrameContents_OnLoadCompleted(object sender, NavigationEventArgs e)
{
Main.LoadCompleted -= SetFrameContents_OnLoadCompleted;
combinedPage.Call();
Main.Navigate(combinedPage);
}
