我的软件创建了相当复杂的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 回答
让我们首先看看你的错误,以便更好地理解代码的作用:
这不符合您的要求,因为您只需替换参考 .
MyCanvas
是实例中的一个变量,它首先指向Canvas
实例(表单中显示的空实例) . 当您执行上述语句时,MyCanvas
变量被修改为引用另一个Canvas
实例 - 一个Canvas
实例,该实例可能包含一些图形元素,但不会添加到您的窗口中 . 您的窗口继续只包含原始的空Canvas
实例 .System.ArgumentException
完全是因为它所说的 . 您不能一次向几个父项添加可视元素 .更干净的解决方案不是复制完整的
Canvas
,而是要有一个方法(或带有方法的对象),该方法将Canvas
作为参数,然后创建并将您的petrinet所包含的所有元素添加到Canvas
. 以这种非常简化的形式:然后,您可以根据需要为多个
Canvas
实例调用此方法 .请注意,您也可以使用
Petrinet
类来存储描述您的petrinets的数据 - 您可以将该类序列化,以便您可以保留该数据,因为它是您自己的类:-)你无法做你想做的事 . 正如您的
Exception
告诉您的那样,在WPF中,每个UI元素只能在可视化树中托管一次 . 基本上,这意味着如果UI元素正在UI中显示,那么您无法将相同的UI元素添加到UI中的另一个容器中 . 您可以从当前位置删除UI元素,然后将其添加到UI中的其他容器,但这不是您想要的 .为了清楚起见,我说的是UI元素,而不是数据元素 . 一个数据元素可以在UI中多次表示,虽然它的渲染形式可能看起来完全相同,但它们实际上都是不同的UI元素 .
在Windows Presentation Foundation(WPF)中,元素只能有一个可视父对象,并且只能有一个逻辑父对象 . 这实际上非常重要,因为它可以确保视觉和逻辑树格式良好 .
But that does not show anything at all. I can, however replace the last line with
这是正常的你正在创建一个新对象,你应该将它添加到你的逻辑树,以便让wpf做所有必需的计算,例如你可以做这样的事情I looked into cloning the canvas-object, but the canvas-object is not serializable
你不能像你一样序列化你的控件,你可以使用这样的东西