Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么我不能将画布对象指定给现有画布?_C#_.net_Wpf_Canvas - Fatal编程技术网

C# 为什么我不能将画布对象指定给现有画布?

C# 为什么我不能将画布对象指定给现有画布?,c#,.net,wpf,canvas,C#,.net,Wpf,Canvas,我的软件创建了相当复杂的Petrinet,将在画布上绘制。由于这是多次显示预览窗口,一个更大的视图,…我想缓存绘制的画布。 我的第一次尝试是 XAML: 但这并没有显示出任何东西。但是,我可以将最后一行替换为 MyCanvas.Children.Add(NewCanvas); 现在我可以看到我的画布,但是如果我尝试打开另一个显示相同画布的窗口 Window NewWindow = new Window(); NewWindow.Content = NewCanvas; NewWindow.Sh

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

XAML:

但这并没有显示出任何东西。但是,我可以将最后一行替换为

MyCanvas.Children.Add(NewCanvas);
现在我可以看到我的画布,但是如果我尝试打开另一个显示相同画布的窗口

Window NewWindow = new Window();
NewWindow.Content = NewCanvas;
NewWindow.Show();
我得到一个System.ArgumentException:

“必须先断开指定子项与当前父项的连接,然后才能进行可视化。” “正在附加到新的父级视觉。”


我研究过克隆画布对象,但画布对象不可序列化,XamlWriter在自定义编写的UIElements类中需要一个特殊的构造函数,但我不知道它到底需要什么。

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

MyCanvas = NewCanvas;
这并不能满足您的需要,因为您只需替换引用。MyCanvas是实例中的一个变量,它首先指向画布实例,即表单中显示的空实例。当您执行上述语句时,MyCanvas变量将被修改为引用另一个Canvas实例—一个可能包含一些图形元素的Canvas实例,但它不会添加到您的窗口中。您的窗口继续只包含原始的空画布实例

System.ArgumentException的发生正是因为它所说的内容。不能同时向多个父级添加视觉元素

更干净的解决方案不是复制完整的画布,而是使用一个方法或对象,该方法将画布作为参数,然后创建petrinet包含的所有元素并将其添加到画布中。以这样一种非常简单的形式:

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);
    }
}
然后,您可以对任意多个画布实例调用此方法


请注意,您还可以使用该Petrinet类来存储描述您的Petrinet的数据,并且您可以使该类可序列化,以便可以持久化该数据,因为它是您自己的类:-

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

我要说的是UI元素,而不是数据元素。一个数据元素可以在UI中多次表示,尽管它的呈现形式可能看起来完全相同,但实际上它们都是不同的UI元素

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

在Windows演示基金会WPF中,一个元素可以有一个以上的可视化父级和不多于一个逻辑父级。这实际上非常重要,因为它确保视觉和逻辑树的格式良好

但这并没有显示出任何东西。但是,我可以将最后一行替换为 通常情况下,您正在创建一个新对象,您应该将其添加到逻辑树中,以便让wpf执行所有必需的计算 例如,你可以做这样的事情

        this.yourGrid.Children.Add(NewCanvas);
我研究过克隆画布对象,但是画布对象是不可序列化的

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

        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);  
        this.yourGrid.Children.Add(NewCanvas);
        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);