2009-10-13 43 views
5

Tôi cần vẽ mũi tên giữa các điều khiển trong canvas. Hiện tại tôi đang sử dụng đối tượng Line nhưng nó không có cách nào để vẽ một hình tam giác ở cuối dòng.Cách vẽ mũi tên trong Silverlight

Đây là khoảng những gì tôi cần:

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

Tôi đã cố gắng để phân lớp Line và thêm một vài dòng ở cuối nhưng lớp được niêm phong.

Bạn sẽ tạo điều khiển tùy chỉnh để vẽ mũi tên giữa X1, Y1 và X2, Y2 bằng cách nào?

Cảm ơn

Trả lời

7

Charles Petzold đã viết một thư viện để làm điều này trong WPF. Logic, ít nhất, nên được chuyển giao cho Silverlight. Nó sử dụng Polylines và Paths và nên dễ dàng để port.

Lines with Arrows @ Petzold Book Blog

--EDIT--

Ok - đây là một cách khác để đi về nó:

Tạo một điều khiển người dùng:

<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> 

như sau mã:

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); 
     } 
    } 
} 

Gọi nó như thế này:

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

và bạn sẽ có dòng đột quỵ 1px với tam giác đột quỵ 20px ở đầu của mỗi dòng.

--EDIT--

@ Number8 có một câu hỏi về cách sửa đổi các điều khiển người dùng để các mũ sẽ chỉ theo hướng tương tự như các dòng.

Sửa đổi XAML của điều khiển người dùng như vậy:

<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> 

Sau đó, thay đổi "Cập nhật" phương pháp để có được những góc của đường và xoay nắp để góc rằng:

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

Đó là một số mã thú vị nhưng trong Silverlight tôi không thể kế thừa từ Line (hoặc hình dạng cho vấn đề đó) như Petzold đã làm trong WPF.Dòng được niêm phong và hình dạng không làm bất kỳ bản vẽ nào. Tôi nghĩ rằng thời gian chạy chịu trách nhiệm vẽ bởi vì mỗi lớp Shape có một "định danh được biết đến" khác nhau. –

+0

Ví dụ thứ hai hoạt động. Cảm ơn. –

+0

Công việc hay. Có vẻ như các mũi tên chỉ hướng đông-tây, ngay cả khi dòng chạy nw-se. Nó sẽ làm gì để làm cho các đầu mũi tên hướng cùng một hướng đường đang chạy? – Number8

5

Phương pháp đơn giản này cũng tạo ra một mũi tên và nó làm việc cho tôi.

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

Tất cả điều này Runtime và hình ảnh động Dòng

//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; 
     } 



    } 
Các vấn đề liên quan