【问题标题】:A Simple Photo Album with Pinch and Zoom using FlipView使用 FlipView 进行捏合和缩放的简单相册
【发布时间】:2013-01-18 00:29:03
【问题描述】:

我正在尝试使用翻转视图创建一个简单的相册(Windows 应用商店应用程序)。

我在 ScrollViewer 中嵌入了 Image 元素。我可以浏览照片,但我想做以下事情。

  • 图像应该均匀地填充屏幕的高度[当图像未缩放时]。我得到几个项目的垂直滚动条。当所有图像的高度相同时,我没有这个问题。
  • 当我更改屏幕方向时,图像的一部分在右侧被剪裁。
  • 当我在页面之间移动时,滚动查看器应该忘记缩放级别(将缩放系数重置为 1)。

这是我现在拥有的代码。我究竟做错了什么?我应该在 EventHandler 中添加什么来重置 ScrollViewer 的缩放系数。

<FlipView 
    Name="MainFlipView"
    Margin="0"
    Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
    Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
    Background="Black">
         <FlipView.ItemTemplate>
              <DataTemplate>
                  <ScrollViewer Name="myScrollViewer" ZoomMode="Enabled"
                                Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
                                Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                HorizontalScrollBarVisibility="Auto"
                                VerticalScrollBarVisibility="Auto"
                                MinZoomFactor="0.5"
                                MaxZoomFactor="2.5"
                                Margin="0" >
                       <Image Source="{Binding Path=Image}"
                              Name="MainImage" Stretch="Uniform" />
                  </ScrollViewer>
            </DataTemplate>
        </FlipView.ItemTemplate>
    </FlipView>

【问题讨论】:

    标签: c# xaml microsoft-metro windows-store-apps .net-4.5


    【解决方案1】:

    为什么在 FlipViewItemTemplate 中有一个 ScrollViewer? Thie 模板将用于每个项目,因此对于您添加到项目列表的每个图像。 也就是说,在模板中包含 Image 元素就足够了。 这至少应该避免比屏幕大的图像的滚动条,因为 Stretch="Uniform" 应该处理调整大小...

    【讨论】:

    • 在这种情况下我如何处理缩放?
    【解决方案2】:

    尝试将滚动查看器的高度和宽度绑定更改为图像。

    <FlipView 
        Name="MainFlipView"
        Margin="0"
        Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
        Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
        Background="Black">
             <FlipView.ItemTemplate>
                  <DataTemplate>
                      <ScrollViewer Name="myScrollViewer" ZoomMode="Enabled"
    
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center"
                                    HorizontalScrollBarVisibility="Auto"
                                    VerticalScrollBarVisibility="Auto"
                                    MinZoomFactor="0.5"
                                    MaxZoomFactor="2.5"
                                    Margin="0" >
                           <Image Source="{Binding Path=Image}"
                                          Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}"
                                          Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}"
                                          Name="MainImage" Stretch="Uniform" />
                      </ScrollViewer>
                </DataTemplate>
            </FlipView.ItemTemplate>
        </FlipView>
    

    【讨论】:

      【解决方案3】:

      user2199147 所说的应该解决您的第一个要点,另外两个我必须以编程方式修复,但应该注意我还必须使用您必须导入的 VisualTreeHelper 类,以及扩展方法来帮助我使用辅助类。

      首先,我必须从VisualTreeHelper 扩展中找到一个方法,它可以找到FlipView 中任何类型的第一个元素:

      private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
      {
          if (parentElement != null)
          {
              var count = VisualTreeHelper.GetChildrenCount(parentElement);
              if (count == 0)
                  return null;
      
              for (int i = 0; i < count; i++)
              {
                  var child = VisualTreeHelper.GetChild(parentElement, i);
      
                  if (child != null && child is T)
                      return (T)child;
                  else
                  {
                      var result = FindFirstElementInVisualTree<T>(child);
                      if (result != null)
                      {
                          return result;
                      }
                  }
              }
          }
          return null;
      }
      

      为了进入纵向模式,我为WindowSizeChanged 添加了一个回调处理程序,并简单地将翻转视图中的所有ScrollViewers 重置为默认值

      private void WindowSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
      {
          //Reset scroll view size
          int count = MainFlipView.Items.Count;
          for(int i = 0; i < count; i++)
          {
              var flipViewItem = MainFlipView.ItemContainerGenerator.ContainerFromIndex((i));
              var scrollViewItem = FindFirstElementInVisualTree<ScrollViewer>(flipViewItem);
              if (scrollViewItem is ScrollViewer)
              {
                  ScrollViewer scroll = (ScrollViewer)scrollViewItem;
                  scroll.Height = e.Size.Height; //Reset width and height to match the new size
                  scroll.Width = e.Size.Width;
                  scroll.ZoomToFactor(1.0f);//Zoom to default factor
              }
          }
      }
      

      然后在您的构造函数中,您需要 Window.Current.SizeChanged += WindowSizeChanged; 才能调用回调。

      现在,为了将每个 ScrollViewer 设置回它们的默认位置,我们执行类似的过程,仅当 FlipView 选择更改时,我们将 ScrollViewer 重置为其默认值缩放系数

      private void FlipViewSelectionChanged(object sender, SelectionChangedEventArgs e)
      {
          if (sender is FlipView)
          {
              FlipView item = (FlipView)sender;
              var flipViewItem = ((FlipView)sender).ItemContainerGenerator.ContainerFromIndex(((FlipView)sender).SelectedIndex);
              var scrollViewItem = FindFirstElementInVisualTree<ScrollViewer>(flipViewItem);
              if (scrollViewItem is ScrollViewer)
              {
                  ScrollViewer scroll = (ScrollViewer)scrollViewItem;
                  scroll.ScrollToHorizontalOffset(0);
                  scroll.ScrollToVerticalOffset(0);
                  scroll.ZoomToFactor(1.0f);
              }
          }
      }
      

      同样,我们必须在构造函数中调用类似于MainFlipView.SelectionChanged += FlipViewSelectionChanged;

      我知道这些方法看起来很老套和迂回,因为它们确实如此,但它对我有用,我希望这会有所帮助。

      【讨论】:

      • 感谢这对我有用。但即使在 FlipView, Height="{Binding ActualHeight, ElementName=pageRoot, Mode=OneWay}" Width="{Binding ActualWidth, ElementName=pageRoot, Mode=OneWay}" 我必须设置新的高度和宽度WindowSizeChanged 事件处理程序。
      • 啊,是的。我也有这个问题。我对 Windows 8 API 之类的不是很熟悉,所以我所做的大部分工作都非常老套。
      【解决方案4】:

      WinRT 的良好做法是:

      1) 为 ScrollViewer 制作附加属性,这将改变 ZoomFactor

      public class ScrollViewerExtension : DependencyObject
      {
          public static readonly DependencyProperty ScrollViewerZoomFactorProperty = DependencyProperty.RegisterAttached(
              "ScrollViewerZoomFactor", typeof(double), typeof(ScrollViewerExtension), new PropertyMetadata(default(double), OnZoomFactorChanged));
      
          public static void SetScrollViewerZoomFactor(DependencyObject element, double value)
          {
              element.SetValue(ScrollViewerZoomFactorProperty, value);
          }
      
          public static double GetScrollViewerZoomFactor(DependencyObject element)
          {
              return (double)element.GetValue(ScrollViewerZoomFactorProperty);
          }
      
          private static void OnZoomFactorChanged(DependencyObject depObject, DependencyPropertyChangedEventArgs args)
          {
              if (depObject is ScrollViewer)
              {
                  var scrollViewer = (ScrollViewer)depObject;
                  var zoomValue = (double)args.NewValue;
                  if (!Double.IsNaN(zoomValue))
                      scrollViewer.ZoomToFactor((float)zoomValue);
              }
              else
              {
                  throw new Exception("ARE YOU KIDDING ME ? ITS NOT SCROLLVIEWER");
              }
          }
      }
      

      2) 转换器 FlipViewItem 模板

      <Style TargetType="FlipViewItem">
          <Setter Property="Template">
              <Setter.Value>
                  <ControlTemplate>
                      <Grid Width="1040">
                          <ScrollViewer HorizontalAlignment="Stretch"
                                        HorizontalScrollBarVisibility="Auto"
                                        MaxZoomFactor="4"
                                        MinZoomFactor="1"
                                        Tag="{Binding IsSelected}"
                                        VerticalScrollBarVisibility="Auto"
                                        VerticalScrollMode="Auto"
                                        ZoomMode="Enabled"
                                        extension:ScrollViewerExtension.ScrollViewerZoomFactor="{Binding  RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected, Converter={StaticResource IsSelectedToZoom}}">
                              <ContentPresenter />
                          </ScrollViewer>
                      </Grid>
                  </ControlTemplate>
              </Setter.Value>
          </Setter>
      </Style>
      

      3) 创建转换器,如果未选择项目,它将将 ScrollViewerZoomFactor 更改为默认值。

      public class IsSelectedToZoomConverter :DependencyObject, IValueConverter
      {
      
          public object Convert(object value, Type targetType, object parameter, string language)
          {
              var val = (bool) value;
              return val ? Double.NaN : 1.0;
          }
      
          public object ConvertBack(object value, Type targetType, object parameter, string language)
          {
              throw new NotImplementedException();
          }
      }
      

      4) FlipView 代码如下所示:

      <FlipView x:Name="FlipView"
                Grid.Row="5"
                Width="1040"
                MinHeight="392"
                MaxHeight="600"
                ItemsSource="{Binding Path=CurrentSession.Photos}"
                Visibility="{Binding CurrentSession.HasContent,
                                     Converter={StaticResource BoolToVisibility}}">
        <FlipView.ItemContainerStyle>
          <Style TargetType="FlipViewItem">
            <Setter Property="Template">
              <Setter.Value>
                <ControlTemplate>
                  <Grid Width="1040">
                    <ScrollViewer HorizontalAlignment="Stretch"
                                  HorizontalScrollBarVisibility="Auto"
                                  MaxZoomFactor="4"
                                  MinZoomFactor="1"
                                  Tag="{Binding IsSelected}"
                                  VerticalScrollBarVisibility="Auto"
                                  VerticalScrollMode="Auto"
                                  ZoomMode="Enabled"
                                  extension:ScrollViewerExtension.ScrollViewerZoomFactor="{Binding RelativeSource={RelativeSource TemplatedParent},
                                                                                                   Path=IsSelected,
                                                                                                   Converter={StaticResource IsSelectedToZoom}}">
                        <ContentPresenter />
                    </ScrollViewer>
                  </Grid>
                </ControlTemplate>
              </Setter.Value>
            </Setter>
          </Style>
      
          </FlipView.ItemContainerStyle>
          <FlipView.ItemTemplate>
            <DataTemplate>
              <Image HorizontalAlignment="Stretch" Source="{Binding Path=Path}" />
            </DataTemplate>
          </FlipView.ItemTemplate>
      </FlipView>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-07
        • 2012-09-08
        • 2017-03-24
        • 2014-11-02
        • 2014-10-23
        • 1970-01-01
        相关资源
        最近更新 更多