裝飾器學習筆記


裝飾器學習筆記

0 定義

裝飾器可以用來給顯示的控件添加一些裝飾的效果;

1 效果

1 框選

鼠標按下獲取當前點

   startPoint = parameter.GetPosition(Application.Current.MainWindow);

隨着鼠標移動獲取末位點,不斷重新畫矩形

 Point tempEndPoint = parameter.GetPosition(Application.Current.MainWindow);

1.1 畫臨時矩形

 private void DrawRect(Point endPoint, Point startPoint)
        {
            if (selectRect == null)
            {
                selectRect = new Rectangle();
                selectRect.Fill = new SolidColorBrush(Colors.Gray) { Opacity = 0.1 };
                selectRect.Margin = new Thickness(startPoint.X, startPoint.Y, 0, 0);
                Controls.Add(selectRect);
            }
            selectRect.Width = Math.Abs(endPoint.X - startPoint.X);
            selectRect.Height = Math.Abs(endPoint.Y - startPoint.Y);
        }

2 添加裝飾器

裝飾器是 FrameworkElement 綁定到的自定義 UIElement , 裝飾器呈現在裝飾器層中。

  • 裝飾器層是始終位於裝飾元素或裝飾元素集合之上。
  • 裝飾器通常使用位於裝飾元素左上部的標准 2D 坐標原點,相對於其綁定到的元素進行定位。
  • 裝飾器始終以可見的方式位於控件頂部,無法使用 z 順序重寫。

2.1 常規添加裝飾器

常規做法一般在裝飾器層添加裝飾器后,在裝飾器中會以重寫Render的方式添加效果

// Adorners must subclass the abstract base class Adorner.
public class SimpleCircleAdorner : Adorner
{
  // Be sure to call the base class constructor.
  public SimpleCircleAdorner(UIElement adornedElement)
    : base(adornedElement)
  {
  }

  // A common way to implement an adorner's rendering behavior is to override the OnRender
  // method, which is called by the layout system as part of a rendering pass.
  protected override void OnRender(DrawingContext drawingContext)
  {
    Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);

    // Some arbitrary drawing implements.
    SolidColorBrush renderBrush = new SolidColorBrush(Colors.Green);
    renderBrush.Opacity = 0.2;
    Pen renderPen = new Pen(new SolidColorBrush(Colors.Navy), 1.5);
    double renderRadius = 5.0;

    // Draw a circle at each corner.
    drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopLeft, renderRadius, renderRadius);
    drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopRight, renderRadius, renderRadius);
    drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomLeft, renderRadius, renderRadius);
    drawingContext.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomRight, renderRadius, renderRadius);
  }
}

2.1 裝飾器如何添加自定義控件?

裝飾器沒有給出一個直接的方法去添加自定義控件,且裝飾器與外界的聯系只有一個被裝飾的控件,那么我們如何在可視化樹上添加自定義控件呢?

我們可以通過間接的方法:

The AddVisualChild method is a notification to the base class that you've acquired a new child into your collection. It doesn't actually add the child to any collection, but it lets the Visual system know that it needs to redraw. This sounds a bit funny, but it's consistent with the way the logical tree is managed as well.

Similarly, when you remove a Visual from your child collection you must call RemoveVisualChild, so the Visual system knows to stop tracking and displaying that Visual. If you'd like, and it sounds appropriate in your scenario, you don't have to use an actual collection for your child visuals. You can simply have a member variable of type Visual, which you can think of as a collection of maximum length 1. Your implementation of GetVisualChild should return the value of that variable, and your implementation of VisualChildrenCount should probably return 0 if that variable is null, or 1 if it's non-null.

通過重寫GetVisualChild方法使可視化樹重繪

2.2 控件和裝飾器如何實現聯動效果

如果想實現預期的效果,需要裝飾器B和被裝飾控件A聯動,比如當A發生形變時,B也發生形變

正常的,我們可以用A去通知B,但是裝飾器作為獨立的一層,不應該和A產生聯系

我們可以通過重寫ArrangeOverride方法,當重新排序的時候給裝飾器內的自定義控件一個自己的大小(位置)

  public Rect AdonerArrange(Size finalSize)
        {
            int margin = 10;
            return new Rect(-margin, -margin, finalSize.Width + 2 * margin, finalSize.Height + 2 * margin);
        }

3 平移例子

在自定義控件層,我們通過裝飾器拿到被裝飾器的控件

自定義裝飾器控件-->裝飾器層-->被裝飾控件

被裝飾控件:grid

裝飾器層:layer

自定義裝飾器控件:contentControl

 			 var layer = AdornerLayer.GetAdornerLayer(grid);
            DragDropControl contentControl = new DragDropControl(grid);
            contentControl.Background = new SolidColorBrush(Colors.Black) { Opacity = 0.1 };
            layer.Add(new ContentAdorner(grid, contentControl));

之后我們在自定義裝飾器控件contentControl中操作被裝飾控件grid:

        bool isCanMove = false;

        private void thumMove_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
        {
            isCanMove = true;
        }

        private void thumMove_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            if (isCanMove)
            {
                InkCanvas.SetLeft(_adornedElement, InkCanvas.GetLeft(_adornedElement) + e.HorizontalChange);
                InkCanvas.SetTop(_adornedElement, InkCanvas.GetTop(_adornedElement) + e.VerticalChange);
            }
        }

        private void thumMove_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
        {
            isCanMove = false;
        }

此時我們通過contentControl控件平移被裝飾的控件grid

而contentControl通過AdonerArrange方法跟隨grid進行平移

 public Rect AdonerArrange(Size finalSize)
        {
            int margin = 10;
            return new Rect(-margin, -margin, finalSize.Width + 2 * margin, finalSize.Height + 2 * margin);

        }

實現了:

當控件沒有裝飾器時,並不具備平移能力。

當控件有改裝飾器修飾時,具備了平移能力。

即常規裝飾器可以添加效果,自定義控件裝飾器可以添加一些能力。

Demo:https://github.com/tiancai4652/MyDecorator


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM