如何通过横向拖动(滑动手势)在 views/screens 之间导航?

How can I navigate between views/screens by dragging sideways (swipe gesture)?

所以我希望用户通过横向拖动来更改显示的 window。他的光标在屏幕上的确切位置应该无关紧要(所以只有拖动操作才是重要的)我画了一点我的想法。我希望用户看到第二个屏幕出现在光标之后,甚至在他将光标向右移动时缩回(基本上跟随他的光标)。这个动作应该是双向的:从 main window 到 2nd window 和从 2nd window 回到 main window 你会如何处理这个问题?

编辑: 图片1;用户将光标放在点 A 上并单击。按住鼠标单击的同时,他将其拖过绿色箭头。

图片2;此图表示“幻灯片”仍在进行时的中间状态(您可以看到“统计”屏幕仍未完全接管初始屏幕)

图3;代表最终状态;在用户到达(假想的)绿色箭头的末尾之后。统计信息屏幕现已完全显示,用户可以阅读其中的信息。

应该允许与现在发生的情况相反(从左向右拖动以返回初始屏幕)

您需要对您的内容应用翻译转换。

以下示例显示如何拖动内容(或内容的图像)。为简单起见,该示例仅显示如何从右向左滑动。它也没有显示如何实现历史记录以返回导航。您需要一个 Queue 来存储下一页,并需要一个 Stack 来存储上一页(基于滑动方向)。
虽然下面的例子做到了,但我不建议直接使用控件来处理页面及其导航。而是创建页面数据模型并使用每个页面模型的 DataTemplate 呈现控件。

MainWindow.xaml.cs

public partial class MainWindow : Window
{
  public object CurrentPage
  {
    get => (object)GetValue(CurrentPageProperty);
    set => SetValue(CurrentPageProperty, value);
  }

  public static readonly DependencyProperty CurrentPageProperty = DependencyProperty.Register(
    "CurrentPage", 
    typeof(object), 
    typeof(MainWindow), 
    new PropertyMetadata(default));

  private StackPanel DraggableContent { get; }

  // Accept swipe after 25% swipe delta 
  // based on the max possible swipe width (a displayed page).
  // Note that the 'PageHost' will host two pages (their image) 
  // during the swipe action.
  private double SwipeAcceptDragThreshold 
    => this.PageHost.ActualWidth / 2 * 0.25;

  private bool IsSwiping { get; set; }
  private double HorizontalDragStart { get; set; }
  private UserControl PreviousPage { get; set; }
  private UserControl NextPage { get; set; }

  /* Page controls */
  private UserControl GreenPage { get; }
  private UserControl OrangePage { get; }
  private UserControl BluePage { get; }

  public MainWindow()
  {
    InitializeComponent();

    this.GreenPage = new PageControl() { Background = Brushes.Green };
    this.OrangePage = new PageControl() { Background = Brushes.Orange };
    this.BluePage = new GreenPage() { Background = Brushes.Blue };

    this.CurrentPage = this.GreenPage;
    this.NextPage = this.OrangePage;

    this.DraggableContent = new StackPanel() { Orientation = Orientation.Horizontal };
  }

  protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
  {
    base.OnPreviewMouseLeftButtonDown(e);
    this.HorizontalDragStart = e.GetPosition(this).X;
  }

  protected override void OnPreviewMouseMove(MouseEventArgs e)
  {
    base.OnPreviewMouseMove(e);
    if (e.LeftButton == MouseButtonState.Released)
    {
      return;
    }

    double dragDelta = e.GetPosition(this).X - this.HorizontalDragStart;
    if (!this.IsSwiping)
    {
      bool isSwipeRightToLeft = dragDelta < HorizontalDragStart;
      UserControl swipeInPage = null;
      UserControl swipeOutPage = null;
      if (isSwipeRightToLeft)
      {
        if (this.NextPage == null)
        {
          return;
        }
        swipeInPage = this.NextPage;
        swipeOutPage = this.CurrentPage as UserControl;
        this.PreviousPage = this.CurrentPage as UserControl;
      }

      this.IsSwiping = true;

      /* Create an image of the content that will be dragged, using VisualBrush */

      swipeInPage.Height = this.PageHost.ActualHeight;
      swipeInPage.Width = this.PageHost.ActualWidth;
      swipeOutPage.Height = this.PageHost.ActualHeight;
      swipeOutPage.Width = this.PageHost.ActualWidth;

      this.CurrentPage = null;

      // Prepare the snapshot
      this.DraggableContent.Children.Add(swipeOutPage);
      this.DraggableContent.Children.Add(swipeInPage);

      // To improve performance, the user will only drag a snapshot
      // of the pages. The snapshot is painted on an empty Grid
      // using a VisualBrush.
      this.CurrentPage = new Grid()
      {
        Background = new VisualBrush(DraggableContent),
        Width = this.PageHost.ActualWidth * 2 // Host two pages
      };
    }

    this.TranslateTransform.X = dragDelta;
  }

  protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
  {
    base.OnMouseLeftButtonUp(e);
    if (this.IsSwiping)
    {
      this.IsSwiping = false;

      double dragDelta = Math.Abs(e.GetPosition(this).X - this.HorizontalDragStart);
      bool isDragAccepted = dragDelta > this.SwipeAcceptDragThreshold;

      // Disconnect page controls from the visual tree
      this.DraggableContent.Children.Clear();
      this.CurrentPage = isDragAccepted
        ? NextPage
        : this.PreviousPage;
      this.TranslateTransform.X = 0;

      // TODO::Generate and set next page or null if last page reached      
      this.NextPage = this.BluePage;
    }
  }
}

MainWindow.xaml

<Window>

  <!-- Allow content to exceed the Window -->
  <ScrollViewer HorizontalScrollBarVisibility="Hidden"
                VerticalScrollBarVisibility="Hidden">
    <ContentPresenter x:Name="PageHost"
                      Content="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=CurrentPage}">
      <ContentPresenter.RenderTransform>
        <TranslateTransform x:Name="TranslateTransform" />
      </ContentPresenter.RenderTransform>
    </ContentPresenter>
  </ScrollViewer>
</Window>

PageControl.xaml

<UserControl>
  <Grid Background="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=Background}" />
</UserControl>