我的软件创建了相当复杂的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>
答案 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);