Reputation: 323
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!
Upvotes: 0
Views: 511
Reputation: 128136
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"/>
Upvotes: 1