2
votes

I am trying to create a photo viewer using a flipview which needs to have pinch to zoom functionality.

I am using a scrollviewer to enable the capability to zoom and this is my XAML.

<FlipView x:Name="FlipView1">
    <FlipView.ItemTemplate>
         <DataTemplate>
             <ScrollViewer HorizontalScrollBarVisibility="Visible"
                           VerticalScrollBarVisibility="Visible"
                           VerticalAlignment="Stretch" 
                           HorizontalAlignment="Stretch" 
                           ZoomMode="Enabled" MinZoomFactor="1" MaxZoomFactor="3"
                           ViewChanged="ScrollViewer_ViewChanged"
                           SizeChanged="ScrollViewer_SizeChanged">
                           <StackPanel Orientation="Horizontal">
                                <Image Source="{Binding Image}" Stretch="Uniform" />
                            </StackPanel>
             </ScrollViewer>
         </DataTemplate>
     </FlipView.ItemTemplate>
</FlipView>

In my code-behind I am changing the image size to scrollviewer.viewport height and width respectively.

private void ScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            ScrollViewer x = sender as ScrollViewer;
            Image img = FindFirstElementInVisualTree<Image>(FlipView1);
            img.Height = x.ViewportHeight;
            img.Width = x.ViewportWidth;
        }

The problems that I face are:

1) When an image is big in size, the image does not resize to fit uniformly and overflows the control/screen area. The Scrollviewer_sizeChanged handler takes care of the first image only and the rest images in the flipview remain big.

2) When we pinch to zoom in, the black/unused area ie. the blank area which does not have the image also gets zoomed in and scroll area is not restricted to the image only. How should I do this, as this really spoils the experience.

Please help! I have already seen a lot of resources/stackoverflow questions but nothing helps, as a lot of them pertain to Silverlight or the previous versions of windows phone.

PLEASE NOTE, we are developing for Windows Phone 8.1 XAML (WINRT) App.

1
At the end of this blog post I explain how to set the image size to be just right for the size of the screen, which answers your first question igrali.com/2015/07/16/…Igor Ralic

1 Answers

1
votes

Your xaml code should look like this:

<Page x:Name="page">

    <FlipView x:Name="ImageBrowser" 
              ItemsSource="{Binding Images}">
        <FlipView.ItemTemplate>
            <DataTemplate>
                    <ScrollViewer
                              ZoomMode="Enabled" 
                              MinZoomFactor="1"
                              MaxZoomFactor="4"
                              HorizontalScrollBarVisibility="Auto"
                              VerticalScrollBarVisibility="Auto" 
                              VerticalScrollMode="Auto">

                        <Image Source="{Binding source}" 
                           MaxWidth="{Binding DataContext.OptimalWidth, ElementName=page}"
                           MaxHeight="{Binding DataContext.OptimalHeight, ElementName=page}"/>

                    </ScrollViewer>
            </DataTemplate>
        </FlipView.ItemTemplate>
    </FlipView>
</Page>

You need to create your own ViewModel for this and bind its properties to Image in FlipView data template

Here is an example of my ViewModel:

public class BrowserViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private double optimalWidth;
    private double optimalHeight;

    public double OptimalWidth
    {
        get { return this.optimalWidth;}
        set
        {
            if (this.optimalWidth != value)
            {
                this.optimalWidth = value;
                NotifyPropertyChanged("OptimalWidth");
            }
        }
    }

    public double OptimalHeight
    {
        get { return this.optimalHeight; }
        set
        {
            if (this.optimalHeight != value)
            {
                this.optimalHeight = value;
                NotifyPropertyChanged("OptimalHeight");
            }
        }
    }

    protected void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (this.PropertyChanged != null)
        {
           PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

When you have your ViewModel ready to go, you need to add it to your page. It is easy, create public Class and in a method OnNavigatedTo assign it. Here is an example:

public BrowserViewModel ViewModel { get; set; }
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {

        ViewModel = new BrowserViewModel();//creating new instance
        DataContext = ViewModel;//setting view model as data context - later used in binding
    }

And now in a Page_SizeChanged method you will set the required size for your image.

private void page_SizeChanged(object sender, SizeChangedEventArgs e)
{
    ViewModel.OptimalWidth = e.NewSize.Width; //new width of the page
    ViewModel.OptimalHeight = e.NewSize.Height; //new height of the page
}

Now look back into the xaml, notice that the image takes it's maximum width and height from that ViewModel I created.

<Image Source="{Binding source}" 
    MaxWidth="{Binding DataContext.OptimalWidth, ElementName=page}"
    MaxHeight="{Binding DataContext.OptimalHeight, ElementName=page}"/>

I used this in my application, hope this will work for you.