2016-02-29 109 views
2

我想創建一個自定義Shape調節控制,即繪製不同的形狀,如PolygonEllipseRectangle等,這取決於一些自定義屬性。創建自定義形狀在UWP(通用的Windows應用程序)時,Windows 10

我能夠創建一個自定義模板控制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方法,以及裏面插入的shapeParentContentControl

相應Shape控制但我」 d喜歡實際上擴展Shape,所以我可以用相同的方式處理所有形狀,framewok和custom。

在WPF中,我們能夠擴展Shape並覆蓋屬性DefiningGeometry。 在UWP中,它不存在任何要覆蓋的DefiningGeometry屬性。

如何創建自定義的Shape控件並定義相應的幾何圖形?

回答

3

我發現在UWP中創建自定義形狀的唯一方法是擴展Path類並設置其屬性Data

更新Data屬性以考慮其他依賴屬性(如Width)的變化不能在布點相關部分,如LayoutUpdated事件或ArrangeOverride方法來完成。

設置Data導致另一個佈局來看,所以設置它什麼,它是在調用會導致一個例外:檢測

佈局循環。佈局不能完成

我使用的方式是註冊屬性更改事件的處理程序,並更新Data

我已經寫了一個blog post,它可以更詳細地解釋它。

這是我使用的示例:

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); 
    } 
} 
+0

這包括你的使用情況,但是當你想要與固定點和其他依賴於大小一些地方自定義的恥辱,會發生什麼,這樣的嗎? http://stackoverflow.com/questions/43761186/how-to-create-a-speech-bubble-in-uwp矩形部分取決於大小,但尖角部分是固定的。 – SuperJMN

相關問題