2009-10-13 7 views
5

Ich muss einen Pfeil zwischen den Steuerelementen in einer Leinwand zeichnen. Zur Zeit verwende ich das Linienobjekt, aber es gibt keine Möglichkeit, ein Dreieck am Ende der Linie zu zeichnen.Wie zeichne ich einen Pfeil in Silverlight

Das ist ungefähr das, was ich brauche:

[TextBox] <----- [Button] 

Ich habe versucht, Linie, Unterklasse und ein paar Zeilen am Ende hinzufügen, aber die Klasse abgedichtet ist.

Wie würden Sie ein benutzerdefiniertes Steuerelement erstellen, das einen Pfeil zwischen X1, Y1 und X2, Y2 zeichnet?

Danke

Antwort

7

Charles Petzold hat eine Bibliothek verwendet. Die Logik sollte zumindest auf Silverlight übertragbar sein. Es verwendet Polylinien und Pfade und sollte einfach zu portieren sein.

Lines with Arrows @ Petzold Book Blog

--EDIT--

Ok - hier ist eine andere Art und Weise, darüber zu gehen:

eine Benutzersteuerung erstellen:

<UserControl x:Class="ArrowsAndDaggersLibrary.ArrowsAndDaggersUC" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Canvas x:Name="LayoutRoot"> 
     <Line x:Name="Cap" /> 
     <Line x:Name="Connector" /> 
     <Line x:Name="Foot" /> 
    </Canvas> 
</UserControl> 

mit folgender Code:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Net; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Shapes; 

namespace ArrowsAndDaggersLibrary 
{ 
    public partial class ArrowsAndDaggersUC : UserControl 
    { 
     private Point startPoint; 
     public Point StartPoint 
     { 
      get { return startPoint; } 
      set 
      { 
       startPoint = value; 
       Update(); 
      } 
     } 

     private Point endPoint; 
     public Point EndPoint 
     { 
      get { return endPoint; } 
      set { 
       endPoint = value; 
       Update(); 
      } 
     } 

     public ArrowsAndDaggersUC() 
     { 
      InitializeComponent(); 
     } 

     public ArrowsAndDaggersUC(Point StartPoint, Point EndPoint) 
     { 
      InitializeComponent(); 
      startPoint = StartPoint; 
      endPoint = EndPoint; 
      Update(); 
     } 

     private void Update() 
     { 
      //reconfig 
      Connector.X1 = startPoint.X; 
      Connector.Y1 = startPoint.Y; 
      Connector.X2 = endPoint.X; 
      Connector.Y2 = endPoint.Y; 
      Connector.StrokeThickness = 1; 
      Connector.Stroke = new SolidColorBrush(Colors.Black); 

      Cap.X1 = startPoint.X; 
      Cap.Y1 = startPoint.Y; 
      Cap.X2 = startPoint.X; 
      Cap.Y2 = startPoint.Y; 
      Cap.StrokeStartLineCap = PenLineCap.Triangle; 
      Cap.StrokeThickness = 20; 
      Cap.Stroke = new SolidColorBrush(Colors.Black); 

      Foot.X1 = endPoint.X; 
      Foot.Y1 = endPoint.Y; 
      Foot.X2 = endPoint.X; 
      Foot.Y2 = endPoint.Y; 
      Foot.StrokeEndLineCap = PenLineCap.Triangle; 
      Foot.StrokeThickness = 20; 
      Foot.Stroke = new SolidColorBrush(Colors.Black); 
     } 
    } 
} 

Nennen Sie es wie folgt aus:

LayoutRoot.Children.Add(new ArrowsAndDaggersUC(new Point(200, 200), new Point(300, 400))); 

und Sie werden 1px Schlaganfall Linien mit 20px Schlaganfall Dreiecke am Ende jeder Zeile haben.

--EDIT--

@ Number8 hatte eine Frage, wie die Benutzersteuerung so zu modifizieren, dass die Kappen in der gleichen Richtung wie die Linie zeigen würden.

Ändern Sie die XAML der Benutzersteuerung wie folgt:

<UserControl x:Class="ArrowsAndDaggersLibrary.ArrowsAndDaggersUC" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Canvas x:Name="LayoutRoot"> 
     <Line x:Name="Cap"> 
      <Line.RenderTransform> 
       <RotateTransform x:Name="CapRotateTransform" /> 
      </Line.RenderTransform> 
     </Line> 
     <Line x:Name="Connector" /> 
     <Line x:Name="Foot"> 
      <Line.RenderTransform> 
       <RotateTransform x:Name="FootRotateTransform" /> 
      </Line.RenderTransform> 
     </Line> 
    </Canvas> 
</UserControl> 

Dann das „Update“ Methode ändern Sie den Winkel der Linie zu bekommen und drehen Sie die Kappen zu diesem Winkel:

private void Update() 
{ 

    double angleOfLine = Math.Atan2((endPoint.Y - startPoint.Y), (endPoint.X - startPoint.X)) * 180/Math.PI; 

    Connector.X1 = startPoint.X; 
    Connector.Y1 = startPoint.Y; 
    Connector.X2 = endPoint.X; 
    Connector.Y2 = endPoint.Y; 
    Connector.StrokeThickness = 1; 
    Connector.Stroke = new SolidColorBrush(Colors.Black); 

    Cap.X1 = startPoint.X; 
    Cap.Y1 = startPoint.Y; 
    Cap.X2 = startPoint.X; 
    Cap.Y2 = startPoint.Y; 
    Cap.StrokeStartLineCap = PenLineCap.Triangle; 
    Cap.StrokeThickness = 20; 
    Cap.Stroke = new SolidColorBrush(Colors.Black); 

    CapRotateTransform.Angle = angleOfLine; 
    CapRotateTransform.CenterX = startPoint.X; 
    CapRotateTransform.CenterY = startPoint.Y; 

    Foot.X1 = endPoint.X; 
    Foot.Y1 = endPoint.Y; 
    Foot.X2 = endPoint.X; 
    Foot.Y2 = endPoint.Y; 
    Foot.StrokeEndLineCap = PenLineCap.Triangle; 
    Foot.StrokeThickness = 20; 
    Foot.Stroke = new SolidColorBrush(Colors.Black); 

    FootRotateTransform.Angle = angleOfLine; 
    FootRotateTransform.CenterX = endPoint.X; 
    FootRotateTransform.CenterY = endPoint.Y; 
} 
+0

Das ist ein interessanter Code, aber in Silverlight kann ich nicht von Line (oder Form für diese Angelegenheit) erben wie Petzold in WPF.Die Linie ist versiegelt und Shape zeichnet keine Zeichnung. Ich denke, dass die Laufzeit für das Zeichnen verantwortlich ist, da jede der Shape-Klassen eine andere "bekannte Kennung" hat. –

+0

Das zweite Beispiel funktionierte. Vielen Dank. –

+0

Gute Arbeit. Es sieht so aus, als ob die Pfeile von Osten nach Westen zeigen, auch wenn die Linie jetzt verläuft. Was würde es brauchen, damit die Pfeilspitzen in die gleiche Richtung zeigen, in der die Linie läuft? – Number8

5

Diese einfache Methode erstellt auch einen Pfeil und es hat für mich funktioniert.

private static Shape DrawArrow(Point p1, Point p2) 
    { 
     GeometryGroup lineGroup = new GeometryGroup(); 

     double theta = Math.Atan2((p2.Y - p1.Y),(p2.X - p1.X)) * 180/Math.PI; 

     PathGeometry pathGeometry = new PathGeometry(); 
     PathFigure pathFigure = new PathFigure(); 
     pathFigure.StartPoint = p1; 

     Point lpoint = new Point(p1.X + 2, p1.Y + 10); 
     Point rpoint = new Point(p1.X - 2, p1.Y + 10); 
     LineSegment seg1 = new LineSegment(); 
     seg1.Point = lpoint; 
     pathFigure.Segments.Add(seg1); 

     LineSegment seg2 = new LineSegment(); 
     seg2.Point = rpoint; 
     pathFigure.Segments.Add(seg2); 

     LineSegment seg3 = new LineSegment(); 
     seg3.Point = p1; 
     pathFigure.Segments.Add(seg3); 

     pathGeometry.Figures.Add(pathFigure); 
     RotateTransform transform = new RotateTransform(); 
     transform.Angle = theta - 90; 
     transform.CenterX = p1.X; 
     transform.CenterY = p1.Y; 
     pathGeometry.Transform = transform; 
     lineGroup.Children.Add(pathGeometry); 

     LineGeometry connectorGeometry = new LineGeometry(); 
     connectorGeometry.StartPoint = p1; 
     connectorGeometry.EndPoint = p2; 
     lineGroup.Children.Add(connectorGeometry); 
     Path path = new Path(); 
     path.Data = lineGroup; 
     return path; 
    } 
0

All Runtime und Animation Linie

//animation 
public class Cls_Barriere 
    {      
     // animazione periferica 
     public static void LineAnimation(Line _line,String _colore) 
     { 

      Storyboard result = new Storyboard(); 
      Duration duration = new Duration(TimeSpan.FromSeconds(2)); 

      ColorAnimation animation = new ColorAnimation(); 
      animation.RepeatBehavior = RepeatBehavior.Forever; 
      animation.Duration = duration; 
      switch (_colore.ToUpper()) 
      { 
       case "RED": 
        animation.From = Colors.Red; 
        break; 
       case "ORANGE": 
        animation.From = Colors.Orange; 
        break; 
       case "YELLOW": 
        animation.From = Colors.Yellow; 
        break; 
       case "GRAY": 
        animation.From = Colors.DarkGray; 
        break; 
       default: 
        animation.From = Colors.Green; 
        break; 
      } 

      animation.To = Colors.Gray; 
      Storyboard.SetTarget(animation, _line); 
      Storyboard.SetTargetProperty(animation, new PropertyPath("(Line.Stroke).(SolidColorBrush.Color)")); 
      result.Children.Add(animation); 
      result.Begin(); 

     } 
    } 



public partial class MainPage : UserControl 
    { 
     private Point startPoint; 
     private Point endPoint; 

     // canvas event onmouse click to start drawing runtime a line 
     public MainPage() 
     { 
      InitializeComponent(); 
      Canvas.MouseLeftButtonDown += Canvas_MouseLeftButtonDown; 
      Canvas.MouseLeftButtonUp += Canvas_MouseLeftButtonUp; 

     } 

     // on muose up drawing line and add canvas all references 
     void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) 
     { 
      endPoint = new Point(); 
      endPoint.X = e.GetPosition(this.Canvas).X; 
      endPoint.Y = e.GetPosition(this.Canvas).Y; 
      Line LineCap = new Line(); 
      Line LineFoot = new Line(); 
      Line LineConnect = new Line(); 
      RotateTransform FootRotateTransform = new RotateTransform(); 
      RotateTransform CapRotateTransform = new RotateTransform(); 


      LineConnect.Stroke = new SolidColorBrush(Colors.White); 
      LineConnect.StrokeThickness = 5; 
      LineConnect.StrokeStartLineCap = PenLineCap.Round; 
      LineConnect.StrokeEndLineCap = PenLineCap.Round; 
      LineConnect.X1 = startPoint.X; 
      LineConnect.Y1 = startPoint.Y; 
      LineConnect.X2 = endPoint.X; 
      LineConnect.Y2 = endPoint.Y; 

      LineCap.X1 = startPoint.X; 
      LineCap.X2 = startPoint.X; 
      LineCap.Y1 = startPoint.Y; 
      LineCap.Y2 = startPoint.Y; 
      LineCap.StrokeThickness = 20; 
      LineCap.StrokeStartLineCap = PenLineCap.Round; 
      LineCap.Stroke = new SolidColorBrush(Colors.White); 
      LineFoot.StrokeThickness = 20; 

      LineFoot.X1 = endPoint.X; 
      LineFoot.X2 = endPoint.X; 
      LineFoot.Y1 = endPoint.Y; 
      LineFoot.Y2 = endPoint.Y; 
      LineFoot.StrokeEndLineCap = PenLineCap.Triangle; 
      LineFoot.Stroke = new SolidColorBrush(Colors.White); 
      Double angleOfLine = new Double(); 
      angleOfLine = Math.Atan2((LineConnect.Y2 - LineConnect.Y1), (LineConnect.X2 - LineConnect.X1)) * 180/Math.PI; 
      FootRotateTransform.Angle = angleOfLine; 
      FootRotateTransform.CenterX = endPoint.X; 
      FootRotateTransform.CenterY = endPoint.Y; 

      CapRotateTransform.Angle = angleOfLine; 
      CapRotateTransform.CenterX = startPoint.X; 
      CapRotateTransform.CenterY = startPoint.Y; 
      LineFoot.RenderTransform = FootRotateTransform; 
      LineCap.RenderTransform = CapRotateTransform; 

      LineConnect.Loaded += _line_Loaded; 
      LineCap.Loaded += _line_Loaded; 
      LineFoot.Loaded += _line_Loaded; 
      Canvas.Children.Add(LineConnect); 
      Canvas.Children.Add(LineCap); 
      Canvas.Children.Add(LineFoot); 
     } 
     //load animation color 
     void _line_Loaded(object sender, RoutedEventArgs e) 
     { 
      Cls_Barriere.LineAnimation(sender as Line, "RED"); 
     } 
     // add canvas lines 
     void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
     { 
      startPoint = new Point(); 
      startPoint.X = e.GetPosition(this.Canvas).X; 
      startPoint.Y = e.GetPosition(this.Canvas).Y; 
     } 



    }