找到一篇有趣的文章,描述如何通过为Panel
类的底层视觉效果公开方法Add
和Remove
来创建自定义画布控件。通过这种方式,我可以创建一个通用的画布,它可以完全容纳任何在上面绘制的方式,GDI+,canvas,Drawings等。例如,第一层将是Bitmap
,第二层Canvas
,第三层DrawingVisual
等。
为了简单起见,我想扩展现有的Canvas
,这样我就可以通过默认Canvas
控件提供原始行为,并且可以创建任意多的额外Visuals
。
这是我现在拥有的。
public class VisualCanvas : Canvas
{
protected IList<Visual> _visuals = null;
protected override int VisualChildrenCount => _visuals.Count;
protected override Visual GetVisualChild(int index) => _visuals.ElementAtOrDefault(index);
public VisualCanvas()
{
_visuals = new List<Visual>();
_visuals.Add(new DrawingVisual());
//(_visuals[0] as DrawingVisual).RenderOpen();
}
public void AddVisual(Visual visual)
{
_visuals.Add(visual);
base.AddVisualChild(visual);
base.AddLogicalChild(visual);
}
public void DeleteVisual(Visual visual)
{
_visuals.Remove(visual);
base.RemoveVisualChild(visual);
base.RemoveLogicalChild(visual);
}
}
不幸的是,我在构造函数中添加的DrawingVisual
并没有使该控件的行为像原始的Canvas
,因为我重写的两个方法似乎期望不同类型的Visual
,而不是DrawingVisual
。
如何使此控件像原始Canvas
一样工作?
在MSDN上发现了类似的问题。似乎仅仅覆盖两个方法来将所有子项保持在一个视觉列表中是不够的。默认画布集合InternalChildren
也需要考虑在内。
这个实现似乎保留了默认的画布行为+新的视觉效果,但可能有不可预测的行为,因为两个类集合共享相同的索引。看起来用每个视觉类型的新属性来扩展这个类会更容易,而不是试图覆盖现有的属性。请随意发布更好的想法和实现。
public class VisualCanvas : Canvas
{
protected IList<Visual> _visuals = new List<Visual>();
protected override int VisualChildrenCount => _visuals.Count + InternalChildren.Count;
protected override Visual GetVisualChild(int index) => _visuals.ElementAtOrDefault(index) ?? InternalChildren[index - _visuals.Count];
public void AddVisual(Visual visual)
{
_visuals.Add(visual);
base.AddVisualChild(visual);
base.AddLogicalChild(visual);
}
public void DeleteVisual(Visual visual)
{
_visuals.Remove(visual);
base.RemoveVisualChild(visual);
base.RemoveLogicalChild(visual);
}
}