Масштабирование и панорамирование работают только с первой попытки с помощью прослушивателя жестов для Windows Phone.

Я новичок в разработке для Windows Phone и пытаюсь использовать Microsoft.Phone.Controls.Toolkit для масштабирования и панорамирования изображения. Моя проблема в том, что масштабирование и панорамирование работают только с первой попытки. Если я масштабирую/панорамирую изображение, иду в другое место в приложении, а затем возвращаюсь к изображению, оно ничего не делает. Метод OnPinchStarted никогда не запускается, когда он должен быть вызван. Я использовал несколько разных способов, которые нашел здесь и в других местах для прослушивателя жестов. Код размещен ниже. Прежде чем я пойду другим путем и выброшу этот способ, я хотел посмотреть, есть ли что-то, чего мне не хватает в том, что у меня есть, потому что с первого раза это работает просто отлично.

Первая попытка:

XAML:

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Image x:Name="Map"
        Source="Images/park.png" 
          HorizontalAlignment="Center" VerticalAlignment="Center" 
          Stretch="Uniform" >
        <toolkit:GestureService.GestureListener>
            <toolkit:GestureListener
                    PinchStarted="OnPinchStarted"
                    PinchDelta="OnPinchDelta"
                    DragDelta="OnDragDelta"/>
        </toolkit:GestureService.GestureListener>
        <Image.RenderTransform>
            <CompositeTransform
                    ScaleX="1" ScaleY="1"
                    TranslateX="0" TranslateY="0"/>
        </Image.RenderTransform>
    </Image>
</Grid>  

CS:

// these two fields fully define the zoom state:
    private double TotalImageScale = 1d;
    private Point ImagePosition = new Point(0, 0);


    private const double MAX_IMAGE_ZOOM = 5;
    private Point _oldFinger1;
    private Point _oldFinger2;
    private double _oldScaleFactor;

    // Initializes the zooming operation
    private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e)
    {
        _oldFinger1 = e.GetPosition(Map, 0);
        _oldFinger2 = e.GetPosition(Map, 1);
        _oldScaleFactor = 1;
    }

    //Computes the scaling and translation to correctly zoom around your fingers.
    private void OnPinchDelta(object sender, PinchGestureEventArgs e)
    {
        var scaleFactor = e.DistanceRatio / _oldScaleFactor;
        if (!IsScaleValid(scaleFactor))
            return;

        var currentFinger1 = e.GetPosition(Map, 0);
        var currentFinger2 = e.GetPosition(Map, 1);

        var translationDelta = GetTranslationDelta(
            currentFinger1,
            currentFinger2,
            _oldFinger1,
            _oldFinger2,
            ImagePosition,
            scaleFactor);

        _oldFinger1 = currentFinger1;
        _oldFinger2 = currentFinger2;
        _oldScaleFactor = e.DistanceRatio;

        UpdateImageScale(scaleFactor);
        UpdateImagePosition(translationDelta);
    }

    //Moves the image around following your finger.
    private void OnDragDelta(object sender, DragDeltaGestureEventArgs e)
    {
        var translationDelta = new Point(e.HorizontalChange, e.VerticalChange);

        if (IsDragValid(1, translationDelta))
            UpdateImagePosition(translationDelta);
    }

    //Computes the translation needed to keep the image centered between your fingers.

    private Point GetTranslationDelta(
        Point currentFinger1, Point currentFinger2,
        Point oldFinger1, Point oldFinger2,
        Point currentPosition, double scaleFactor)
    {
        var newPos1 = new Point(
         currentFinger1.X + (currentPosition.X - oldFinger1.X) * scaleFactor,
         currentFinger1.Y + (currentPosition.Y - oldFinger1.Y) * scaleFactor);

        var newPos2 = new Point(
         currentFinger2.X + (currentPosition.X - oldFinger2.X) * scaleFactor,
         currentFinger2.Y + (currentPosition.Y - oldFinger2.Y) * scaleFactor);

        var newPos = new Point(
            (newPos1.X + newPos2.X) / 2,
            (newPos1.Y + newPos2.Y) / 2);

        return new Point(
            newPos.X - currentPosition.X,
            newPos.Y - currentPosition.Y);
    }

    //Updates the scaling factor by multiplying the delta.
    private void UpdateImageScale(double scaleFactor)
    {
        TotalImageScale *= scaleFactor;
        ApplyScale();
    }

    //Applies the computed scale to the image control.
    private void ApplyScale()
    {
        ((CompositeTransform)Map.RenderTransform).ScaleX = TotalImageScale;
        ((CompositeTransform)Map.RenderTransform).ScaleY = TotalImageScale;
    }

    //Updates the image position by applying the delta.
    //Checks that the image does not leave empty space around its edges.
    private void UpdateImagePosition(Point delta)
    {
        var newPosition = new Point(ImagePosition.X + delta.X, ImagePosition.Y + delta.Y);

        if (newPosition.X > 0) newPosition.X = 0;
        if (newPosition.Y > 0) newPosition.Y = 0;

        if ((Map.ActualWidth * TotalImageScale) + newPosition.X < Map.ActualWidth)
            newPosition.X = Map.ActualWidth - (Map.ActualWidth * TotalImageScale);

        if ((Map.ActualHeight * TotalImageScale) + newPosition.Y < Map.ActualHeight)
            newPosition.Y = Map.ActualHeight - (Map.ActualHeight * TotalImageScale);

        ImagePosition = newPosition;

        ApplyPosition();
    }

    //Applies the computed position to the image control.
    private void ApplyPosition()
    {
        ((CompositeTransform)Map.RenderTransform).TranslateX = ImagePosition.X;
        ((CompositeTransform)Map.RenderTransform).TranslateY = ImagePosition.Y;
    }

    //Resets the zoom to its original scale and position
    private void ResetImagePosition()
    {
        TotalImageScale = 1;
        ImagePosition = new Point(0, 0);
        ApplyScale();
        ApplyPosition();
    }

    //Checks that dragging by the given amount won't result in empty space around the image
    private bool IsDragValid(double scaleDelta, Point translateDelta)
    {
        if (ImagePosition.X + translateDelta.X > 0 || ImagePosition.Y + translateDelta.Y > 0)
            return false;

        if ((Map.ActualWidth * TotalImageScale * scaleDelta) + (ImagePosition.X + translateDelta.X) < Map.ActualWidth)
            return false;

        if ((Map.ActualHeight * TotalImageScale * scaleDelta) + (ImagePosition.Y + translateDelta.Y) < Map.ActualHeight)
            return false;

        return true;
    }

    //Tells if the scaling is inside the desired range
    private bool IsScaleValid(double scaleDelta)
    {
        return (TotalImageScale * scaleDelta >= 1) && (TotalImageScale * scaleDelta <= MAX_IMAGE_ZOOM);
    }

Вторая попытка (из http://www.wintellect.com/blogs/jprosise/building-touch-interfaces-for-windows-phones-part-4)

XAML:

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid x:Name="ContentPanel" Grid.Row="1" RenderTransformOrigin="0.5,0.5" >
        <toolkit:GestureService.GestureListener>
            <toolkit:GestureListener PinchDelta="OnPinchDelta"
        PinchStarted="OnPinchStarted" DragDelta="OnDragDelta" />
        </toolkit:GestureService.GestureListener>
        <Grid.RenderTransform>
            <CompositeTransform x:Name="HambyTransform" />
        </Grid.RenderTransform>
        <Image Source="Images/trails.png" 
               HorizontalAlignment="Center" VerticalAlignment="Center" 
          Stretch="Uniform" />
    </Grid>
</Grid>

CS:

private double _cx, _cy;
private void OnPinchStarted(object sender, PinchStartedGestureEventArgs e)
    {
        _cx = HambyTransform.ScaleX;
        _cy = HambyTransform.ScaleY;
    }

    //scale the map
    private void OnPinchDelta(object sender, PinchGestureEventArgs e)
    {
        //compute the new scaling factors
        double cx = _cx * e.DistanceRatio;
        double cy = _cy * e.DistanceRatio;

        // If they're between 1.0 and 4.0, inclusive, apply them

        if (cx >= 1.0 && cx <= 4.0 && cy >= 1.0 && cy <= 4.0)
        {
            HambyTransform.ScaleX = cx;
            HambyTransform.ScaleY = cy;
        }
    }

    private void OnDragDelta(object sender, DragDeltaGestureEventArgs e)
    {
        HambyTransform.TranslateX += e.HorizontalChange;
        HambyTransform.TranslateY += e.VerticalChange;
    }

person KFP    schedule 15.11.2013    source источник


Ответы (1)


После многих попыток найти исправление, чего я так и не сделал, я начал все сначала с нового проекта, и проблема исчезла. Масштаб/панорамирование работает нормально. Я не знаю, что произошло, или что-то внутри моего проекта было повреждено, но теперь оно работает. Я надеюсь, что это поможет любому, кто сталкивается с той же проблемой. Мне пришлось много копировать/вставлять код, но это сработало.

person KFP    schedule 09.12.2013