none
在Canvas上将DrawingVisual转化为FrameworkElement以后出现的问题? RRS feed

  • 问题

  • 我在Canvas上利用DrawingVisual进行动态绘制,绘制完成以后将DrawingVisual里面的内容转移到一个新的FrameworkElement中,然后移除DrawingVisual,并将FrameworkElement加入到Canvas的Children集合中。程序运行以后,绘制的内容作为FrameworkElement存在于Children集合中,但是我通过其它方式插入一个Image以后,在进行动态绘制,就出现问题了。1、动态绘制的内容显示在Image的下面,只有绘制完成以后,才会在Image上显示;2、动态绘制的线条和没有加入Image以前相比,延迟变明显了。请问这里如何解决?

    示例链接地址如下:https://skydrive.live.com/redir.aspx?cid=8f125a6da8d15aee&resid=8F125A6DA8D15AEE!112

    代码如下:

        /// <summary>
        /// Window2.xaml 的交互逻辑
        /// </summary>
        public partial class Window2 : Window
        {
            public Window2()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                string path = AppDomain.CurrentDomain.BaseDirectory;
                if (!path.EndsWith("\\")) { path += "\\"; }
                path += "Cats_Baby.jpg";
                Image image = new Image();
                BitmapImage myBitmapImage = new BitmapImage();
                myBitmapImage.BeginInit();
                myBitmapImage.UriSource = new Uri(path);
                myBitmapImage.EndInit();
                image.Source = myBitmapImage;
                image.Width = 200;
                image.Height = 200;
                this.window2Panel1.Children.Add(image);   
            }
        }
    
        public class Window2Panel : Canvas
        {
            private VisualCollection _col;
    
            public Window2Panel()
            {
                _col = new VisualCollection(this); 
            }
    
            protected override Visual GetVisualChild(int index)
            {
                if (index >= _col.Count)
                {
                    return this.Children[index - _col.Count];
                }
                else
                {
                    return _col[index];
                }
            }
    
            protected override int VisualChildrenCount
            {
                get
                {
                    return _col.Count + this.Children.Count;
                }
            }
            
    
            bool down = false;
    
            TestVisual testpen = null;
    
            protected override void OnMouseDown(MouseButtonEventArgs e)
            {
                down = true;
                testpen = new TestVisual(e.GetPosition(this));
                _col.Add(testpen);             
            }
    
            protected override void OnMouseMove(MouseEventArgs e)
            {
                if (down && testpen != null)
                {
                    testpen.AddPoint(e.GetPosition(this));  
                }
            }
            protected override void OnMouseUp(MouseButtonEventArgs e)
            {
                down = false;
                if (testpen != null)
                {
                    this._col.Remove(testpen);
                    TestItem item = new TestItem(testpen.stroke.Clone());
                    this.Children.Add(item);
                    testpen = null;
                }
            }
        }
    
        public class TestVisual : DrawingVisual
        {
            public Stroke stroke;
    
            public TestVisual(Point point):this(new StylusPoint(point.X, point.Y))
            {            
            }
    
            public TestVisual(StylusPoint point)
            {
                StylusPointCollection points = new StylusPointCollection();
                points.Add(point); 
                stroke = new Stroke(points);
            }
    
            public void AddPoint(Point point)
            {
                this.AddPoint(new StylusPoint(point.X, point.Y));
            }
    
            public void AddPoint(StylusPoint point)
            {
                stroke.StylusPoints.Add(point);
                this.Draw();
            }
    
            private void Draw()
            {
                DrawingContext dc = this.RenderOpen();
                stroke.Draw(dc);
                dc.Close();
            }
        }
    
        public class TestItem :FrameworkElement 
        {  
            private Stroke _stroke;
    
            public TestItem(Stroke stroke)
            {
                this._stroke = stroke;  
            }
    
            protected override void OnRender(DrawingContext drawingContext)
            {
                if (_stroke != null)
                {
                    _stroke.Draw(drawingContext);
                }
    
            }
        }
    

    请问这里如何解决?谢谢了!

    2011年10月10日 7:42

答案

  • 先讲原因吧,我看了下插入图片后的Visual Tree, 你的 DrawingVisual 虽然位于图片的上面 (可视树是这么显示的)但是 DrawingVisual 始终是在用 DrawingContext 中绘制,而你的 DrawingVisual 是建立在Canvas上的,所以你的动态绘制永远在图片下方。

    方式还是两种,一是在装饰层进行 DrawingVisual 的绘制,通过建立Canvas的装饰层,达到最顶层效果。然后再转换成UIElement到Canvas的Children中。

    二是,直接在Canvas中Chlidren插入一个UIElement元素,然后在这个UIElement元素的 VisualCollection 中加入 DrawingVisual 进行绘制。

    我修改了你的代码,采用了第二种方案,你看下:

      /// <summary>
      /// Window2.xaml 的交互逻辑
      /// </summary>
      public partial class Window2 : Window
      {
        public Window2()
        {
          InitializeComponent();
        }
    
        private void button1_Click(object sender, RoutedEventArgs e)
        {
          string path = AppDomain.CurrentDomain.BaseDirectory;
          if (!path.EndsWith("\\")) { path += "\\"; }
          path += "Cats_Baby.jpg";
          Image image = new Image();
          BitmapImage myBitmapImage = new BitmapImage();
          myBitmapImage.BeginInit();
          myBitmapImage.UriSource = new Uri(path);
          myBitmapImage.EndInit();
          image.Source = myBitmapImage;
          image.Width = 200;
          image.Height = 200;
          this.window2Panel1.Children.Add(image);
        }
      }
    
      public class Window2Panel : Canvas
      {
        bool down = false;
    
        TestItem testpen = null;
    
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
          down = true;
          testpen = new TestItem(e.GetPosition(this));
          this.Children.Add(testpen);
        }
    
        protected override void OnMouseMove(MouseEventArgs e)
        {
          if (down && testpen != null)
          {
            testpen.AddPoint(e.GetPosition(this));
          }
        }
        protected override void OnMouseUp(MouseButtonEventArgs e)
        {
          down = false;
          if (testpen != null)
          {
            testpen.DV2UE();
            testpen = null;
          }
        }
      }
    
    
      public class TestVisual : DrawingVisual
      {
        public Stroke stroke;
    
        public TestVisual(Point point)
          : this(new StylusPoint(point.X, point.Y))
        {
        }
    
        public TestVisual(StylusPoint point)
        {
          StylusPointCollection points = new StylusPointCollection();
          points.Add(point);
          stroke = new Stroke(points);
        }
    
        public void AddPoint(Point point)
        {
          this.AddPoint(new StylusPoint(point.X, point.Y));
        }
    
        public void AddPoint(StylusPoint point)
        {
          stroke.StylusPoints.Add(point);
          this.Draw();
        }
    
        private void Draw()
        {
          DrawingContext dc = this.RenderOpen();
          stroke.Draw(dc);
          dc.Close();
        }
      }
    
      public class TestItem : UIElement
      {
        private Stroke _stroke;
        private VisualCollection _col;
        private TestVisual _tpen;
    
        protected override Visual GetVisualChild(int index)
        {
          return _col[index];
        }
    
        protected override int VisualChildrenCount
        {
          get
          {
            return _col.Count;
          }
        }
    
        public TestItem(Point point) : this(new StylusPoint(point.X, point.Y)) { }
    
        public TestItem(StylusPoint point)
        {
          _col = new VisualCollection(this);
          _tpen = new TestVisual(point);
          _col.Add(_tpen);
        }
    
        public void AddPoint(Point point)
        {
          _tpen.AddPoint(new StylusPoint(point.X, point.Y));
        }
    
        protected override void OnRender(DrawingContext drawingContext)
        {
          if (_stroke != null)
          {
            _stroke.Draw(drawingContext);
          }
        }
    
        public void DV2UE()
        {
          this._col.Remove(_tpen);
          this._stroke = _tpen.stroke.Clone();
          this.InvalidateVisual();
        }
      }
    

    Sincerely,


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 张柱敏 2011年10月12日 6:28
    2011年10月11日 8:36
    版主

全部回复

  • Dear all,
    My idea is: Using DrawingVisual draw on a Canvas, lift the mouse after the contents of the DrawingVisual transferred to a UIElement, and then remove the DrawingVisual, and UIElement added to the Canvas's Children collection.
    But I by clicking the "Insert Image" button to add a Image, discovered two problems:
    1、Lines drawn in the Image below, only the drawing is completed, will be on display in the Image;
    2、In the drawing process, the line slowed down, obviously the delay;
    Is this why? How to solve?
    Code:
        public partial class Window2 : Window
        {
            public Window2()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
                string path = AppDomain.CurrentDomain.BaseDirectory;
                if (!path.EndsWith("\\")) { path += "\\"; }
                path += "Cats_Baby.jpg";
                Image image = new Image();
                BitmapImage myBitmapImage = new BitmapImage();
                myBitmapImage.BeginInit();
                myBitmapImage.UriSource = new Uri(path);
                myBitmapImage.EndInit();
                image.Source = myBitmapImage;
                image.Width = 200;
                image.Height = 200;
                this.window2Panel1.Children.Add(image);   
            }
        }
    
        public class Window2Panel : Canvas
        {
            private VisualCollection _col;
    
            public Window2Panel()
            {
                _col = new VisualCollection(this); 
            }
    
            protected override Visual GetVisualChild(int index)
            {
                if (index >= _col.Count)
                {
                    return this.Children[index - _col.Count];
                }
                else
                {
                    return _col[index];
                }
            }
    
            protected override int VisualChildrenCount
            {
                get
                {
                    return _col.Count + this.Children.Count;
                }
            }
            
    
            bool down = false;
    
            TestVisual testpen = null;
    
            protected override void OnMouseDown(MouseButtonEventArgs e)
            {
                down = true;
                testpen = new TestVisual(e.GetPosition(this));
                _col.Add(testpen);             
            }
    
            protected override void OnMouseMove(MouseEventArgs e)
            {
                if (down && testpen != null)
                {
                    testpen.AddPoint(e.GetPosition(this));  
                }
            }
            protected override void OnMouseUp(MouseButtonEventArgs e)
            {
                down = false;
                if (testpen != null)
                {
                    this._col.Remove(testpen);
                    TestItem item = new TestItem(testpen.stroke.Clone());
                    this.Children.Add(item);
                    testpen = null;
                }
            }
        }
    
        public class TestVisual : DrawingVisual
        {
            public Stroke stroke;
    
            public TestVisual(Point point):this(new StylusPoint(point.X, point.Y))
            {            
            }
    
            public TestVisual(StylusPoint point)
            {
                StylusPointCollection points = new StylusPointCollection();
                points.Add(point); 
                stroke = new Stroke(points);
            }
    
            public void AddPoint(Point point)
            {
                this.AddPoint(new StylusPoint(point.X, point.Y));
            }
    
            public void AddPoint(StylusPoint point)
            {
                stroke.StylusPoints.Add(point);
                this.Draw();
            }
    
            private void Draw()
            {
                DrawingContext dc = this.RenderOpen();
                stroke.Draw(dc);
                dc.Close();
            }
        }
    
        public class TestItem :FrameworkElement 
        {  
            private Stroke _stroke;
    
            public TestItem(Stroke stroke)
            {
                this._stroke = stroke;  
            }
    
            protected override void OnRender(DrawingContext drawingContext)
            {
                if (_stroke != null)
                {
                    _stroke.Draw(drawingContext);
                }
            }
        }
    

    Please help.
    Thank you!
    2011年10月11日 6:23
  • 先讲原因吧,我看了下插入图片后的Visual Tree, 你的 DrawingVisual 虽然位于图片的上面 (可视树是这么显示的)但是 DrawingVisual 始终是在用 DrawingContext 中绘制,而你的 DrawingVisual 是建立在Canvas上的,所以你的动态绘制永远在图片下方。

    方式还是两种,一是在装饰层进行 DrawingVisual 的绘制,通过建立Canvas的装饰层,达到最顶层效果。然后再转换成UIElement到Canvas的Children中。

    二是,直接在Canvas中Chlidren插入一个UIElement元素,然后在这个UIElement元素的 VisualCollection 中加入 DrawingVisual 进行绘制。

    我修改了你的代码,采用了第二种方案,你看下:

      /// <summary>
      /// Window2.xaml 的交互逻辑
      /// </summary>
      public partial class Window2 : Window
      {
        public Window2()
        {
          InitializeComponent();
        }
    
        private void button1_Click(object sender, RoutedEventArgs e)
        {
          string path = AppDomain.CurrentDomain.BaseDirectory;
          if (!path.EndsWith("\\")) { path += "\\"; }
          path += "Cats_Baby.jpg";
          Image image = new Image();
          BitmapImage myBitmapImage = new BitmapImage();
          myBitmapImage.BeginInit();
          myBitmapImage.UriSource = new Uri(path);
          myBitmapImage.EndInit();
          image.Source = myBitmapImage;
          image.Width = 200;
          image.Height = 200;
          this.window2Panel1.Children.Add(image);
        }
      }
    
      public class Window2Panel : Canvas
      {
        bool down = false;
    
        TestItem testpen = null;
    
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
          down = true;
          testpen = new TestItem(e.GetPosition(this));
          this.Children.Add(testpen);
        }
    
        protected override void OnMouseMove(MouseEventArgs e)
        {
          if (down && testpen != null)
          {
            testpen.AddPoint(e.GetPosition(this));
          }
        }
        protected override void OnMouseUp(MouseButtonEventArgs e)
        {
          down = false;
          if (testpen != null)
          {
            testpen.DV2UE();
            testpen = null;
          }
        }
      }
    
    
      public class TestVisual : DrawingVisual
      {
        public Stroke stroke;
    
        public TestVisual(Point point)
          : this(new StylusPoint(point.X, point.Y))
        {
        }
    
        public TestVisual(StylusPoint point)
        {
          StylusPointCollection points = new StylusPointCollection();
          points.Add(point);
          stroke = new Stroke(points);
        }
    
        public void AddPoint(Point point)
        {
          this.AddPoint(new StylusPoint(point.X, point.Y));
        }
    
        public void AddPoint(StylusPoint point)
        {
          stroke.StylusPoints.Add(point);
          this.Draw();
        }
    
        private void Draw()
        {
          DrawingContext dc = this.RenderOpen();
          stroke.Draw(dc);
          dc.Close();
        }
      }
    
      public class TestItem : UIElement
      {
        private Stroke _stroke;
        private VisualCollection _col;
        private TestVisual _tpen;
    
        protected override Visual GetVisualChild(int index)
        {
          return _col[index];
        }
    
        protected override int VisualChildrenCount
        {
          get
          {
            return _col.Count;
          }
        }
    
        public TestItem(Point point) : this(new StylusPoint(point.X, point.Y)) { }
    
        public TestItem(StylusPoint point)
        {
          _col = new VisualCollection(this);
          _tpen = new TestVisual(point);
          _col.Add(_tpen);
        }
    
        public void AddPoint(Point point)
        {
          _tpen.AddPoint(new StylusPoint(point.X, point.Y));
        }
    
        protected override void OnRender(DrawingContext drawingContext)
        {
          if (_stroke != null)
          {
            _stroke.Draw(drawingContext);
          }
        }
    
        public void DV2UE()
        {
          this._col.Remove(_tpen);
          this._stroke = _tpen.stroke.Clone();
          this.InvalidateVisual();
        }
      }
    

    Sincerely,


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 张柱敏 2011年10月12日 6:28
    2011年10月11日 8:36
    版主
  • Thanks, same to this thread: http://social.microsoft.com/Forums/zh-CN/wpfzhchs/thread/a8153f36-19b5-40f9-8750-a250377fffb8

    Sincerely,


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年10月11日 8:37
    版主
  • 非常感谢!这确实解决了第一个问题。但是为什么我点击“插入图片”以后,再次进行绘制的时候,会变慢呢?我试过了就是在一个不相关的Canvas上,动态添加image(视频组件也是一样)以后,也会变慢。这是为什么呢?这里应该如何解决呢?
    2011年10月11日 9:05
  • 在多了一个Image资源的情况下,进行动态绘制,本身和没有的情况下比总是有性能损耗的。不过我这边感觉不出来。你用WPF Performance Tool 看下,是不是你的硬件绘制触发的特别多;或者你试着完全用 软件来渲染,关闭硬件渲染。
    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年10月11日 9:12
    版主
  • Thank you very much! The first problem is solved.But the second is very strange.In another unrelated Canvas, I added Image, Draw will be affected.Why is this?

    2011年10月11日 9:16
  • Let us discuss it in one thread, I will merge it.
    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年10月11日 9:22
    版主
  • 非常感谢!
    2011年10月12日 6:28