[英]Create custom Shape Control in UWP (Universal Windows Apps), Windows 10
我想創建一個自定義的Shape
控件,該控件根據某些自定義屬性繪制不同的形狀,例如Polygon
, Ellipse
, Rectangle
等。
我能夠像這樣創建一個自定義模板控件ColorShape
:
<Style TargetType="local:CustomShape">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:CustomShape">
<ContentControl x:Name="shapeParent">
</ContentControl>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
然后,重寫OnTemplateChanged
方法,並在shapeParent
ContentControl
插入相應的Shape
控件。
但是我想要的是實際擴展Shape
,以便我可以用相同的方式處理所有形狀,包括framewok和custom。
在WPF中,我們能夠擴展Shape
並覆蓋屬性DefiningGeometry
。 在UWP中,不存在任何要覆蓋的DefiningGeometry
屬性。
如何創建自定義Shape
控件並定義相應的Geometry?
我發現在UWP中創建自定義形狀的唯一方法是擴展Path
類並設置其Data
屬性。
在布局相關部分(例如LayoutUpdated
事件或ArrangeOverride
方法)時,請勿完成更新Data
屬性以解決其他依賴項屬性(例如Width
)變化的問題。
設置Data
會導致另一個布局運行,因此將其設置為在此期間調用的任何內容都會導致異常:
檢測到布局周期。 布局無法完成
我使用的方法是為屬性更改的事件注冊處理程序,並在其中更新Data
。
我寫了一篇博客文章 ,對它進行了更詳細的解釋。
這是我使用的示例:
public class CandlestickShape : Path
{
public double StartValue
{
get { return Convert.ToDouble(GetValue(StartValueProperty)); }
set { SetValue(StartValueProperty, value); }
}
public static readonly DependencyProperty StartValueProperty =
DependencyProperty.Register("StartValue", typeof(double), typeof(CandlestickShape), new PropertyMetadata(0));
public double EndValue
{
get { return Convert.ToDouble(GetValue(EndValueProperty)); }
set { SetValue(EndValueProperty, value); }
}
public static readonly DependencyProperty EndValueProperty =
DependencyProperty.Register("EndValue", typeof(double), typeof(CandlestickShape), new PropertyMetadata(0));
public double MinValue
{
get { return Convert.ToDouble(GetValue(MinValueProperty)); }
set { SetValue(MinValueProperty, value); }
}
public static readonly DependencyProperty MinValueProperty =
DependencyProperty.Register("MinValue", typeof(double), typeof(CandlestickShape), new PropertyMetadata(0));
public double MaxValue
{
get { return Convert.ToDouble(GetValue(MaxValueProperty)); }
set { SetValue(MaxValueProperty, value); }
}
public static readonly DependencyProperty MaxValueProperty =
DependencyProperty.Register("MaxValue", typeof(double), typeof(CandlestickShape), new PropertyMetadata(0));
/// <summary>
/// Defines how many Pixel should be drawn for one Point
/// </summary>
public double PixelPerPoint
{
get { return Convert.ToDouble(GetValue(PointsPerPixelProperty)); }
set { SetValue(PointsPerPixelProperty, value); }
}
public static readonly DependencyProperty PointsPerPixelProperty =
DependencyProperty.Register("PixelPerPoint", typeof(double), typeof(CandlestickShape), new PropertyMetadata(0));
public CandlestickShape()
{
this.RegisterPropertyChangedCallback(CandlestickShape.WidthProperty, new DependencyPropertyChangedCallback(RenderAffectingPropertyChanged));
this.RegisterPropertyChangedCallback(CandlestickShape.StartValueProperty, new DependencyPropertyChangedCallback(RenderAffectingPropertyChanged));
this.RegisterPropertyChangedCallback(CandlestickShape.EndValueProperty, new DependencyPropertyChangedCallback(RenderAffectingPropertyChanged));
this.RegisterPropertyChangedCallback(CandlestickShape.MinValueProperty, new DependencyPropertyChangedCallback(RenderAffectingPropertyChanged));
this.RegisterPropertyChangedCallback(CandlestickShape.MaxValueProperty, new DependencyPropertyChangedCallback(RenderAffectingPropertyChanged));
this.RegisterPropertyChangedCallback(CandlestickShape.PointsPerPixelProperty, new DependencyPropertyChangedCallback(RenderAffectingPropertyChanged));
}
private void RenderAffectingPropertyChanged(DependencyObject o, DependencyProperty e)
{
(o as CandlestickShape)?.SetRenderData();
}
private void SetRenderData()
{
var maxBorderValue = Math.Max(this.StartValue, this.EndValue);
var minBorderValue = Math.Min(this.StartValue, this.EndValue);
double topLineLength = (this.MaxValue - maxBorderValue) * this.PixelPerPoint;
double bottomLineLength = (minBorderValue - this.MinValue) * this.PixelPerPoint;
double bodyLength = (this.EndValue - this.StartValue) * this.PixelPerPoint;
var fillColor = new SolidColorBrush(Colors.Green);
if (bodyLength < 0)
fillColor = new SolidColorBrush(Colors.Red);
bodyLength = Math.Abs(bodyLength);
var bodyGeometry = new RectangleGeometry
{
Rect = new Rect(new Point(0, topLineLength), new Point(this.Width, topLineLength + bodyLength)),
};
var topLineGeometry = new LineGeometry
{
StartPoint = new Point(this.Width / 2, 0),
EndPoint = new Point(this.Width / 2, topLineLength)
};
var bottomLineGeometry = new LineGeometry
{
StartPoint = new Point(this.Width / 2, topLineLength + bodyLength),
EndPoint = new Point(this.Width / 2, topLineLength + bodyLength + bottomLineLength)
};
this.Data = new GeometryGroup
{
Children = new GeometryCollection
{
bodyGeometry,
topLineGeometry,
bottomLineGeometry
}
};
this.Fill = fillColor;
this.Stroke = new SolidColorBrush(Colors.Black);
}
protected override Size ArrangeOverride(Size finalSize)
{
double height = (MaxValue - MinValue) * PixelPerPoint;
return new Size(this.Width, height);
}
protected override Size MeasureOverride(Size availableSize)
{
double height = (MaxValue - MinValue) * PixelPerPoint;
return new Size(this.Width, height);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.