2017-01-05 2 views
1

Au travail, nous avons construit une application complexe en utilisant C#/WPF et le canevas MVVM. Dans l'application, nous avons une toile. Sur cette toile, nous affichons une image au centre de la toile. Nous voulons pouvoir mettre à l'échelle et traduire l'image. Nous pouvons spécifier un facteur d'échelle pour mettre à l'échelle tous les éléments du canevas. Pour appliquer des transformations à l'image, nous avons lié un TransformGroup à la propriété RenderTransform de l'image dans XAML. Le TransformGroup est construit dans le modèle de vue en ajoutant d'abord le ScaleTransform suivi du TranslateTransform.Problèmes lors de la mise à l'échelle et de la traduction de l'image sur le canevas

Les transformations sont spécifiées de cette façon:

// View model 
// Global fileds 
private ScaleTransform scaleTransform = new ScaleTransform(1, 1); 
private TranslateTransform translateTransform = new TranslateTransform(0, 0); 
private Vector totalShift = new Vector(0, 0); 

... 

public void ApplyTransformations() { 
    scaleTransform.ScaleX = scaleFactor; 
    scaleTransform.ScaleY = scaleFactor; 

    translateTransform.X = canvasCenter.X - imageWidth/2; 
    translateTransform.Y = canvasCenter.Y - imageHeight/2; 
} 

Maintenant, nous sommes en mesure de redimensionner l'image correctement lors du changement du facteur d'échelle.

Pour permettre la traduction de l'image, nous mettons l'image dans un pouce. Le pouce fournit un événement DragDelta qui nous donne le décalage dans les directions x et y. Ce décalage est ajouté à totalShift chaque fois que nous faisons glisser le pouce. La méthode suivante fait partie du modèle de vue et est appelée par le gestionnaire d'événements DragDelta dans le code derrière la vue.

public void addShift(double horizontal, double vertical) { 
    totalShift.X += horizontal; 
    totalShift.Y += vertical; 
} 

ApplyTransformations() est modifié comme suit:

private double prevScaleFactor = 0; 

public void ApplyTransformations() { 
    double oldCenterX = scaleTransform.CenterX; 
    double oldCenterY = scaleTransform.CenterY; 

    scaleTransform.CenterX = -totalShift.X; 
    scaleTransform.CenterY = -totalShift.Y; 

    translateTransform.X = (canvasCenter.X - imageWidth/2) + (scaleTransform.CenterX - oldCenterX) * prevScaleFactor; 
    translateTransform.Y = (canvasCenter.Y - imageHeight/2) + (scaleTransform.CenterY - oldCenterY) * prevScaleFactor; 

    scaleTransform.ScaleX = scaleFactor; 
    scaleTransform.ScaleY = scaleFactor; 

    prevScaleFactor = scaleFactor; 
} 

Le problème: Disons que scaleFactor est de 1,5 et nous avons traîné l'image 100 px dans la direction x. Lorsque nous exécutons ApplyTransformation(), l'image n'est pas décalée de 100 px dans la direction x, mais seulement 100/1,5 = 66,67 px. Cela signifie que le décalage est mis à l'échelle avant d'être appliqué.

Comment pouvons-nous y parvenir? Toute aide est appréciée. Merci d'avance.

Edit: Le TransformGroup est construit de cette façon:

private TransformGroup _transform = new TransformGroup(); 
public TransformGroup Transform { 
    get { 
     _transformGroup.Children.Clear(); 
     _transformGroup.Children.Add(scaleTransform); 
     _transformGroup.Children.Add(translateTransform); 
    } 
} 

Si je le fais de cette façon le problème décrit ci-dessus occures.

Edit 2

J'ai créé un MCVE, vous pouvez l'exécuter et voir le problème. Changer le facteur d'échelle à une valeur différente de 1.0. Ensuite, faites glisser la toile noire avec votre souris loin du point rouge (point central) et modifiez le facteur d'échelle à nouveau. Maintenant, la toile noire semble sauter un peu.

+1

Modifier l'ordre des enfants du TransformGroup? – Clemens

+0

Avez-vous également corrigé le CenterX et le CenterY de ScaleTransform? Vous pourriez peut-être mieux définir RenderTansformOrigin de l'image. – Clemens

+0

J'ai défini RenderTransformOrigin sur totalShift négatif au lieu de définir CenterX et CenterY de la transformation d'échelle, mais cela n'a pas fonctionné. – ooorndtski

Répondre

0

Je crois que vous appliquez vos transformations dans le mauvais ordre. Vous traduisez d'abord, puis vous mettez à l'échelle. Vous devriez plutôt essayer d'appliquer votre changement d'échelle à votre image, suivi de toute rotation à votre image (dans cet exemple, vous n'en utilisez pas), suivie de toutes les traductions.

Vérifiez cette article MSDN pour plus d'informations sur l'ordre des transformations: https://msdn.microsoft.com/en-us/library/eews39w7(v=vs.110).aspx

+0

J'ai mis à jour mon message. Si je change l'ordre des enfants, l'image ne se redimensionne plus correctement, même si la première mise à l'échelle, puis la traduction semble correcte. – ooorndtski

+0

Assurez-vous que vos transformations sont correctement configurées en suivant les conseils de @Clemens ci-dessus. – RichardJones