简体   繁体   中英

CustomControl XAML: ArcSegment.Size binding to control's Actual Width and Height

my fellow programmers!

I have searched the Internet and could not find a solution. Probably this is due to me being a newbie in WPF. I'm trying to achieve the following:

CustomControl having an ArcSegment whose Size is bound to the size of the CustomControl : 在此处输入图像描述

This should illustrate a wafer with dies (semiconductor industry)

So I understood that I need to use <Path> in XAML in order to construct that 'circle with notch'

My problem is that I cannot bind the ArcSegment element to CustomControl's Size . ArcSegment has Size property and CustomControl has ActualWidth & ActualHeight . I tried several approaches but neither of them worked for me.

Here is my class for CustomControl :

    public class WaferMap : Control
    {
        public static readonly DependencyProperty ActualSizeProperty = DependencyProperty.Register(
            nameof(ActualSize), typeof(Size), typeof(WaferMap), new PropertyMetadata(default(Size)));

        public Size ActualSize
        {
            get => (Size) this.GetValue(ActualSizeProperty);
            set => this.SetValue(ActualSizeProperty, value);
        }

        public WaferMap()
        {
            var actualWidthPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ActualWidthProperty, typeof(WaferMap));
            actualWidthPropertyDescriptor.AddValueChanged(this, OnActualWidthOrHeightChanged);

            var actualHeightPropertyDescriptor = DependencyPropertyDescriptor.FromProperty(ActualHeightProperty, typeof(WaferMap));
            actualHeightPropertyDescriptor.AddValueChanged(this, OnActualWidthOrHeightChanged);
        }

        private void OnActualWidthOrHeightChanged(object? sender, EventArgs e)
        {
            this.ActualSize = new Size(ActualWidth, ActualHeight);
        }

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

And the XAML Style that I use for it:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Zeiss.CdAnalizer.Ui">
    <Style TargetType="local:WaferMap">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:WaferMap" >
                    <ControlTemplate.Resources>
                        <local:WaferMap x:Key="WaferMap"/>
                    </ControlTemplate.Resources>
                    <Grid DataContext="{Binding Source={StaticResource WaferMap}}">
                        <Path Stroke="Black" StrokeThickness="1">
                            <Path.Data>
                                <PathGeometry>
                                    <PathGeometry.Figures>
                                        <PathFigureCollection>
                                            <PathFigure StartPoint="145,300">
                                                <PathFigure.Segments>
                                                    <PathSegmentCollection>
                                                        <ArcSegment 
                                                            IsLargeArc="True"
                                                            Size="{Binding Path=ActualSize, PresentationTraceSources.TraceLevel=High}"
                                                            SweepDirection="Clockwise"
                                                            Point="155,300" />
                                                    </PathSegmentCollection>
                                                </PathFigure.Segments>
                                            </PathFigure>
                                        </PathFigureCollection>
                                    </PathGeometry.Figures>
                                </PathGeometry>
                            </Path.Data>
                        </Path>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style></ResourceDictionary>

Surely I'll need to bind also the StartPoint , but first I wanted to see that simple stuff works for me. Unfortunately, it doesn't. I see this in my Output window:

System.Windows.Data Warning: 60 : BindingExpression (hash=14976165): Default mode resolved to OneWay
System.Windows.Data Warning: 61 : BindingExpression (hash=14976165): Default update trigger resolved to PropertyChanged
System.Windows.Data Warning: 62 : BindingExpression (hash=14976165): Attach to System.Windows.Media.ArcSegment.Size (hash=24211521)
System.Windows.Data Warning: 64 : BindingExpression (hash=14976165): Use Framework mentor <null>
System.Windows.Data Warning: 67 : BindingExpression (hash=14976165): Resolving source 
System.Windows.Data Warning: 69 : BindingExpression (hash=14976165): Framework mentor not found
System.Windows.Data Warning: 65 : BindingExpression (hash=14976165): Resolve source deferred
System.Windows.Data Warning: 95 : BindingExpression (hash=14976165): Got InheritanceContextChanged event from ArcSegment (hash=24211521)
System.Windows.Data Warning: 67 : BindingExpression (hash=14976165): Resolving source 
System.Windows.Data Warning: 69 : BindingExpression (hash=14976165): Framework mentor not found
System.Windows.Data Warning: 95 : BindingExpression (hash=14976165): Got InheritanceContextChanged event from ArcSegment (hash=24211521)
System.Windows.Data Warning: 67 : BindingExpression (hash=14976165): Resolving source 
System.Windows.Data Warning: 69 : BindingExpression (hash=14976165): Framework mentor not found
System.Windows.Data Warning: 95 : BindingExpression (hash=14976165): Got InheritanceContextChanged event from ArcSegment (hash=24211521)
System.Windows.Data Warning: 67 : BindingExpression (hash=14976165): Resolving source 
System.Windows.Data Warning: 69 : BindingExpression (hash=14976165): Framework mentor not found
System.Windows.Data Warning: 95 : BindingExpression (hash=14976165): Got InheritanceContextChanged event from ArcSegment (hash=24211521)
System.Windows.Data Warning: 67 : BindingExpression (hash=14976165): Resolving source 
System.Windows.Data Warning: 69 : BindingExpression (hash=14976165): Framework mentor not found
System.Windows.Data Warning: 95 : BindingExpression (hash=14976165): Got InheritanceContextChanged event from ArcSegment (hash=24211521)
System.Windows.Data Warning: 67 : BindingExpression (hash=14976165): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=14976165): Found data context element: Path (hash=10232270) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=14976165): Activate with root item WaferMap (hash=14353717)
System.Windows.Data Warning: 108 : BindingExpression (hash=14976165):   At level 0 - for WaferMap.ActualSize found accessor DependencyProperty(ActualSize)
System.Windows.Data Warning: 104 : BindingExpression (hash=14976165): Replace item at level 0 with WaferMap (hash=14353717), using accessor DependencyProperty(ActualSize)
System.Windows.Data Warning: 101 : BindingExpression (hash=14976165): GetValue at level 0 from WaferMap (hash=14353717) using DependencyProperty(ActualSize): Size (hash=0)
System.Windows.Data Warning: 80 : BindingExpression (hash=14976165): TransferValue - got raw value Size (hash=0)
System.Windows.Data Warning: 89 : BindingExpression (hash=14976165): TransferValue - using final value Size (hash=0)

When I say it doesn't work = when I change the size of the form nothing happens (the arc stays the same small dash). Also, the WaferMap.ActualSize.get is never get called. The setter is called when I change size of the form (As you can see I have registered to change event of ActualWidth and ActualHeight ).

Thank you!

You may perhaps use a simple derived Shape like shown below.

It draws an ArcSegment with a notch at the bottom center, and all you would have to do is to adjust the size of the notch.

public class WaferMap : Shape
{
    private readonly StreamGeometry geometry = new StreamGeometry();

    protected override Geometry DefiningGeometry => geometry;

    protected override Size MeasureOverride(Size size)
    {
        if (double.IsInfinity(size.Width))
        {
            size.Width = StrokeThickness;
        }

        if (double.IsInfinity(size.Height))
        {
            size.Height = StrokeThickness;
        }

        return size;
    }

    protected override Size ArrangeOverride(Size size)
    {
        var x = size.Width / 2;
        var y = size.Height - StrokeThickness / 2;
        var arcSize = new Size(
            (size.Width - StrokeThickness) / 2, (size.Height - StrokeThickness) / 2);

        using (var sgc = geometry.Open())
        {
            sgc.BeginFigure(new Point(x, y - 20), true, true);
            sgc.LineTo(new Point(x - 10, y), true, true);
            sgc.ArcTo(new Point(x + 10, y), arcSize, 0, true,
                      SweepDirection.Clockwise, true, true);
        }

        return size;
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        drawingContext.DrawGeometry(Fill, new Pen(Stroke, StrokeThickness), geometry);
    }
}

You would use it like any other Shape element:

<local:WaferMap Stroke="Orange" StrokeThickness="3" Margin="10"/>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM