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

时间:2013-12-10 10:26:30

标签: c# .net wpf canvas

我的软件创建了相当复杂的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:

  

“之前必须断开指定的子视图与当前父视图的连接   附加到新的父视觉。“

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

3 个答案:

答案 0 :(得分: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的数据 - 您可以将该类序列化,以便您可以保留该数据,因为它是您自己的上课: - )

答案 1 :(得分:0)

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

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

答案 2 :(得分: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);