首页 文章

为什么我不能将canvas-object分配给现有画布?

提问于
浏览
1

我的软件创建了相当复杂的petrinets,将在画布上绘制 . 由于这是多次显示(预览窗口,更大的视图,...)我想缓存绘制的画布 . 我的第一次尝试是

XAML:

<Canvas Name="MyCanvas" />

代码背后:

public MainWindow()
{
    InitializeComponent();

    Canvas NewCanvas = new Canvas();
    TextBlock txt1 = new TextBlock();
    txt1.Text = "Hello World!";
    Canvas.SetTop(txt1, 10);
    Canvas.SetLeft(txt1, 10);
    NewCanvas.Children.Add(txt1);

    MyCanvas = NewCanvas;
}

但这根本没有显示任何东西 . 但我可以用最后一行代替

MyCanvas.Children.Add(NewCanvas);

现在我可以看到我的画布,但是如果我尝试打开另一个显示相同画布的窗口

Window NewWindow = new Window();
NewWindow.Content = NewCanvas;
NewWindow.Show();

我得到一个System.ArgumentException:

“在附加到新的父Visual之前,必须断开指定子项与当前父Visual . ”

我研究了克隆canvas-object,但是canvas-object不是可序列化的,而XamlWriter在自定义编写的UIElements类中需要一个特殊的构造函数,但我不知道它究竟需要什么 .

3 回答

  • 0

    让我们首先看看你的错误,以便更好地理解代码的作用:

    MyCanvas = NewCanvas;
    

    这不符合您的要求,因为您只需替换参考 . MyCanvas 是实例中的一个变量,它首先指向 Canvas 实例(表单中显示的空实例) . 当您执行上述语句时, MyCanvas 变量被修改为引用另一个 Canvas 实例 - 一个 Canvas 实例,该实例可能包含一些图形元素,但不会添加到您的窗口中 . 您的窗口继续只包含原始的空 Canvas 实例 .

    System.ArgumentException 完全是因为它所说的 . 您不能一次向几个父项添加可视元素 .


    更干净的解决方案不是复制完整的 Canvas ,而是要有一个方法(或带有方法的对象),该方法将 Canvas 作为参数,然后创建并将您的petrinet所包含的所有元素添加到 Canvas . 以这种非常简化的形式:

    public class Petrinet
    {
        public void OutputPetrinet(Canvas dest)
        {
            if (dest == null) {
                throw new ArgumentNullException("dest");
            }
    
            Ellipse e = new Ellipse() {
                Width = 50,
                Height = 60,
                Fill = Brushes.Blue
            };
            Canvas.SetLeft(e, 20);
            Canvas.SetTop(e, 30);
            dest.Children.Add(e);
        }
    }
    

    然后,您可以根据需要为多个 Canvas 实例调用此方法 .

    请注意,您也可以使用 Petrinet 类来存储描述您的petrinets的数据 - 您可以将该类序列化,以便您可以保留该数据,因为它是您自己的类:-)

  • 0

    你无法做你想做的事 . 正如您的 Exception 告诉您的那样,在WPF中,每个UI元素只能在可视化树中托管一次 . 基本上,这意味着如果UI元素正在UI中显示,那么您无法将相同的UI元素添加到UI中的另一个容器中 . 您可以从当前位置删除UI元素,然后将其添加到UI中的其他容器,但这不是您想要的 .

    为了清楚起见,我说的是UI元素,而不是数据元素 . 一个数据元素可以在UI中多次表示,虽然它的渲染形式可能看起来完全相同,但它们实际上都是不同的UI元素 .

  • 0
    *`I get an System.ArgumentException: “Must disconnect specified child from current parent Visual before attaching to new parent Visual.”`*
    

    在Windows Presentation Foundation(WPF)中,元素只能有一个可视父对象,并且只能有一个逻辑父对象 . 这实际上非常重要,因为它可以确保视觉和逻辑树格式良好 .

    But that does not show anything at all. I can, however replace the last line with 这是正常的你正在创建一个新对象,你应该将它添加到你的逻辑树,以便让wpf做所有必需的计算,例如你可以做这样的事情

    this.yourGrid.Children.Add(NewCanvas);
    

    I looked into cloning the canvas-object, but the canvas-object is not serializable

    你不能像你一样序列化你的控件,你可以使用这样的东西

    string saved = XamlWriter.Save(canvas1); 
            StringReader sReader = new StringReader(saved); 
            XmlReader xReader = XmlReader.Create(sReader); 
            Canvas newCanvas = (Canvas)XamlReader.Load(xReader); 
            yourGrid.Children.Add(newCanvas);
    

相关问题