为什么WPF的Canvas操作时会抛出System.InvalidOperationException异常
异常原因与解决方案
核心触发原因
WPF 框架要求所有 UI 元素(你代码中的 Polyline 属于 UI 元素子类)同一时间只能关联一个父级逻辑容器。你遇到的报错就是因为同一个 Polyline 实例被重复添加到不同的 Canvas 容器,或是添加时还没有和上一个父容器断开绑定关系。
原有项目可以正常运行,大概率是原有逻辑中每次打开 dlgDisplayTwoXYPlots 对话框时都会创建新的 Polyline 实例,或是对话框全局仅实例化一次、不会重复打开;新建项目中你应该是将 poXYTop、poXYBottom 定义为了全局复用的实例,重复打开对话框时复用了已经绑定过父容器的 Polyline 对象,因此触发异常。
修复方案
你可以根据自己的业务逻辑选择任意一种方案修复:
方案1:每次打开对话框前新建 Polyline 实例(最推荐,逻辑最简单)
不要复用全局的 Polyline 实例,每次调用对话框前重新创建新的对象即可:
// 每次触发打开对话框的逻辑时,都重新new Polyline,不要复用外部全局实例 Polyline poXYTop = new Polyline { Stroke = Brushes.Blue }; Polyline poXYBottom = new Polyline { Stroke = Brushes.Blue }; var plotDialog = new dlgDisplayTwoXYPlots(listdParamsTop, listPointsTop, poXYTop, listdParamsBottom, listPointsBottom, poXYBottom); plotDialog.ShowDialog();
方案2:添加到容器前先断开原有父级绑定
如果必须复用 Polyline 实例,可在 Plot 方法中添加判断,先把 Polyline 从原有父容器中移除再添加到新容器:
private void Plot(Canvas canvas, Polyline poXY, List<double> listdParams, List<Point> listPoints) { // 新增以下代码:如果Polyline已经绑定过父容器,先从原有父容器移除 if (poXY.Parent is Panel oldParent) { oldParent.Children.Remove(poXY); } // 原有逻辑保持不变 int iii = 0; int iNumOfPoints = (int)listdParams[iii++]; double dXmin = listdParams[iii++]; double dXmax = listdParams[iii++]; double dYmin = listdParams[iii++]; double dYmax = listdParams[iii++]; double dPlotWidth = dXmax - dXmin; double dPlotHeight = dYmax - dYmin; for (int ii = 0; ii < iNumOfPoints; ii++) { var pointResult = new Point { X = (listPoints[ii].X - dXmin) * canvas.Width / dPlotWidth, Y = canvas.Height - (listPoints[ii].Y - dYmin) * canvas.Height / dPlotHeight }; poXY.Points.Add(pointResult); } canvas.Children.Add(poXY); }
方案3:将UI元素创建逻辑放到对话框内部
完全避免外部传递UI元素的风险,对话框内部自己创建Polyline实例,外部仅传递绘制需要的参数和点数据即可,符合WPF数据和UI分离的设计规范。
内容的提问来源于stack exchange,提问作者ttom
相关产品推荐
相关产品推荐

