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