WPF中添加椭圆控件抛出指定视觉元素已存在异常如何解决?
解决WPF中重复添加同一Ellipse实例到Grid引发的异常问题
我有一个空白多米诺骨牌,尝试通过以下Arrange方法为Grid控件填充圆点,但执行grid.Children.Add(e)时抛出**"Specified visual is already a child of another visual or root of a CompositionTarget"**异常,已知原因是同一个Ellipse实例被重复添加到Grid中,求解决方案。
原Arrange方法代码
private void Arrange(Grid grid, byte dots) { Ellipse e = new Ellipse { Fill = new SolidColorBrush(Colors.Black) }; Border b = new Border { Background = new SolidColorBrush(Colors.Black), Margin = new Thickness(0, 5, 0, 5), CornerRadius = new CornerRadius(2.5) }; //BoneView.Layout.Children.Add(b); Grid.SetColumn(b, 1); if (dots == 0) return; if (dots == 1) { grid.Children.Add(e); Grid.SetColumn(e, 1); Grid.SetRow(e, 1); return; } if (dots == 2) { List<Ellipse> ellipses = new List<Ellipse>(); for (int i = 0; i < dots; i++) { ellipses.Add(e); grid.Children.Add(ellipses[i]); } Grid.SetColumn(ellipses[1], 2); Grid.SetRow(ellipses[1], 2); return; } if (dots == 3) { List<Ellipse> ellipses = new List<Ellipse>(); for (int i = 0; i < dots; i++) { ellipses.Add(e); grid.Children.Add(ellipses[i]); } Grid.SetColumn(ellipses[1], 2); Grid.SetRow(ellipses[1], 2); Grid.SetColumn(ellipses[2], 1); Grid.SetRow(ellipses[2], 1); return; } if (dots == 4) { List<Ellipse> ellipses = new List<Ellipse>(); for (int i = 0; i < dots; i++) { ellipses.Add(e); grid.Children.Add(ellipses[i]); } Grid.SetColumn(ellipses[1], 2); Grid.SetRow(ellipses[1], 2); Grid.SetColumn(ellipses[2], 2); Grid.SetRow(ellipses[2], 0); Grid.SetColumn(ellipses[3], 0); Grid.SetRow(ellipses[3], 2); return; } if (dots == 5) { List<Ellipse> ellipses = new List<Ellipse>(); for (int i = 0; i < dots; i++) { ellipses.Add(e); grid.Children.Add(ellipses[i]); } Grid.SetColumn(ellipses[1], 2); Grid.SetRow(ellipses[1], 2); Grid.SetColumn(ellipses[2], 2); Grid.SetRow(ellipses[2], 0); Grid.SetColumn(ellipses[3], 0); Grid.SetRow(ellipses[3], 2); Grid.SetColumn(ellipses[4], 1); Grid.SetRow(ellipses[4], 1); return; } if (dots == 6) { List<Ellipse> ellipses = new List<Ellipse>(); for (int i = 0; i < dots; i++) { ellipses.Add(e); grid.Children.Add(ellipses[i]); } Grid.SetColumn(ellipses[1], 2); Grid.SetRow(ellipses[1], 2); Grid.SetColumn(ellipses[2], 2); Grid.SetRow(ellipses[2], 0); Grid.SetColumn(ellipses[3], 0); Grid.SetRow(ellipses[3], 2); Grid.SetColumn(ellipses[4], 1); Grid.SetRow(ellipses[4], 0); Grid.SetColumn(ellipses[5], 1); Grid.SetRow(ellipses[5], 2); return; } }
多米诺骨牌XAML布局
<Border Background="AntiqueWhite" CornerRadius="7" > <Grid Name="Layout"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition Width="5"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid Grid.Column="0" x:Name="Left"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> </Grid> <Grid Grid.Column="2" x:Name="Right"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> </Grid> </Grid> </Border>
问题根源
你在代码中只创建了一个Ellipse实例e,后续循环里反复将这个实例添加到Grid的子元素集合中。WPF的视觉元素属于独占式父容器,同一个元素不能同时被多个父容器持有,也不能重复添加到同一个父容器,因此触发异常。
解决方案
为每个圆点创建独立的Ellipse实例,同时简化冗余的代码逻辑:
修复后的代码
private void Arrange(Grid grid, byte dots) { // 创建中间分隔线(按需启用添加到Layout的代码) Border b = new Border { Background = new SolidColorBrush(Colors.Black), Margin = new Thickness(0, 5, 0, 5), CornerRadius = new CornerRadius(2.5) }; Grid.SetColumn(b, 1); // BoneView.Layout.Children.Add(b); if (dots == 0) return; // 预定义不同点数对应的圆点位置(行索引, 列索引) var dotPositionMap = new Dictionary<byte, List<(int Row, int Col)>> { {1, new List<(int, int)> {(1, 1)}}, {2, new List<(int, int)> {(0, 0), (2, 2)}}, {3, new List<(int, int)> {(0, 0), (2, 2), (1, 1)}}, {4, new List<(int, int)> {(0, 0), (2, 2), (0, 2), (2, 0)}}, {5, new List<(int, int)> {(0, 0), (2, 2), (0, 2), (2, 0), (1, 1)}}, {6, new List<(int, int)> {(0, 0), (2, 2), (0, 2), (2, 0), (0, 1), (2, 1)}} }; // 遍历位置,创建新Ellipse并添加到Grid foreach (var (row, col) in dotPositionMap[dots]) { Ellipse dot = CreateDot(); grid.Children.Add(dot); Grid.SetRow(dot, row); Grid.SetColumn(dot, col); } } // 封装创建圆点的方法,每次调用生成新实例 private Ellipse CreateDot() { return new Ellipse { Fill = new SolidColorBrush(Colors.Black), Width = 12, // 可根据布局调整大小 Height = 12, Margin = new Thickness(2) // 可选:添加间距避免圆点贴边 }; }
修复说明
- 独立实例创建:通过
CreateDot方法每次生成全新的Ellipse对象,彻底避免重复添加同一实例的问题。 - 逻辑简化:用字典存储不同点数对应的圆点坐标,替代原有大量if-else分支,代码可读性和可维护性大幅提升。
- 样式统一:圆点的样式(颜色、大小、间距)集中在
CreateDot方法中,后续修改只需调整这一处。
内容的提问来源于stack exchange,提问作者Cover Basha
相关产品推荐
相关产品推荐

