21
21
namespace BionicCode . Controls . Net . Core . Wpf
22
22
{
23
23
[ TemplatePart ( Name = "PART_ElementHost" , Type = typeof ( FrameworkElement ) ) ]
24
- public class AnalogClockFace : Control
24
+ public class AnalogClockFace : ContentControl
25
25
{
26
26
#region IsCenterElementOnCircumferenceEnabled attached property
27
27
@@ -230,19 +230,7 @@ public class AnalogClockFace : Control
230
230
public double SelectedSecond { get => ( double ) GetValue ( AnalogClockFace . SelectedSecondProperty ) ; set => SetValue ( AnalogClockFace . SelectedSecondProperty , value ) ; }
231
231
232
232
#endregion SelectedSecond dependency property
233
-
234
- #region Diameter dependency property
235
-
236
- //public static readonly DependencyProperty DiameterProperty = DependencyProperty.Register(
237
- // "Diameter",
238
- // typeof(double),
239
- // typeof(AnalogClockFace),
240
- // new PropertyMetadata(default(double), AnalogClockFace.OnDiameterChanged));
241
-
242
- //public double Diameter { get => (double) GetValue(AnalogClockFace.DiameterProperty); set => SetValue(AnalogClockFace.DiameterProperty, value); }
243
-
244
- #endregion Diameter dependency property
245
-
233
+
246
234
#region ClockFaceLoadedRoutedEvent
247
235
248
236
public static readonly RoutedEvent ClockFaceLoadedRoutedEvent = EventManager . RegisterRoutedEvent ( "ClockFaceLoaded" ,
@@ -256,21 +244,39 @@ public event RoutedEventHandler ClockFaceLoaded
256
244
257
245
#endregion
258
246
247
+ #region Diameter read-only dependecy property
248
+
249
+ protected static readonly DependencyPropertyKey DiameterPropertyKey = DependencyProperty . RegisterReadOnly (
250
+ "Diameter" ,
251
+ typeof ( double ) ,
252
+ typeof ( AnalogClockFace ) ,
253
+ new PropertyMetadata ( default ( double ) ) ) ;
254
+
255
+ public static readonly DependencyProperty DiameterProperty = AnalogClockFace . DiameterPropertyKey . DependencyProperty ;
256
+
257
+ public double Diameter
258
+ {
259
+ get => ( double ) GetValue ( AnalogClockFace . DiameterProperty ) ;
260
+ private set => SetValue ( AnalogClockFace . DiameterPropertyKey , value ) ;
261
+ }
262
+
263
+ #endregion Diameter read-only dependecy property
264
+
259
265
#region Radius read-only dependecy property
260
266
261
- // protected static readonly DependencyPropertyKey RadiusPropertyKey = DependencyProperty.RegisterReadOnly(
262
- // "Radius",
263
- // typeof(double),
264
- // typeof(AnalogClockFace),
265
- // new PropertyMetadata(default(double)));
267
+ protected static readonly DependencyPropertyKey RadiusPropertyKey = DependencyProperty . RegisterReadOnly (
268
+ "Radius" ,
269
+ typeof ( double ) ,
270
+ typeof ( AnalogClockFace ) ,
271
+ new PropertyMetadata ( default ( double ) ) ) ;
266
272
267
- // public static readonly DependencyProperty RadiusProperty = AnalogClockFace.RadiusPropertyKey.DependencyProperty;
273
+ public static readonly DependencyProperty RadiusProperty = AnalogClockFace . RadiusPropertyKey . DependencyProperty ;
268
274
269
- // public double Radius
270
- // {
271
- // get => (double) GetValue(AnalogClockFace.RadiusProperty);
272
- // private set => SetValue(AnalogClockFace.RadiusPropertyKey, value);
273
- // }
275
+ public double Radius
276
+ {
277
+ get => ( double ) GetValue ( AnalogClockFace . RadiusProperty ) ;
278
+ private set => SetValue ( AnalogClockFace . RadiusPropertyKey , value ) ;
279
+ }
274
280
275
281
#endregion Radius read-only dependecy property
276
282
@@ -298,34 +304,29 @@ static AnalogClockFace()
298
304
}
299
305
public AnalogClockFace ( )
300
306
{
301
- InitializeClockFaceCanvas ( ) ;
302
307
InitializeClockRotateTransforms ( ) ;
308
+ InitializeClockFaceCanvas ( ) ;
303
309
this . IntervalLabelFormatter = value => value . ToString ( ) ;
304
- //this.Loaded += OnLoaded;
305
- }
306
-
307
- private void OnLoaded ( object sender , RoutedEventArgs e )
308
- {
309
- AddClockHands ( ) ;
310
310
}
311
311
312
312
private void InitializeClockFaceCanvas ( )
313
313
{
314
314
this . ClockFaceCanvas = new Canvas ( ) ;
315
- var widthBinding = new Binding ( nameof ( this . ActualWidth ) ) { Source = this } ;
315
+ this . Content = this . ClockFaceCanvas ;
316
+
317
+ var widthBinding = new Binding ( nameof ( this . Diameter ) ) { Source = this } ;
316
318
this . ClockFaceCanvas . SetBinding ( FrameworkElement . WidthProperty , widthBinding ) ;
317
319
var heightBinding = new Binding ( nameof ( this . Height ) ) { Source = this } ;
318
320
this . ClockFaceCanvas . SetBinding ( FrameworkElement . HeightProperty , heightBinding ) ;
319
321
}
320
322
321
323
private void InitializeClockRotateTransforms ( )
322
324
{
323
- var radius = this . ActualWidth / 2 ;
324
- this . IntervalElementTransform = new RotateTransform ( 0 , radius , radius ) ;
325
- this . HourHandTransform = new RotateTransform ( 0 , radius , radius ) ;
326
- this . MinuteHandTransform = new RotateTransform ( 0 , radius , radius ) ;
327
- this . SecondHandTransform = new RotateTransform ( 0 , radius , radius ) ;
328
- var radiusBinding = new Binding ( nameof ( this . ActualWidth ) ) { Source = this , Converter = new DividerValueConverter ( ) , ConverterParameter = 2 } ;
325
+ this . IntervalElementTransform = new RotateTransform ( 0 , this . Radius , this . Radius ) ;
326
+ this . HourHandTransform = new RotateTransform ( ) ;
327
+ this . MinuteHandTransform = new RotateTransform ( 0 , this . Radius , this . Radius ) ;
328
+ this . SecondHandTransform = new RotateTransform ( 0 , this . Radius , this . Radius ) ;
329
+ var radiusBinding = new Binding ( nameof ( this . Radius ) ) { Source = this } ;
329
330
BindingOperations . SetBinding ( this . IntervalElementTransform , RotateTransform . CenterXProperty , radiusBinding ) ;
330
331
BindingOperations . SetBinding ( this . IntervalElementTransform , RotateTransform . CenterYProperty , radiusBinding ) ;
331
332
BindingOperations . SetBinding ( this . HourHandTransform , RotateTransform . CenterXProperty , radiusBinding ) ;
@@ -335,31 +336,26 @@ private void InitializeClockRotateTransforms()
335
336
BindingOperations . SetBinding ( this . SecondHandTransform , RotateTransform . CenterXProperty , radiusBinding ) ;
336
337
BindingOperations . SetBinding ( this . SecondHandTransform , RotateTransform . CenterYProperty , radiusBinding ) ;
337
338
}
338
-
339
- #region Overrides of FrameworkElement
340
-
341
- /// <inheritdoc />
342
- public override void OnApplyTemplate ( )
343
- {
344
- base . OnApplyTemplate ( ) ;
345
- var hostPanel = GetTemplateChild ( "PART_ElementHost" ) as FrameworkElement ;
346
-
347
- hostPanel . TryAssignValueToUnknownElement ( this . ClockFaceCanvas ) ;
348
- }
349
-
350
- #endregion
351
-
339
+
352
340
353
341
#region Overrides of FrameworkElement
354
342
355
343
/// <inheritdoc />
356
344
protected override Size MeasureOverride ( Size constraint )
357
345
{
358
- DrawAnalogClock ( ) ;
359
346
constraint = base . MeasureOverride ( constraint ) ;
347
+ DrawAnalogClock ( ) ;
360
348
return constraint ;
361
349
}
362
350
351
+ /// <inheritdoc />
352
+ protected override void OnRenderSizeChanged ( SizeChangedInfo sizeInfo )
353
+ {
354
+ base . OnRenderSizeChanged ( sizeInfo ) ;
355
+ this . Diameter = this . ActualWidth ;
356
+ this . Radius = this . Diameter / 2 ;
357
+ }
358
+
363
359
#endregion
364
360
365
361
@@ -628,7 +624,7 @@ protected virtual UIElement Create15MinuteIntervalLabel(int labelValue)
628
624
return label ;
629
625
}
630
626
631
- return new TextBlock { Text = formattedLabelValue . ToString ( ) } ;
627
+ return new TextBlock { Text = formattedLabelValue . ToString ( ) , Padding = new Thickness ( 0 ) } ;
632
628
}
633
629
634
630
protected virtual UIElement Create5MinuteIntervalLabel ( int labelValue )
@@ -640,7 +636,7 @@ protected virtual UIElement Create5MinuteIntervalLabel(int labelValue)
640
636
return label ;
641
637
}
642
638
643
- return new TextBlock { Text = formattedLabelValue . ToString ( ) } ;
639
+ return new TextBlock { Text = formattedLabelValue . ToString ( ) , Padding = new Thickness ( 0 ) } ;
644
640
}
645
641
646
642
protected virtual UIElement CreateMinuteIntervalLabel ( int labelValue )
@@ -652,7 +648,7 @@ protected virtual UIElement CreateMinuteIntervalLabel(int labelValue)
652
648
return label ;
653
649
}
654
650
655
- return new TextBlock { Text = formattedLabelValue . ToString ( ) } ;
651
+ return new TextBlock { Text = formattedLabelValue . ToString ( ) , Padding = new Thickness ( 0 ) } ;
656
652
}
657
653
658
654
protected virtual UIElement CloneElement ( UIElement elementToClone ) => elementToClone . CloneElement ( ) ;
@@ -691,12 +687,10 @@ protected virtual void DrawAnalogClock()
691
687
{
692
688
this . ClockFaceCanvas . Children . Clear ( ) ;
693
689
694
- if ( this . ActualWidth == 0 )
690
+ if ( this . Diameter == 0 )
695
691
{
696
692
return ;
697
693
}
698
-
699
- double radius = this . ActualWidth / 2 ;
700
694
double steps = 60.0 ;
701
695
double degreeOfStep = 360.0 / steps ;
702
696
double intervalMarkerCenterPositionRadius = - 1 ;
@@ -718,7 +712,7 @@ protected virtual void DrawAnalogClock()
718
712
if ( intervalMarkerCenterPositionRadius . Equals ( - 1 ) )
719
713
{
720
714
double radiusOffset = CalculateIntervalMarkerCenterRadiusOffset ( intervalMarker ) ;
721
- intervalMarkerCenterPositionRadius = radius + radiusOffset ;
715
+ intervalMarkerCenterPositionRadius = this . Radius + radiusOffset ;
722
716
}
723
717
724
718
var stepLabel = GetStepLabel ( step ) ;
@@ -735,7 +729,7 @@ protected virtual void DrawAnalogClock()
735
729
if ( ! this . Is15MinuteIntervalEnabled && intervalMarkerCenterPositionRadius . Equals ( - 1 ) )
736
730
{
737
731
double radiusOffset = CalculateIntervalMarkerCenterRadiusOffset ( intervalMarker ) ;
738
- intervalMarkerCenterPositionRadius = radius + radiusOffset ;
732
+ intervalMarkerCenterPositionRadius = this . Radius + radiusOffset ;
739
733
}
740
734
741
735
var stepLabel = GetStepLabel ( step ) ;
@@ -748,7 +742,7 @@ protected virtual void DrawAnalogClock()
748
742
if ( ! this . Is15MinuteIntervalEnabled && ! this . Is5MinuteIntervalEnabled && intervalMarkerCenterPositionRadius . Equals ( - 1 ) )
749
743
{
750
744
double radiusOffset = CalculateIntervalMarkerCenterRadiusOffset ( intervalMarker ) ;
751
- intervalMarkerCenterPositionRadius = radius + radiusOffset ;
745
+ intervalMarkerCenterPositionRadius = this . Radius + radiusOffset ;
752
746
}
753
747
754
748
if ( this . Is24HModeEnabled )
@@ -776,7 +770,7 @@ protected virtual void DrawAnalogClock()
776
770
}
777
771
778
772
Point cartesianPoint = GetCartesianPointOfStep ( degreesOfCurrentStep , intervalMarkerCenterPositionRadius ) ;
779
- if ( GetIsCenterElementOnCircumferenceEnabled ( intervalMarker ) )
773
+ if ( AnalogClockFace . GetIsCenterElementOnCircumferenceEnabled ( intervalMarker ) )
780
774
{
781
775
AlignElementCenterPointToRadius ( ref cartesianPoint , intervalMarker ) ;
782
776
}
@@ -791,14 +785,15 @@ protected virtual void DrawAnalogClock()
791
785
double labelRadiusOffset = - 24 ;
792
786
double intervalMarkerLabelCenterPositionRadius = intervalMarkerCenterPositionRadius + labelRadiusOffset ;
793
787
cartesianPoint = GetCartesianPointOfStep ( degreesOfCurrentStep , intervalMarkerLabelCenterPositionRadius ) ;
794
- AlignElementCenterPointToRadius ( ref cartesianPoint , intervalMarkerLabel ) ;
788
+ AlignElementCenterPointToRadius ( ref cartesianPoint , intervalMarkerLabel ) ;
789
+ cartesianPoint . Offset ( 0 , 4 ) ;
795
790
AddCartesianElementToClockFace ( intervalMarkerLabel , cartesianPoint ) ;
796
791
}
797
792
798
- double deltaToMiddleRadius = ( radius - intervalMarkerCenterPositionRadius ) * 2 ;
793
+ double deltaToMiddleRadius = ( this . Radius - intervalMarkerCenterPositionRadius ) * 2 ;
799
794
var clockFaceBackgroundPosition = new Point ( ) ;
800
795
clockFaceBackgroundPosition . Offset ( deltaToMiddleRadius / 2 , deltaToMiddleRadius / 2 ) ;
801
- AddElementToClockFace ( new Ellipse ( ) { Height = this . Height - deltaToMiddleRadius , Width = this . ActualWidth - deltaToMiddleRadius , Fill = Brushes . DarkRed } , clockFaceBackgroundPosition , 0 ) ;
796
+ AddElementToClockFace ( new Ellipse ( ) { Height = this . Diameter - deltaToMiddleRadius , Width = this . Diameter - deltaToMiddleRadius , Fill = Brushes . DarkRed } , clockFaceBackgroundPosition , 0 ) ;
802
797
803
798
AddClockHands ( ) ;
804
799
OnClockFaceLoaded ( ) ;
@@ -846,7 +841,7 @@ private double CalculateIntervalMarkerCenterRadiusOffset(UIElement intervalMarke
846
841
847
842
private Point GetCartesianPointOfStep ( double degreesOfCurrentStep , double radius )
848
843
{
849
- double axisOffset = this . ActualWidth / 2 ;
844
+ double axisOffset = this . Radius ;
850
845
// Rotate and invert degrees in order to move the 0 clock value to the top
851
846
// (instead of the original right -> cartesian based circle)
852
847
double rotatedDegrees = degreesOfCurrentStep - 90 ;
@@ -868,7 +863,7 @@ private Point GetCartesianPointOfStep(double degreesOfCurrentStep, double radius
868
863
869
864
public void AddCartesianElementToClockFace ( UIElement clockElement , Point cartesianPoint )
870
865
{
871
- Point screenPoint = ConvertCartesianPointToScreenPoint ( cartesianPoint , this . ActualWidth ) ;
866
+ Point screenPoint = ConvertCartesianPointToScreenPoint ( cartesianPoint , this . Diameter ) ;
872
867
AddElementToClockFace ( clockElement , screenPoint ) ;
873
868
}
874
869
0 commit comments