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
LoadCompleted
event after thenull
assignment/Frame
reset and set the newPage
from the handler.Use the
Dispatcher
with a priority of at leastDispatcherPriority.Background
to defer the assignment after thenull
assignment/Frame
reset. 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);
}