【问题标题】:make line that connects two objects in silverlight在silverlight中制作连接两个对象的线
【发布时间】:2013-06-11 15:12:30
【问题描述】:

如何连接这些实体框?

框是通过单击按钮创建的,并且可以拖动。现在我想用线什么的把它们连接起来。

【问题讨论】:

    标签: c# silverlight line connect


    【解决方案1】:

    这是一个快速而肮脏的实现:

    代表连接的类:

    public partial class Connection
    {
        public MyBox Box1 { get; set; }
        public MyBox Box2 { get; set; }
        public Line Line { get; set; }
    }
    

    为了创建一个新连接,我使用了一个基本形式:源名称、目标名称和一个按钮:

    <StackPanel Orientation="Horizontal" Grid.Row="3">
        <TextBox Width="100" Text="{Binding From,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
        <TextBlock Text=" ----> " />
        <TextBox Width="100" Text="{Binding To,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" />
        <Button Content="Connect" Click="Button_Click_2" />
    </StackPanel>
    

    这里是处理程序:

    public string From { get; set; }
    public string To { get; set; }
    
    private IList<Connection> connections = new List<Connection>();
    private void Button_Click_2(object sender, RoutedEventArgs e)
    {
        MyBox box1 = boxes.Single(b => b.Header == From);
        MyBox box2 = boxes.Single(b => b.Header == To);
    
        Connection conn = new Connection { Box1 = box1, Box2 = box2, Line = new Line { StrokeThickness = 1, Stroke = Brushes.Black } };
        connections.Add(conn);
    
        RefreshLinesPositions();
    
        panel.Children.Add(conn.Line);
    }
    

    还有 RefreshLinesPositions 代码:

    private void RefreshLinesPositions()
    {
        foreach (Connection conn in connections)
        {
            Point p1 = conn.Box1.TranslatePoint(new Point(0, 0), panel);
            Point p2 = conn.Box2.TranslatePoint(new Point(0, 0), panel);
    
            double t1 = p1.Y;
            double b1 = p1.Y + conn.Box1.ActualHeight;
            double l1 = p1.X;
            double r1 = p1.X + conn.Box1.ActualWidth;
    
            double t2 = p2.Y;
            double b2 = p2.Y + conn.Box2.ActualHeight;
            double l2 = p2.X;
            double r2 = p2.X + conn.Box2.ActualWidth;
    
            if (r1 < l2)
            {
                conn.Line.X1 = r1;
                conn.Line.Y1 = t1 + (b1 - t1) / 2;
                conn.Line.X2 = l2;
                conn.Line.Y2 = t2 + (b2 - t2) / 2;
    
                conn.Line.Visibility = Visibility.Visible;
            }
            else if (r2 < l1)
            {
                conn.Line.X1 = r2;
                conn.Line.Y1 = t2 + (b2 - t2) / 2;
                conn.Line.X2 = l1;
                conn.Line.Y2 = t1 + (b1 - t1) / 2;
    
                conn.Line.Visibility = Visibility.Visible;
            }
            else if (b1 < t2)
            {
                conn.Line.X1 = l1 + (r1 - l1) / 2;
                conn.Line.Y1 = b1;
                conn.Line.X2 = l2 + (r2 - l2) / 2;
                conn.Line.Y2 = t2;
    
                conn.Line.Visibility = Visibility.Visible;
            }
            else if (b2 < t1)
            {
                conn.Line.X1 = l1 + (r1 - l1) / 2;
                conn.Line.Y1 = t1;
                conn.Line.X2 = l2 + (r2 - l2) / 2;
                conn.Line.Y2 = b2;
    
                conn.Line.Visibility = Visibility.Visible;
            }
            else
            {
                conn.Line.Visibility = System.Windows.Visibility.Collapsed;
            }
        }
    

    每当一个盒子被移动时,你都会调用 RefreshLinesPositions:

    private void Box_MouseMove(object sender, MouseEventArgs e)
    {
        if (draggedBox != null)
        {
            ...
    
            RefreshLinesPositions();
        }
    }
    

    编辑:对于节点

    新的RefreshLinesPosition版本:

    private void RefreshLinesPositions()
    {
        foreach (Connection conn in connections)
        {
            Point p1 = conn.Box1.TranslatePoint(new Point(0, 0), panel);
            Point p2 = conn.Box2.TranslatePoint(new Point(0, 0), panel);
    
            double t1 = p1.Y;
            double b1 = p1.Y + conn.Box1.ActualHeight;
            double l1 = p1.X;
            double r1 = p1.X + conn.Box1.ActualWidth;
    
            double t2 = p2.Y;
            double b2 = p2.Y + conn.Box2.ActualHeight;
            double l2 = p2.X;
            double r2 = p2.X + conn.Box2.ActualWidth;
    
            if (r1 < l2)
            {
                conn.Line.X1 = r1;
                conn.Line.Y1 = t1 + (b1 - t1) / 2;
                conn.Line.X2 = l2;
                conn.Line.Y2 = t2 + (b2 - t2) / 2;
    
                conn.Line.Visibility = Visibility.Visible;
    
                conn.Node1.Text.RenderTransform = new TranslateTransform(r1, t1 + (b1 - t1) / 2);
                conn.Node2.Text.RenderTransform = new TranslateTransform(l2 - conn.Node2.Text.ActualWidth, t2 + (b2 - t2) / 2);
            }
            else if (r2 < l1)
            {
                conn.Line.X1 = l1;
                conn.Line.Y1 = t1 + (b1 - t1) / 2;
                conn.Line.X2 = r2;
                conn.Line.Y2 = t2 + (b2 - t2) / 2;
    
                conn.Line.Visibility = Visibility.Visible;
    
                conn.Node1.Text.RenderTransform = new TranslateTransform(l1 - conn.Node1.Text.ActualWidth, t1 + (b1 - t1) / 2);
                conn.Node2.Text.RenderTransform = new TranslateTransform(r2, t2 + (b2 - t2) / 2);
            }
            else if (b1 < t2)
            {
                conn.Line.X1 = l1 + (r1 - l1) / 2;
                conn.Line.Y1 = b1;
                conn.Line.X2 = l2 + (r2 - l2) / 2;
                conn.Line.Y2 = t2;
    
                conn.Line.Visibility = Visibility.Visible;
    
                conn.Node1.Text.RenderTransform = new TranslateTransform(l1 + (r1 - l1) / 2, b1);
                conn.Node2.Text.RenderTransform = new TranslateTransform(l2 + (r2 - l2) / 2, t2 - conn.Node2.Text.ActualHeight);
            }
            else if (b2 < t1)
            {
                conn.Line.X1 = l1 + (r1 - l1) / 2;
                conn.Line.Y1 = t1;
                conn.Line.X2 = l2 + (r2 - l2) / 2;
                conn.Line.Y2 = b2;
    
                conn.Line.Visibility = Visibility.Visible;
    
                conn.Node1.Text.RenderTransform = new TranslateTransform(l1 + (r1 - l1) / 2, t1 - conn.Node1.Text.ActualHeight);
                conn.Node2.Text.RenderTransform = new TranslateTransform(l2 + (r2 - l2) / 2, b2);
            }
            else
            {
                conn.Line.Visibility = System.Windows.Visibility.Collapsed;
            }
        }
    }
    

    新的事件处理程序:

    private void Button_Click_2(object sender, RoutedEventArgs e)
    {
        MyBox box1 = boxes.Single(b => b.Header == From);
        MyBox box2 = boxes.Single(b => b.Header == To);
    
        Connection conn = new Connection
        {
            Box1 = box1,
            Box2 = box2,
            Line = new Line { StrokeThickness = 1, Stroke = Brushes.Black },
            Node1 = new Node { Text = new TextBox() },
            Node2 = new Node { Text = new TextBox() }
        };
        connections.Add(conn);
    
        panel.Children.Add(conn.Line);
    
        panel.Children.Add(conn.Node1.Text);
        panel.Children.Add(conn.Node2.Text);
    
        RefreshLinesPositions();
    }
    

    我用它来表示节点:

    public partial class Node
    {
        public string Title { get; set; }
        public TextBox Text { get; set; }
    }
    

    【讨论】:

    • 我在“From”和“To”上遇到错误,它说它不存在
    • 我点击连接,但没有任何反应,可能是我做错了什么
    • 尝试调试,尤其是当您达到“conn.Line.Visibility = Visibility.Visible;”之一时
    • 当我点击连接时,它崩溃并出现此错误:“用户代码未处理 InvalidOperationException - 序列不包含匹配元素”
    • @LuisAmaro: 再次SL :( 试试new TranslateTransform{ X = r1, Y = t1 + (b1 - t1) / 2) }
    【解决方案2】:
    1. 你必须得到每个盒子的位置;
    2. 在方框之间画一个Path;
    3. 重绘框拖放...

    带有两个 Rectangle 的简单示例:

    XAML:

    <Canvas x:Name="Root">
        <Rectangle
            x:Name="rect1"
            Fill="Aqua"
            Width="20"
            Height="20"
            Canvas.Left="24"
            Canvas.Top="44" />
        <Rectangle
            x:Name="rect2"
            Fill="Red"
            Width="20"
            Height="20"
            Canvas.Left="119"
            Canvas.Top="73" />
    </Canvas>
    

    C#:

    ConnectBoxes(Root, rect1, rect2);
    ....
    
    public void ConnectBoxes(Canvas container, Rectangle boxeSrc, Rectangle boxeDest)
    {
        var transform1 = boxeSrc.TransformToVisual(container);
        var transform2 = boxeDest.TransformToVisual(container);
    
        var lineGeometry = new LineGeometry()
        {
            StartPoint = transform1.Transform(
                new Point(boxeSrc.ActualWidth / 2, boxeSrc.ActualHeight / 2.0)
            ),
            EndPoint = transform2.Transform(
                new Point(boxeDest.ActualWidth / 2.0, boxeDest.ActualHeight / 2.0)
            )
        };
        container.Children.Add(new Path()
        {
            Data = lineGeometry,
            Fill = new SolidColorBrush(Colors.Brown),
            Stroke = new SolidColorBrush(Colors.Brown),
    
        });
    }
    

    【讨论】:

    • 这个例子很好,但是没有预制对象我怎么能做到呢?我猜想画线的更好方法是单击一个按钮,该按钮允许从一个对象到另一个对象画一条线......链接上的这个例子是完美的,但它在 wpf 上,我不能把它放在我的项目:/denisvuyka.wordpress.com/2007/10/13/…
    • 你知道如何使路径在拖动时随矩形调整吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多