none
Bild drehen in einer Grid-Row RRS feed

  • Frage

  • Hallo,

    ich habe folgenden, einfachen Aufbau:

    <Grid>
    	<Grid.RowDefinitions>
    		<RowDefinition Height="50"/>
    		<RowDefinition/>
    	</Grid.RowDefinitions>
    	<Button Name="btnRotate" Click="btnRotate_Click">Drehen</Button>
    	<Image Name="img" Grid.Row="1" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Source="Beispiel.jpg"/>
    </Grid

    Im CodeBehind wurde nur ein Ereignishandler definiert:

    private void btnRotate_Click(object sender, RoutedEventArgs e)
    {
      img.RenderTransform = new RotateTransform(90);
    }

    Das ganze sieht so aus:

    Der Benutzer soll die Möglichkeit erhalten, das Bild um 90° zu drehen. Wenn man nun auf den Button klickt, steht das Bild über:

    Warum kann ich mir leider nicht erklären. VerticalAligment und HorizontalAligment sind beide auf Stretch gesetzt. Ich würde eine möglichst nicht rechenintensive Lösung bevorzugen. Desweiteren wird das Bild hinterher direkt nach dem Laden eingefroren (mittels Freeze()); somit kann ich das Bild nicht mehr direkt drehen sondern nur den Container.

    Freitag, 1. September 2017 14:20

Antworten

  • Du kannst die Skalierung über ein paar Winkelbeziehungen berechnen.

    Der dazugehörige Code sieht wie folgt aus:

    void RotateImage(double angleInDegree)
    {
        double angleInRadian = angleInDegree / 180 * Math.PI;
        double actualHeight = this.img.ActualHeight;
        double actualWidth = this.img.ActualWidth;
    
        double h1 = actualWidth * Math.Sin(angleInRadian);
        double h2 = actualHeight * Math.Cos(angleInRadian);
        double rotateHeight = Math.Abs(h1) + Math.Abs(h2);
        double scale = actualHeight / rotateHeight;
    
        TransformGroup transformGroup = new TransformGroup();
        transformGroup.Children.Add(new RotateTransform(angleInDegree));
        transformGroup.Children.Add(new ScaleTransform(scale, scale));
        this.img.RenderTransform = transformGroup;
    }

    Und die dazugehörige Anwendung so:

    Wenn ActualHeight und ActualWidth 0.0 sind, dürfte glaube ich ein Aufruf von Measure() und Arrange() Abhilfe schaffen.

    Beste Grüße

    Sonntag, 3. September 2017 15:48

Alle Antworten

  • Hi,
    so richtig habe ich Dein Problem nicht verstanden.

    Mit dem RotateTransform wird die Anzeige gedreht. Die Breite, die in Deinem Fall dann die dargestellte Höhe ist, wird dadurch nicht verändert, da die Anzeige (Grafikkarte) ja nicht weiß, dass da etwas anzupassen ist. Das musst Du schon selbst mit einem zusätz6lichen ScaleTransform machen, welches auf das Verhältnis Höhe/Breite skailert.


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks



    Freitag, 1. September 2017 14:48
  • Achso, ich dachte, dass sich der Image-Container automatisch an die neuen Größen anpasst, da VerticalAligment und HorizontalAligment beide auf Stretch gesetzt sind. Wie würde man eine passende Scale-Transform realisieren? Mir würde nur einfallen, anhand von ActualWidth und ActualHeight die Skalierung zu berechnen. Nur leider habe ich damit schlechte Erfahrungen gemacht; die Werte sind manchmal einfach 0.
    Freitag, 1. September 2017 15:30
  • Mittlerweile habe ich eine Lösung über den CodeBehind gefunden. Das Problem ist aber, dass der GC die nicht mehr benötigten Objekte im Speicher hält und so der Arbeitsspeicherverbrauch massiv ist. Wenn man das noch beheben könnte, wäre ich zufrieden.

    Der neue CodeBehind:

    public partial class MainWindow : Window
    {
    	private BitmapSource bmp;
    	public MainWindow()
    	{
    		InitializeComponent();
    
    		//Bild laden
    		bmp = new BitmapImage(new Uri("pack://application:,,,/WpfRotateSample;component/Beispiel.JPG", UriKind.Absolute));
    		bmp.Freeze();
    		img.Source = bmp;
    	}
    
    	private void btnRotate_Click(object sender, RoutedEventArgs e)
    	{
    		bmp = new TransformedBitmap(bmp, new RotateTransform(90));
    		bmp.Freeze();
    		img.Source = bmp;
    	}
    }
    In XAML wurde die Source Eigenschaft des Image Containers entfernt.

    Samstag, 2. September 2017 07:53
  • Du kannst die Skalierung über ein paar Winkelbeziehungen berechnen.

    Der dazugehörige Code sieht wie folgt aus:

    void RotateImage(double angleInDegree)
    {
        double angleInRadian = angleInDegree / 180 * Math.PI;
        double actualHeight = this.img.ActualHeight;
        double actualWidth = this.img.ActualWidth;
    
        double h1 = actualWidth * Math.Sin(angleInRadian);
        double h2 = actualHeight * Math.Cos(angleInRadian);
        double rotateHeight = Math.Abs(h1) + Math.Abs(h2);
        double scale = actualHeight / rotateHeight;
    
        TransformGroup transformGroup = new TransformGroup();
        transformGroup.Children.Add(new RotateTransform(angleInDegree));
        transformGroup.Children.Add(new ScaleTransform(scale, scale));
        this.img.RenderTransform = transformGroup;
    }

    Und die dazugehörige Anwendung so:

    Wenn ActualHeight und ActualWidth 0.0 sind, dürfte glaube ich ein Aufruf von Measure() und Arrange() Abhilfe schaffen.

    Beste Grüße

    Sonntag, 3. September 2017 15:48