2009-12-09 3 views
14

Das WPF Canvas hat ein Koordinatensystem, das bei (0,0) oben links im Steuerelement beginnt.WPF: Wie man das (0,0) in der Mitte eines Canvas erzeugt

Zum Beispiel die folgende Einstellung meiner Kontrolle erscheinen auf der oberen linken:

<Control Canvas.Left="0" Canvas.Top="0"> 

Wie kann ich es zum Standard cartesian coordinates ändern?

Grundsätzlich:

  • (0,0) in der Mitte
  • Flip Y

I bemerkte this post ähnlich ist, aber es spricht nicht über das Koordinatensystem zu übersetzen. Ich habe versucht, eine TranslateTransform hinzuzufügen, aber ich kann es nicht funktionieren lassen.

Antwort

5

Die beste Sache ist, ein benutzerdefiniertes Canvas zu schreiben, in dem Sie ArrangeOverride so schreiben können, dass es 0,0 als das Zentrum nimmt.

Update: Ich hatte einen weiteren Kommentar in der folgenden Antwort (@decasteljau) Ich werde nicht von Canvas abzuleiten empfehlen, können Sie von Panel ableiten und fügen Sie zwei Attached Dependancy Eigenschaften Top und Left und den gleichen Code oben eingefügt. Auch braucht es keinen Konstruktor mit LayoutTransform, und verwenden Sie keine Transformation auf dem Panel-Code verwenden Sie die richtige Maßnahme und ordnen Sie auf der DesiredSize des Panels Anordnen, so dass Sie nette Inhalte Größe Verhalten auch bekommen können. Canvas positioniert Elemente nicht dynamisch, wenn sich die Canvas-Größe ändert.

+0

ok, das war was ich dachte. Danke, du hast es bestätigt. – decasteljau

+0

Leider ist diese Antwort falsch :-(. Eine benutzerdefinierte Leinwand ist viel mehr Arbeit als nötig: Sie können genau denselben Effekt ohne Arbeit erzielen, indem Sie die Leinwandhöhe/-breite auf Null setzen, sie in ihrem Behälter zentrieren und spiegeln es auf render. Siehe meine Antwort. –

+0

Ich stimme Ihrer Antwort @ Ray, aber wenn Sie eine re aisable Lösung, dann empfehle ich nicht Ihre Antwort., was bedeutet, wenn ich mein Kind Canvas.Left = 0,5 und Canvas. Oben = 0,5, wenn Sie die Größe des übergeordneten Fensters/Canvas ändern, wird die untergeordnete Position total durcheinander gebracht.Aber wenn Sie ein richtiges benutzerdefiniertes Steuerelement schreiben (nur 10-15 Zeilen Code), wird es immer auf (0.5.0.5) positioniert. Daher empfehle ich, ein benutzerdefiniertes Panel zu schreiben - Dieses resultierende 'UnitPanel' ist ein sehr nützliches als normales Canvas. :) –

6

Es war sehr einfach zu tun. Ich habe den Code von Original Canvas mit .NET Reflector betrachtet und festgestellt, dass die Implementierung sehr einfach ist. Das einzige, was erforderlich war die Funktion außer Kraft zu setzen ArrangeOverride(...)

public class CartesianCanvas : Canvas 
{ 
    public CartesianCanvas() 
    { 
     LayoutTransform = new ScaleTransform() { ScaleX = 1, ScaleY = -1 }; 
    } 
    protected override Size ArrangeOverride(Size arrangeSize) 
    { 
     Point middle = new Point(arrangeSize.Width/2, arrangeSize.Height/2); 

     foreach(UIElement element in base.InternalChildren) 
     { 
      if(element == null) 
      { 
       continue; 
      } 
      double x = 0.0; 
      double y = 0.0; 
      double left = GetLeft(element); 
      if(!double.IsNaN(left)) 
      { 
       x = left; 
      } 

      double top = GetTop(element); 
      if(!double.IsNaN(top)) 
      { 
       y = top; 
      } 

      element.Arrange(new Rect(new Point(middle.X + x, middle.Y + y), element.DesiredSize)); 
     } 
     return arrangeSize; 
    } 
} 
+0

gut, aber ich werde nicht empfehlen abgeleitet von Canvas, Sie können von Panel ableiten und fügen Sie zwei Attached Dependancy Eigenschaften Top und Left und fügen Sie den gleichen Code, den Sie oben eingefügt. Außerdem benötigt es keinen Konstruktor mit LayoutTransform. –

+0

@JobiJoy "Panel und fügen Sie zwei Attached Dependancy-Eigenschaften oben und links und fügen Sie den gleichen Code, den Sie oben eingefügt" Kannst du es zeigen? – RobinAtTech

+1

Dies ist das Beispiel, das das tut, was Sie wahrscheinlich wollen. Die anderen sind nette Abkürzungen, werden aber ziemlich leicht scheitern, wie wenn man Rasterlinien auf die Leinwand zeichnet (seit actualSize = 0) etc. – Spiked3

25

Es gibt keine Notwendigkeit, eine benutzerdefinierte Panels zu erstellen. Leinwand wird gut tun. wickeln Sie es einfach in einem anderen Steuerelement (wie eine Grenze), zentriert, gibt ihm die Größe Null, und drehen Sie sie mit einem Render:

<Border> 
    <Canvas HorizontalAlignment="Center" VerticalAlignment="Center" 
      Width="0" Height="0" 
      RenderTransform="1 0 0 -1 0 0"> 
    ... 
    </Canvas> 
</Border> 

Sie können dies tun, und alles, was in der Leinwand wird noch erscheinen, mit Ausnahme von (0,0) wird in der Mitte des enthaltenden Steuerelements sein (in diesem Fall die Mitte des Randes) und + Y wird oben statt unten sein.

Auch hier gibt es keine Notwendigkeit, um ein benutzerdefiniertes Panel dafür zu erstellen.

+0

@Ray, super, ich war auf der Suche nach sowas. Ich kann jedoch keine Klicks auf der Arbeitsfläche erfassen. Gibt es eine Lösung? –

+0

@Bruno: Wie jedes Panel ist Canvas vollständig am Event-Routing beteiligt. Sie können Mausereignisse auf der Canvas-Ebene oder in ihrem Container behandeln. Es malt jedoch selbst nichts und nimmt somit nicht am Treffertest teil. Wenn Sie auf einen leeren Bereich der Zeichenfläche klicken möchten, der als Klick auf die Zeichenfläche erkannt werden soll, fügen Sie einfach ein Rechteck mit Füllung = "Transparent" hinzu, das die gesamte Zeichenfläche abdeckt. Dieses Rechteck erhält Klick-Events, die natürlich auf die Leinwand und darüber hinaus geleitet werden, so dass sie auf jeder Ebene bearbeitet werden können. –

+0

@Ray, ich habe eine Anwendung, die Canvas benötigt, um zentriert zu werden (0, 0). Ich habe es so gemacht, wie du es hier erklärt hast. Aber die Leinwandgröße bleibt 0, obwohl ich Linien darauf zeichne oder das Fenster maximiere. Muss ich etwas anderes tun als das, was Sie erwähnt haben? – Shankar

5

Sie können den Ursprung einfach mit RenderTransformOrigin ändern.

<Canvas Width="Auto" Height="Auto" 
      HorizontalAlignment="Center" 
      VerticalAlignment="Center" 
      RenderTransformOrigin="0.5,0.5"> 
     <Canvas.RenderTransform> 
      <TransformGroup> 
       <ScaleTransform ScaleY="-1" ScaleX="1" /> 
      </TransformGroup> 
     </Canvas.RenderTransform> 
    </Canvas> 
Verwandte Themen