【问题标题】:WPF: Connecting rectangles on canvas dynamically with path betweenWPF:动态连接画布上的矩形与路径之间
【发布时间】:2015-09-03 03:01:25
【问题描述】:

这是我第一次发帖,请放心...

肯定有一些帖子展示了如何将线连接到块,但这个有点不同。网格动态放置在画布上。我想要一条线将按下按钮的网格连接到放置在画布上的新网格。但是下面的代码不起作用。我已经为此苦苦挣扎了很长时间。
只是偶然我发现按钮事件处理程序中抛出的消息框将允许它工作。我认为这是来自在不同时间运行的线程,但是在弄乱了 task.delay/thread.sleep/async/await 之后我找不到解决方案。
我正在使用自定义类,因为这是大型程序的精简版本,我希望在我的示例中具有类似的功能以反映可能的错误,但省略不必要的部分。 我将其用作最后的手段,在此先感谢您提供的任何帮助。首先是CS代码

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Grid1 g = myCanvas.CreateGrid();
            ContentControl1 cc = myCanvas.CreateCC();
            Button1 b = myCanvas.CreateButton1();

            Grid1.SetColumn(cc, 0);
            Grid1.SetRow(cc, 0);
            Grid1.SetColumn(b, 1);
            Grid1.SetRow(b, 1);
            g.Children.Add(cc);
            g.Children.Add(b);

            Canvas1.SetLeft(g, 500);
            Canvas1.SetTop(g, 5);
            myCanvas.Children.Add(g);
        }

    }

    public class Button1 : Button
    {

        protected override void OnClick()
        {

            Grid1 old_g = (Grid1)VisualTreeHelper.GetParent(this as DependencyObject);
            Canvas1 cnv = (Canvas1)VisualTreeHelper.GetParent(old_g as DependencyObject);
            Grid1 g = cnv.CreateGrid();
            ContentControl1 cc = cnv.CreateCC();
            Button1 b = cnv.CreateButton1();

            Grid1.SetColumn(cc, 0);
            Grid1.SetRow(cc, 0);
            Grid1.SetColumn(b, 1);
            Grid1.SetRow(b, 1);
            g.Children.Add(cc);
            g.Children.Add(b);

            Canvas1.SetLeft(g, 500);
            Canvas1.SetTop(g, cnv.Children.Count * 120);
            cnv.Children.Add(g);

            cnv.ConnectGrids(old_g, g);
        }


    }

    public class Canvas1 : Canvas
    {
        public Grid1 CreateGrid()
        {
            Grid1 g = new Grid1() { Width = 100, Height = 20, Background = Brushes.White };
            g.HorizontalAlignment = HorizontalAlignment.Center;
            g.VerticalAlignment = VerticalAlignment.Center;
            g.ShowGridLines = false;

            ColumnDefinition colDef1 = new ColumnDefinition();
            ColumnDefinition colDef2 = new ColumnDefinition() { Width = new GridLength(20) };
            g.ColumnDefinitions.Add(colDef1);
            g.ColumnDefinitions.Add(colDef2);

            RowDefinition rowDef1 = new RowDefinition();
            g.RowDefinitions.Add(rowDef1);
            return g;
        }

        public ContentControl1 CreateCC()
        {
            ContentControl1 cc = new ContentControl1()
            {
                VerticalContentAlignment = VerticalAlignment.Stretch,
                HorizontalContentAlignment = HorizontalAlignment.Stretch,
                BorderBrush = Brushes.BlueViolet,
            };
            return cc;
        }

        public Button1 CreateButton1()
        {
            Button1 b = new Button1()
            {
                VerticalContentAlignment = VerticalAlignment.Stretch,
                HorizontalContentAlignment = HorizontalAlignment.Stretch,
                BorderBrush = Brushes.Red
            };
            return b;
        }

        public void ConnectGrids(Grid1 g1, Grid1 g2)
        {
            Canvas1 cnv = (Canvas1)VisualTreeHelper.GetParent(g1 as DependencyObject);
            Transform transform1 = (Transform)g1.TransformToVisual(cnv as Visual);
            Transform transform2 = (Transform)g2.TransformToVisual(cnv as Visual);

            Point StartPoint1 = transform1.Transform(new Point(g1.Width, g1.Height / 2.0));
            Point EndPoint1 = transform2.Transform(new Point(g2.Width, g2.Height / 2.0));


            var lineGeometry = new LineGeometry()
            {
                StartPoint = StartPoint1,
                EndPoint = EndPoint1
            };

            var path = new Path()
            {
                Data = lineGeometry,
                Stroke = new SolidColorBrush(Colors.Black),
            };

            cnv.Children.Add(path);

        }

    }

    public class ContentControl1 : ContentControl
    {

    }

    public class Grid1 : Grid
    {

    }


}

然后是 xaml:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local ="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="1000" Width="1000">
    <DockPanel>
        <Button DockPanel.Dock="Top" Width="100" Height="20" Content="Start" Click="Button_Click"/>
        <ScrollViewer HorizontalScrollBarVisibility="Visible" Width="901" x:Name="_scrollViewer" Margin="0,5,0,25">
            <local:Canvas1 Background="Gray" Height="1000" Width="1000" x:Name="myCanvas"/>
        </ScrollViewer>
    </DockPanel>
</Window>

如何才能成功地将网格与路径连接起来?

【问题讨论】:

  • 删除所有内容并使用正确的 XAML 和数据绑定。
  • 如果你的意思是……让对象的创建成为静态的,那就违背了这个项目的目的。如果有一种方法可以通过 xaml 动态创建对象,我很乐意学习。但是每次点击一个按钮,我都想在画布上创建更多对象。
  • 不,我并不是要以任何方式使对象的“创建”成为“静态”。我的意思是使用正确的 XAML 和 DataBinding。请参阅我的示例,了解如何正确执行此操作here

标签: c# wpf multithreading canvas


【解决方案1】:

我喜欢我解决了这个问题/讨厌我必须回答我自己的愚蠢问题......

太简单了。更新布局()。对象在渲染之前不会更改位置,因此该线将转到其旧位置。

【讨论】:

  • UpdateLayout() 是个糟糕的主意。 -1.
猜你喜欢
  • 2012-10-28
  • 2016-12-03
  • 1970-01-01
  • 1970-01-01
  • 2013-01-24
  • 2015-03-16
  • 2013-01-16
  • 2016-11-27
  • 1970-01-01
相关资源
最近更新 更多