2016-12-07 2 views
1

Ich habe Windows Phone 10 (C# UWP) App und ich benutze ScrollViewer in ListView, um Folie von Bildern anzuzeigen. Beim geänderten Ereignis für scrollviewer überprüfe ich, welcher Bildcontainer für den Benutzer besser sichtbar ist und verwende die ChangeView-Methode, um das Bild als einziges auf dem Bildschirm angezeigt zu bekommen. Das alles funktioniert gut, aber wenn ich den Touchscreen drücke und halte, während ChangeView aktiv ist, ändern sich die Bilder und ich bekomme eine Fehlermeldung "Dieses Objekt wurde versiegelt, so dass diese Änderung nicht länger erlaubt ist", die ich nicht erfassen kann.Berühren Sie auf dem Bildschirm, während ScrollViewer.ChangeView aktiv ist bricht App UWP

XAML: (Hinweis, CurrentSizeConverter gibt nur sichtbare Seite Grenzen basierend auf Parameter)

<Page.Resources>    
    <DataTemplate x:Key="dtPhotoView"> 
     <Grid x:Name="grPhotoView" Width="{Binding Id, Converter={StaticResource CurrentSizeConverter}, ConverterParameter=Width}" Height="{Binding Id, Converter={StaticResource CurrentSizeConverter}, ConverterParameter=Height}"> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="*"/> 
       <RowDefinition Height="50"/> 
      </Grid.RowDefinitions> 
      <Image x:Name="imgFullSize" Source="{Binding ImageSource}" Stretch="Fill" Grid.RowSpan="2"/> 
      <Grid Grid.Row="1" x:Name="grDeleteFullImage" Background="#66000000"> 
       <Button x:Name="btnDeletePhoto" Style="{StaticResource btnActionCommandButtonStyle}" Tag="{Binding Id}" Canvas.ZIndex="10" Margin="0" Click="btnDeletePhoto_Click" Background="#66000000" Padding="10"> 
        <Button.Foreground> 
         <ImageBrush Stretch="Uniform" ImageSource="Assets/delete_icon.png"/> 
        </Button.Foreground> 
       </Button> 
      </Grid> 
     </Grid> 
    </DataTemplate> 
</Page.Resources> 

<Grid> 
    <ListView HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Visibility="Collapsed" SelectionMode="None" IsItemClickEnabled="False" x:Name="lvPhotoView" Grid.Row="0" DataContext="{Binding}" Background="Transparent" BorderThickness="0" ItemTemplate="{StaticResource dtPhotoView}" ScrollViewer.ZoomMode="Disabled" ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollMode="Enabled" ScrollViewer.VerticalScrollMode="Disabled" PointerEntered="lvPhotoView_PointerEntered"> 
     <ListView.ItemContainerStyle> 
      <Style TargetType="ListViewItem"> 
       <Setter Property="HorizontalAlignment" Value="Stretch" /> 
       <Setter Property="VerticalAlignment" Value="Stretch" /> 
       <Setter Property="HorizontalContentAlignment" Value="Stretch"/> 
       <Setter Property="Margin" Value="2" /> 
      </Style> 
     </ListView.ItemContainerStyle> 
     <ListView.ItemsPanel> 
      <ItemsPanelTemplate> 
       <ItemsStackPanel Orientation="Horizontal"/> 
      </ItemsPanelTemplate> 
     </ListView.ItemsPanel> 
    </ListView> ......... 

privaten Variablen:

private static bool _imagesShowing = false; 
private ScrollViewer _imagesViewer; 

Ereignisbehandlung:

private void lvPhotoView_PointerEntered(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e) 
{ 
    try 
    { 
     if (!_imagesShowing) 
     { 
      _imagesShowing = true; 

      if (_imagesViewer == null) 
      { 
       _imagesViewer = GetScrollViewer(lvPhotoView); 
      } 

      if (_imagesViewer != null) 
      { 
       _imagesViewer.ViewChanged += ImagesScrollViewer_OnViewChanged; 
      } 
     } 
    } 
    catch (Exception ex) 
    { 
     return; 
    } 
} 

public static ScrollViewer GetScrollViewer(DependencyObject depObj) 
{ 
    try 
    { 
     if (depObj is ScrollViewer) 
     { 
      return depObj as ScrollViewer; 
     } 

     for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) 
     { 
      var child = VisualTreeHelper.GetChild(depObj, i); 

      var result = GetScrollViewer(child); 
      if (result != null) 
      { 
       return result; 
      } 
     } 
     return null; 
    } 
    catch 
    { 
     return null; 
    } 
} 

private async void ImagesScrollViewer_OnViewChanged(object sender, ScrollViewerViewChangedEventArgs e) 
{ 
    if (!e.IsIntermediate) 
    { 
     var isDone = false; 
     try 
     { 
      _imagesViewer.ViewChanged -= ImagesScrollViewer_OnViewChanged; 
      _imagesViewer.HorizontalScrollMode = ScrollMode.Disabled; 
      _imagesViewer.IsScrollInertiaEnabled = false; 

      for (var i = 0; i < lvPhotoView.Items.Count; i++) 
      { 
       var item = lvPhotoView.Items[i]; 
       var itemContainer = lvPhotoView.ContainerFromItem(item) as ListViewItem; 

       double firstVisValue; 

       var isVisible = itemContainer.IsVisibileToUserHorizontal(sender as ScrollViewer, out firstVisValue); 

       if (isVisible && lvPhotoView.Items.Count - 1 > i) 
       { 
        var nextItem = lvPhotoView.Items[i + 1]; 
        var secondItemContainer = lvPhotoView.ContainerFromItem(nextItem) as ListViewItem; 

        double secondVisValue; 

        var isNextVisible = secondItemContainer.IsVisibileToUserHorizontal(sender as ScrollViewer, out secondVisValue); 

        if (isNextVisible) 
        { 

         _imagesViewer.ScrollToElement(firstVisValue < secondVisValue ? secondItemContainer : itemContainer); 
        } 

        await Task.Delay(800); 
        _imagesViewer.HorizontalScrollMode = ScrollMode.Enabled; 
        _imagesViewer.IsScrollInertiaEnabled = true; 
        _imagesShowing = false; 
        isDone = true; 
       } 
      } 
     } 
     finally 
     { 
      if (!isDone) 
      { 
       await Task.Delay(500); 
       _imagesViewer.HorizontalScrollMode = ScrollMode.Auto; 
       _imagesViewer.IsScrollInertiaEnabled = true; 
       _imagesShowing = false; 
      } 
     } 
    } 
} 

public static bool IsVisibileToUserHorizontal(this FrameworkElement element, FrameworkElement container, out double visValue) 
{ 
    visValue = 0; 

    if (element == null || container == null) 
    { 
     return false; 
    } 

    if (element.Visibility != Visibility.Visible) 
    { 
     return false; 
    } 

    var elementBounds = element.TransformToVisual(container).TransformBounds(new Rect(0.0, 0.0, element.ActualWidth, element.ActualHeight)); 
    var containerBounds = new Rect(0.0, 0.0, container.ActualWidth, container.ActualHeight); 

    if (elementBounds.Left >= containerBounds.Left && elementBounds.Left < containerBounds.Right) 
    { 
     visValue = containerBounds.Right - elementBounds.Left; 
     return true; 
    } 

    if (elementBounds.Right >= containerBounds.Left && elementBounds.Right < containerBounds.Right) 
    { 
     visValue = elementBounds.Right - containerBounds.Left; 
     return true; 
    } 

    return false; 
} 

public static void ScrollToElement(this ScrollViewer scrollViewer, UIElement element, bool isHorizontalScrolling = true, bool smoothScrolling = true, float? zoomFactor = null) 
{ 
    var transform = element.TransformToVisual((UIElement)scrollViewer.Content); 
    var position = transform.TransformPoint(new Point(0, 0)); 

    if (isHorizontalScrolling) 
    { 
     scrollViewer.ChangeView(position.X, null, zoomFactor, !smoothScrolling); 
    } 
    else 
    { 
     scrollViewer.ChangeView(null, position.Y, zoomFactor, !smoothScrolling); 
    } 
} 

Schließlich binden jede beobachtbare Auflistungsliste mit XAML-Bindungseigenschaften wo ImageSource-Eigenschaft ist Image StorageFile (in meinem Fall sind sie alle .jpg) zu Listenansicht.

Im Wesentlichen wenn SmoothScrolling ist wahr, Scrolling ist im Gange und ich tippe und halte Element, Gegenstände Größe ändern und ich kann sie bewegen, während halten, und wenn ich loslassen App Bremsen mit unbehandelten Ausnahme von oben.

Irgendwelche Ideen?

+0

Es gibt keinen genug Code Ihr Problem zu reproduzieren. Bitte verweisen Sie [fragen], um ein reproduziertes Projekt zur Verfügung zu stellen. Zumindest wo und wie Sie die 'ScrollToElement' Methode aufrufen. –

+0

Danke für den Tipp, ich habe Code-Snippets aktualisiert, jetzt sollte alles reproduzierbar sein. Wenn Sie blättern und loslassen, wird ScrollToElement aufgerufen, und scrollview scrollt automatisch zu einem Bild, das für den Benutzer besser sichtbar ist. Während dieses automatische Scrollen geht, tippen Sie auf den Bildschirm und wischen Sie nach oben/unten und das Problem wird auftreten. – user2081328

Antwort

1

Möglicherweise stören Sie DirectManipulation, daher die Ausnahme beim Scrollen.

Was passiert ist, dass, wenn es "ein Berührungsereignis gibt, das die FlipView animiert", die Sache, die diese Animation verursacht, der in FlipView eingebaute ScrollViewer ist, der zum Spiegeln verwendet wird. Der Scrollviewer nimmt die Zeigereingabe weg, bis das Verschieben abgeschlossen ist, und kann nicht zurückgenommen werden. Dies ist eine Funktion namens DirectManipulation, die nun Eingaben in einem separaten Thread verarbeitet, um eine möglichst reibungslose Panning-Behandlung zu ermöglichen. (Pointer Ereignisse Feuer im UI-Thread) in http://social.msdn.microsoft.com/Forums/windowsapps/en-US/1e6732d3-0457-4ddc-b762-963ab974491c/pointerreleased-and-flipview

gleiches Problem begegnete hier: Why ScrollViewer fired PointerCaptureLost when starting scroll?

+0

Ich habe keine Ausnahme beim Scrollen. Noch verwende ich FlipView. Ich starte programmatisch die Animation von ScrollViewer in der ListView und dann, während die Animation läuft, wenn ich dran und hoch/runter gehe (nicht links/rechts) bekomme ich eine Ausnahme. – user2081328

+0

Ja, das Beispiel, das ich gab, war von FlipView, aber intern ist es ein ScrollViewer, genau wie in Ihrem Fall. Punkt ist, ScrollViewer verwendet direkte Manipulation, die eine hardwarebeschleunigte, exklusive Pipeline ist. Sobald Sie versuchen, mit den Daten in der Pipeline zu fummeln, werden Sie immer Ausnahmen bekommen. – MoDu

+1

Ich sehe, das gibt mir ein besseres Verständnis dafür, was das Problem verursacht und wo zu suchen. Haben Sie eine gute Idee für eine Problemumgehung (um dem Benutzer nicht zu erlauben, auf ListView zu tippen, während ScrollView den Zeiger hält, so etwas)? – user2081328

Verwandte Themen