ContextMenu.PlacementTarget (DependencyProperty)

 

ContextMenu가 열리는 위치의 기준이 되는 UIElement를 가져오거나 설정함

'.NET > WPF' 카테고리의 다른 글

ObjectDataProvider  (0) 2022.05.28
Calendar  (0) 2021.12.24
WPF CustomControl  (0) 2021.08.15
Adorner  (0) 2021.08.15
WPF Graphics Rendering  (0) 2021.08.15

Choose the right base class

UIElement Layout, Input, Focus and Events
FrameworkElement Style, ToolTip, ContextMenu, and etc.
Control Template, Foreground, Background, FontSize
ContentControl ContentProperty
HeaderedContentControl HeaderProperty
TabControl, Expander, GroupBox
ItemsControl ItemCollection
Selector ComboBox, ListBox, ListView, TabControl
RangeBase Slider, ProgressBar
MinimumProperty, MaximumProperty

Override the Default Style

static MyCustomControl()
{
    DefaultStyleKeyProperty.OverrideMetadata(
        typeof(MyCustomControl),
        new FrameworkPropertyMetadata(typeof(MyCustomControl));
}

Create a default Style

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns:sd="clr-namespace:System.Drawing;assembly=System.Drawing"
    xmlns:swm="clr-namespace:System.Windows.Media;assembly=PresentationCore">
 
    <Style TargetType="{x:Type local:MyCustomControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:MyCustomControl}">
                    ...
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
 
</ResourceDictionary>
public static readonly DependencyProperty MyContentProperty =
    DependencyProperty.Register(
        nameof(MyContent),
        typeof(object),
        typeof(MyCustomControl),
        new FrameworkPropertyMetadata(
            null,
            FrameworkPropertyMetadataOptions.AffectsRender |
            FrameworkPropertyMetadataOptions.AffectsParentMeasure));
 
public object MyContent
{
    get => GetValue(MyContentProperty);
    set => SetValue(MyContentProperty, value);
}

'.NET > WPF' 카테고리의 다른 글

Calendar  (0) 2021.12.24
WPF ContextMenu Tips  (0) 2021.08.15
Adorner  (0) 2021.08.15
WPF Graphics Rendering  (0) 2021.08.15
Routed Event  (0) 2021.08.15

UIElement 위에 정보, 기능 등을 표시하기 위해 사용하는 사용자 지정 FrameworkElement

Adorner는 UIElement 내에 AdornerLayer를 생성하여 그 위에 객체를 배치하므로 어떤 객체들보다 상위에 나타난다.

(Z-inddex 등을 조절하는 것보다 편한 방법)

 

Adorner 모든 구체적인 표시기 구현이 상속받는 추상 기본 클래스
AdornerLayer 하나 이상의 표시한 요소의 표시기에 대한 렌더링 계층을 나타내는 클래스
AdornerDecorator 표시기 계층이 요소 컬렉션에 연결될 수 있도록 하는 클래스

MSDN

// 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 dc)
    {
        Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);
 
        // Some arbitrary drawing implements.
        var 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.
        dc.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopLeft, renderRadius, renderRadius);
        dc.DrawEllipse(renderBrush, renderPen, adornedElementRect.TopRight, renderRadius, renderRadius);
        dc.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomLeft, renderRadius, renderRadius);
        dc.DrawEllipse(renderBrush, renderPen, adornedElementRect.BottomRight, renderRadius, renderRadius);
    }
}
myAdornerLayer = AdornerLayer.GetAdornerLayer(myTextBox);
myAdornerLayer.Add(new SimpleCircleAdorner(myTextBox));

SimpleCircleAdorner

 

★마우스 이벤트를 받지 않고 통과시키려면

myAdorner.IsHitTestVisible = false;

'.NET > WPF' 카테고리의 다른 글

WPF ContextMenu Tips  (0) 2021.08.15
WPF CustomControl  (0) 2021.08.15
WPF Graphics Rendering  (0) 2021.08.15
Routed Event  (0) 2021.08.15
ScrollViewer Tips  (0) 2021.08.15

Role of the Visual Object

Provides support for:

  • Output display
    • Rendering the persisted, serialzied drawing content of a visual.
  • Transformations
  • Clipping
  • Hit testing
    • Detemining whether a coordinate or geometry is contained within the bounds of a visual.
  • Bounding box calculations

Not include support for non-rendering features:

  • Event handling
  • Layout
  • Styles
  • Data binding
  • Globalization

시각적 개체 클래스 계층 구조

DrawingVisual Class

A lightweight drawing class that is used to render shapes, images, or text.

It does not provide layout or event handling, which improves its runtime performance.

Ideal for backgrounds and clip art.

 

Viewport3DVisual class

 

ContainerVisual class

Used as a container for a collection of Visual Objects.

Drawing Content in Visual Objects

Drawing Content at the Visual Layer

You never directly instantiate a DrawingContext;

you can, however, acquire a drawing context from certain methods, such as:

  • DrawingOpen.Open
  • DrawingVisual.RenderOpen
// Create a DrawingVisual that contains a rectangle.
private DrawingVisual CreateDrawingVisualRectangle()
{
    var dv = new DrawingVisual();
 
    // Retrieve the DrawingContext in order to create new drawing content.
    DrawingContext dc = dv.RenderOpen();
 
    // Create a rectangle and draw it in the DrawingContext.
    Rect rect = new Rect(new Point(160, 100), new Size(320, 80));
    dc.DrawRectangle(Brushes.LightBlue, (System.Windows.Media.Pen)null, rect);
 
    // Persist the drawing content.
    dc.Close();
 
    return dv;
}

Enumerating Drawing Content at the Visual Layer

public void RetrieveDrawing(Visual v)
{
    DrawingGroup dg = VisualTreeHelper.GetDrawing(v);
    EnumDrawingGroup(dg);
}
 
// Enumerate the drawings in the DrawingGroup.
public void EnumDrawingGroup(DrawingGroup dg)
{
    DrawingCollection dc = dg.Children;
 
    // Enumerate the drawings in the DrawingCollection.
    foreach (Drawing drawing in dc)
    {
        // If the drawing is a DrawingGroup, call the function recursively.
        if (drawing is DrawingGroup group)
        {
            EnumDrawingGroup(group);
        }
        else if (drawing is GeometryDrawing)
        {
            // Perform action based on drawing type.  
        }
        else if (drawing is ImageDrawing)
        {
            // Perform action based on drawing type.
        }
        else if (drawing is GlyphRunDrawing)
        {
            // Perform action based on drawing type.
        }
        else if (drawing is VideoDrawing)
        {
            // Perform action based on drawing type.
        }
    }
}

 

How Visual Objects are Used to Build Controls

 

Visual Tree

 

Visual Rendering Behavior

 

VisualTreeHelper Class

 

Hit Testing

 

Enumerating the Visual Tree

// Enumerate all the descendants of the visual object.
static public void EnumVisual(Visual myVisual)
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); ++i)
    {
        // Retrieve child visual at specified index value.
        var childVisual = VisualTreeHelper.GetChild(myVisual, i) as Visual;
 
        // Do processing of the child visual object.
 
        // Enumerate children of the child visual object.
        EnumVisual(childVisual);
    }
}
// Returns the cached bounding box rectangle for the the specified Visual.
Rect rcBounds = VisualTreeHelper.GetContentBounds(myVisual);
 
// Return the bounding rectangle of the parent visual object and all of its descendants.
Rect rcBounds = VisualTreeHelper.GetDescendantBounds(parentVisual);

 

'.NET > WPF' 카테고리의 다른 글

WPF CustomControl  (0) 2021.08.15
Adorner  (0) 2021.08.15
Routed Event  (0) 2021.08.15
ScrollViewer Tips  (0) 2021.08.15
Save Canvas as an Image  (0) 2021.08.15

Bubbling & Tunneling

Bubbling: 일반적으로 사용되는 방식, from Child to Parent until Root!

Tunneling: 접두사로 Preview가 붙는 이벤트, from Root to Child.

 

input event routing

 

더이상 이벤트가 전파되지 않도록 막는 방법

void MyEventHandler(object sender, RoutedEventArgs e)
{
    e.Handled = true;
}

 

Custom Routed Event

MSDN

public class MyButtonSimple: Button
{
    // Create a custom routed event by first registering a RoutedEventID
    // This event uses the bubbling routing strategy
    public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
        "Tap",
        RoutingStrategy.Bubble,
        typeof(RoutedEventHandler),
        typeof(MyButtonSimple));
 
    // Provide CLR accessors for the event
    public event RoutedEventHandler Tap
    {
        add { AddHandler(TapEvent, value); } 
        remove { RemoveHandler(TapEvent, value); }
    }
 
    // This method raises the Tap event
    void RaiseTapEvent()
    {
        var newEventArgs = new RoutedEventArgs(MyButtonSimple.TapEvent);
        RaiseEvent(newEventArgs);
    }
 
    // For demonstration purposes we raise the event when the MyButtonSimple is clicked
    protected override void OnClick()
    {
        RaiseTapEvent();
    }
}

 

'.NET > WPF' 카테고리의 다른 글

Adorner  (0) 2021.08.15
WPF Graphics Rendering  (0) 2021.08.15
ScrollViewer Tips  (0) 2021.08.15
Save Canvas as an Image  (0) 2021.08.15
LayoutTransform vs. RenderTransform  (0) 2021.08.15

+ Recent posts