1

I'm writing a UWP photo viewer app that has a custom control that contains a Viewbox and has custom ManipulationEvents, inside a FlipView. I want to make it so that when you are zoomed out all the way you can swipe to flip, but still able to zoom in. That's where my problem is.

When I have the viewbox set to anything except ManipulationMode = ManipulationModes.System, dragging on the viewbox does not trigger the FlipView. The problem is I want to be able to still zoom in on the image when in zoom level 1.

Basically I'd like to set something that looks like: ManipulationMode="Scale, System", where everything that's not scale would be bubbled up. Or even trigger this in code-behind.

How would I accomplish this?

Here is the basis of what I am doing:

CustomControl.xaml

<UserControl ...>
<Grid>
    <ScrollViewer ...
        ManipulationMode="System">
        <Viewbox ManipulationMode="TranslateX, TranslateY, Rotate, Scale"
            ManipulationStarted="Viewbox_OnManipulationStarted"
            ManipulationDelta="Viewbox_ManipulationDelta">
            <ContentControl Content="{Binding ElementName=MyControl, Path=ViewboxContext}" />
        </Viewbox>
    </ScrollViewer>
</Grid>


CustomControl.xaml.cs

...
void ViewboxHost_OnManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
{
    ...
}

void ViewboxHost_OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
    if (IsAtMinZoom && e.Delta.Scale <= 1)
    {
        e.Handled = false;
    } else {
        e.Handled = true;
        return;
    }

    ...
}


MainPage.xaml

<Page ...>
<Grid>
    <FlipView>
        <FlipView.Items> <!-- These will later be added view ItemsSource -->
            <FlipViewItem>
                <controls:CustomControl>
                    <Image src="..." />
                </controls:CustomControl>
            </FlipViewItem>

            <!-- More of these guys --->

        </FlipView.Items>
    </FlipView>
</Grid>
Nolan Blew
  • 374
  • 3
  • 18

1 Answers1

0

If I have correctly understand your question, you want to show a picture in each FlipViewItem, and this picture can be zoomed. When FlipView works on mobile, it can be swiped between items, and you want to make sure, this FlipView can only be swiped when the iamge's ZoomFactor = 1.

Here I wrote a sample to solve this problem, I didn't use any ViewBox and UserControl here, if you need to use them, you can change the DataTemplate in my sample:

<FlipView x:Name="flipView" ItemsSource="{x:Bind mylist}">
    <FlipView.ItemTemplate>
        <DataTemplate>
            <ScrollViewer ZoomMode="Enabled" MinZoomFactor="1" MaxZoomFactor="4" PointerPressed="ScrollViewer_PointerPressed">
                <Image Source="{Binding ImageSource}"  Stretch="Uniform" />
            </ScrollViewer>
        </DataTemplate>
    </FlipView.ItemTemplate>
</FlipView>

code behind:

private ObservableCollection<MyFlipViewItem> mylist = new ObservableCollection<MyFlipViewItem>();

public MainPage()
{
    this.InitializeComponent();
    this.Loaded += MainPage_Loaded;
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    mylist.Clear();
    mylist.Add(new MyFlipViewItem { ImageSource = "Assets/1.jpeg" });
    mylist.Add(new MyFlipViewItem { ImageSource = "Assets/1.jpeg" });
    mylist.Add(new MyFlipViewItem { ImageSource = "Assets/1.jpeg" });
    mylist.Add(new MyFlipViewItem { ImageSource = "Assets/1.jpeg" });
}

private ScrollViewer flipviewscrollviewer;

private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    flipviewscrollviewer = FindChildOfType<ScrollViewer>(flipView);
}

public static T FindChildOfType<T>(DependencyObject root) where T : class
{
    var queue = new Queue<DependencyObject>();
    queue.Enqueue(root);
    while (queue.Count > 0)
    {
        DependencyObject current = queue.Dequeue();
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(current); i++)
        {
            var child = VisualTreeHelper.GetChild(current, i);
            var typedChild = child as T;
            if (typedChild != null)
            {
                return typedChild;
            }
            queue.Enqueue(child);
        }
    }
    return null;
}

private void ScrollViewer_PointerPressed(object sender, PointerRoutedEventArgs e)
{
    var itemscrollviewer = sender as ScrollViewer;
    if (itemscrollviewer.ZoomFactor != 1)
    {
        flipviewscrollviewer.HorizontalScrollMode = ScrollMode.Disabled;
    }
    else
    {
        flipviewscrollviewer.HorizontalScrollMode = ScrollMode.Enabled;
    }
}

The MyFlipViewItem class:

public class MyFlipViewItem
{
    public string ImageSource { get; set; }
}

Here in my sample you can see that I used PointerPressed event to detect if the manipulation is started. For the reason, you can refer to my other case: ListView ManipulationCompleted event doesn't work on phone.

Community
  • 1
  • 1
Grace Feng
  • 16,564
  • 2
  • 22
  • 45
  • Thanks for the answer. However, the point of this is that I have a custom control that does a lot of other manipulation events irrelevant to the current problem, but necessary in our app. I need to be able to keep the custom control separate from the `FlipView` control. We also don't want to use the `ScrollViewer` to zoom, as it presents other problems for us (two of the big ones is not being able to rotate and loss of accurate scale factor for some of our advanced controls underneath) – Nolan Blew May 16 '16 at 18:31
  • @NolanBlew, I can understand, but you can replace the `DataTemplate` part with your usercontrol, if your control is already done the work of zoom, rotate or something else. Here I just wrote a simple sample, the point in my sample is using `VisualTreeHelper` to find the `ScrollViewer` inside of the `FlipView`, so can you disable /enable the scrolling of the `FlipView` when it is needed. You can have a try. – Grace Feng May 17 '16 at 09:05
  • I jumped the gun a bit too soon. This does work with a `ScrollViewer` inside a `FlipView`. However, This doesn't solve my Viewbox problem: When my Viewbox's manipulation mode is set to anything but `ManipulationModes.System` it takes full control over touch input, and you cannot swipe the `ScrollViewer`. However, when it is set to `ManipulationModes.System`, you can't pinch to zoom in on the `ViewBox` control (inside my custom control). I wish to do both, like the Windows 10 Photo App – Nolan Blew May 18 '16 at 21:48