WPF как нарисовать стрелку между двумя компонентами - PullRequest
0 голосов
/ 26 мая 2020

Я создал собственное дерево для своей программы (не могу использовать древовидное представление по разным причинам), но не совсем ясно, какой компонент является родительским для какого ребенка. Я хотел бы добавить стрелку, которую можно было бы назвать так:

var arrow = CreateArrowBetween(c1,c2)

Но я не знаю, как, может ли кто-нибудь помочь мне или дать мне подсказку? Ps: пока элемент находится на сетке

1 Ответ

0 голосов
/ 26 мая 2020

В следующем примере показано, как нарисовать центрированную стрелку между двумя элементами FrameworkElement, размещенными в контейнере, например, Grid.

Это очень базовый c и его необходимо улучшить, чтобы обнаруживать если элементы уложены друг на друга или рядом. Прямо сейчас алгоритм предполагает, что элементы расположены в стопке, и позиционирует стрелку горизонтально по центру на нижнем / верхнем краях элементов.
Если элементы расположены рядом друг с другом, вы можете захотеть соединить левый / правый края. MainWindow.xaml

<Window>
  <Grid x:Name="Container">
    <TextBox x:Name="TextBox" Text="Some text" Height="20" />
    <TextBlock x:Name="TextBlock" Margin="0,100,0,0" Text="More text" />
  </Grid>
</Window>

MainWindow.xaml.cs

partial class MainWindow : Window
{
  public MainWindow()
  {
    InitializeComponent();
    this.Loaded += OnLoaded;
  }

  private void OnLoaded(object sender, RoutedEventArgs e)
  {
    CreateArrowBetween(this.TextBlock, this.TextBox, this.Container);
  }

  // The arrow will point from start to end
  private void CreateArrowBetween(FrameworkElement startElement, FrameworkElement endElemend, Panel parentContainer)
  {
    SolidColorBrush arrowBrush = Brushes.Red;

    // Center the line horizontally and vertically.
    // Get the positions of the controls that should be connected by a line.
    Point centeredArrowStartPosition = startElement.TransformToAncestor(parentContainer)
      .Transform(new Point(startElement.ActualWidth / 2, startElement.ActualHeight / 2));

    Point centeredArrowEndPosition = endElemend.TransformToAncestor(parentContainer)
      .Transform(new Point(endElemend.ActualWidth / 2, endElemend.ActualHeight / 2));

    // Draw the line between two controls
    var arrowLine = new Line()
    {
      Stroke = Brushes.Red,
      StrokeThickness = 2,
      X1 = centeredArrowStartPosition.X,
      Y2 = centeredArrowEndPosition.Y,
      X2 = centeredArrowEndPosition.X,
      Y1 = centeredArrowStartPosition.Y
    };
    parentContainer.Children.Add(
      arrowLine);

    // Create the arrow tip of the line. The arrow has a width of 8px and a height of 8px,
    // where the position of arrow tip and the line's end are the same
    var arrowLineTip = new Polygon() {Fill = Brushes.Red};
    var leftRectanglePoint = new Point(centeredArrowEndPosition.X - 4, centeredArrowEndPosition.Y + 8);
    var rightRectanglePoint = new Point(
      centeredArrowEndPosition.X + 4,
      centeredArrowEndPosition.Y + 8);
    var rectangleTipPoint = new Point(centeredArrowEndPosition.X, centeredArrowEndPosition.Y);
    var myPointCollection = new PointCollection
    {
      leftRectanglePoint, 
      rightRectanglePoint, 
      rectangleTipPoint
    };
    arrowLineTip.Points = myPointCollection;
    parentContainer.Children.Add(
      arrowLineTip);
  }
}
...