【问题标题】:Why does Page disappears when I move it between frames?为什么页面在帧之间移动时会消失?
【发布时间】:2021-12-30 09:09:27
【问题描述】:

我有一个带有 Main 框架的窗口,其中包含一个页面。我还有另一个包含第一页的页面。我想在这两个页面之间移动。这是第一页:
第二个:
第一次运行应用程序时一切正常。但是当我回到第一页然后到第二页时,第二页框架中的第一页消失了:
这是 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>

所以最后一个问题是——为什么我在页面之间移动时第一页消失了?

【问题讨论】:

    标签: c# wpf xaml frame


    【解决方案1】:

    我实际上很少使用Frame quiet。这是一个非常繁重的控件,仅在您想要显示 Web 内容时才推荐使用。
    我强烈建议为每个页面/视图使用 ContentControlDataTemplate
    请参阅此示例:C# WPF Navigation Between Pages (Views).
    使用建议的解决方案使导航更加方便。它消除了像你这样的问题。此外,您还有更多选项可以自定义页面导航,例如添加动画。

    问题在于Frame 实现了一个特殊的导航流程。设置Frame.SourceFrame.Content 属性不会立即完成导航,即不会立即应用目标Page 值:

    (来源:Microsoft Docs: Navigation Overview

    您可以从图中了解到,设置 Frame.SourceFrame.Content 会导致一系列以 LoadCompleted 事件结束的事件。
    您当前导航到页面太早。 testPage 仍在最近的Frame 中加载,因此无法在下一个Frame 中显示。

    您的方案的特殊问题是您希望在不同的Frame 实例中加载相同的Page 实例。由于Page 实例只能渲染一次,您必须从最近的Frame 中卸载Page 实例,以便在下一个Frame 中显示它。

    要解决您的问题,您有两种选择:

    1. null 赋值/Frame 重置后处理LoadCompleted 事件并从处理程序设置新的Page

    2. 使用优先级至少为DispatcherPriority.BackgroundDispatchernull assignment/Frame 重置后推迟分配。例如:

      Dispatcher.InvokeAsync(() => Main.Navigate(testPage), DispatcherPriority.Background);
      

    我建议处理 LoadCompleted 事件,因为该行为肯定更具确定性:

    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);
    }
    

    【讨论】:

    • 谢谢你这么好的回答。我读到了DataTemplate 并明白这对我来说太难了。因此,我使用LoadCompleted 获取了您的代码,对其进行了一些更改,它可以按我的意愿工作。再次感谢!
    猜你喜欢
    • 1970-01-01
    • 2018-12-12
    • 2011-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多