Wpf 如何在鼠标上更改DrawingVisual的颜色

Wpf 如何在鼠标上更改DrawingVisual的颜色,wpf,wpf-graphics,Wpf,Wpf Graphics,以下代码是Adam Nathan WPF 4.5发布版第502页代码示例的改编 按照那里的建议,我创建了一个类VisualHostClass,它“承载”了一个DrawingVisuals列表,从而使它们可以显示。到目前为止,这一做法行之有效 现在我想通过改变显示的视觉效果的颜色来对鼠标左键单击做出反应。此操作的代码位于方法HitTestCallback中 通过包含的Trace.WriteLine语句,我可以看到相关行 drw.Brush = Brushes.Red; 之后,属性笔刷将有一个新值

以下代码是Adam Nathan WPF 4.5发布版第502页代码示例的改编

按照那里的建议,我创建了一个类
VisualHostClass
,它“承载”了一个DrawingVisuals列表,从而使它们可以显示。到目前为止,这一做法行之有效

现在我想通过改变显示的视觉效果的颜色来对鼠标左键单击做出反应。此操作的代码位于方法
HitTestCallback

通过包含的Trace.WriteLine语句,我可以看到相关行

drw.Brush = Brushes.Red;
之后,属性笔刷将有一个新值。但是:显示不变,单击的DrawingVisual随后仍然是黄色(这是创建时使用的笔刷颜色)

我能/应该在这里做什么?(我是WPF的绝对初学者)

提前感谢所有的答案

    public partial class VisualHostClass : FrameworkElement
    {
        public VisualHostClass()
        {
 
        }

        public List<DrawingVisual> myVisuals = new List<DrawingVisual>();

        public void AddVisual(DrawingVisual dvs)
        {
            myVisuals.Add(dvs);
            AddVisualChild(dvs);
            AddLogicalChild(dvs);

        }

        protected override int VisualChildrenCount
        {
            get { return myVisuals.Count; }
        }

        protected override Visual GetVisualChild(int index)
        {
            if (index < 0 || index >= myVisuals.Count)
            {
                throw new ArgumentOutOfRangeException("index");
            }

            return myVisuals[index];
        }

        public void removeAllChilds()
        {
            foreach (DrawingVisual dvs in myVisuals)
            {
                RemoveVisualChild(dvs);
                RemoveLogicalChild(dvs);
            }
            myVisuals.Clear();
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonDown(e);

            Point location = e.GetPosition(this);

            VisualTreeHelper.HitTest(this, null,
                new HitTestResultCallback(HitTestCallback),
                new PointHitTestParameters(location));

        }

        public HitTestResultBehavior HitTestCallback(HitTestResult result)
        {
            if (result.VisualHit.GetType() == typeof(DrawingVisual))
            {
                DrawingVisual dv = result.VisualHit as DrawingVisual;

                Trace.WriteLine("HitTestCallback: dv = " + dv.ToString());

                foreach(GeometryDrawing drw in dv.Drawing.Children)
                {
                    Trace.WriteLine("HitTestCallback: drw = " + drw.ToString());
                    
                    Trace.WriteLine("HitTestCallback: drw.Geometry = " + drw.Geometry.ToString());

                    Trace.WriteLine("HitTestCallback: drw.Brush = " + drw.Brush.ToString());

                    drw.Brush = Brushes.Red;

                    Trace.WriteLine("HitTestCallback: drw.Brush = " + drw.Brush.ToString());

                    Trace.WriteLine("HitTestCallback: drw.IsFrozen = " + drw.IsFrozen.ToString());

                }
 
            }

            return HitTestResultBehavior.Continue;
        }
    }
}
为了记录,我引用了构建
DrawingVisual
并放入
VisualHostClass

        PathGeometry pgnGeom = RenderPolygonWithHoles2Geometry(pgn);

        DrawingVisual dv = new DrawingVisual();

        using (DrawingContext dc = dv.RenderOpen())
        {
            SolidColorBrush brush1 = new SolidColorBrush(Colors.LightGoldenrodYellow);
            dc.DrawGeometry(brush1, null, pgnGeom);
        }

        myVisualHost.AddVisual(dv);

dc.DrawGeometry(…)
创建的图形似乎已冻结,即不可修改

通过我自己的绘画对我很有用:

using (var dc = dv.RenderOpen())
{
    dc.DrawDrawing(new GeometryDrawing(Brushes.LightGoldenrodYellow, null, pgnGeom));
}

你的代码对我来说很好。单击后,笔刷将发生变化,UI将显示一个红色图形。不过,我强烈建议不要在命中测试回调中更改可视化树的任何属性。虽然更改画笔实际上不是对可视化树的修改,但值得记住的是:。。。在命中测试结果枚举期间,不应执行任何修改可视树的操作。在遍历可视化树时从该树中添加或删除对象可能会导致不可预测的行为。对于如何更改图形颜色的一般问题,使用高级形状类(如矩形或路径)会简单得多,并在XAML中附加MouseDown事件处理程序或IsMouseOver触发器。@Clemens关于您对高级形状类(如Path)的建议:我之前使用shape渲染了许多由PathGeometry给定的多边形(每个多边形在其自己的路径中成为画布的子对象)。但是它有点慢,所以我想按照WPF书中的建议使用更轻量级的绘图视觉效果。的确,缩放和平移的渲染速度明显提高了。@Clemens我现在修改了代码,因此,在回调中,找到的DrawingVisualDV被添加到名为changeStage的列表中,该列表在鼠标按钮事件处理程序的末尾由上面驻留在HitTestCallback中的修改代码进行处理,现在成为一个单独的成员函数。但它仍然不起作用。也许这就是问题所在,因为我把VisualHostClass作为一个孩子放在画布中,也许我必须为这个画布调用一个“更新”?非常非常感谢!(不知何故,我太不愿意尝试这一点,因为我从WPF的书中得到的印象是,这会影响性能。但它(至少可以注意到)并不慢)。你真的很想在鼠标点击时看到复杂艺术品的PCB痕迹如何再次变成红色和黄色。。。
using (var dc = dv.RenderOpen())
{
    dc.DrawDrawing(new GeometryDrawing(Brushes.LightGoldenrodYellow, null, pgnGeom));
}