// (c) Copyright ESRI. // This source is subject to the Microsoft Public License (Ms-PL). // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. // All other rights reserved. using System.Windows; using System.Windows.Controls; namespace ESRI.ArcGIS.Client.Toolkit.Primitives { /// /// TickBar control used for placing a specified amount of tick marks evenly spread out. /// [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] public class TickBar : Panel { internal static readonly DependencyProperty PositionProperty = DependencyProperty.RegisterAttached("Position", typeof(double), typeof(Map), new PropertyMetadata(0.0)); private const string template = ""; private static DataTemplate DefaultTickMarkTemplate; /// /// Initializes a new instance of the class. /// public TickBar() { if (DefaultTickMarkTemplate == null) { #if SILVERLIGHT DefaultTickMarkTemplate = System.Windows.Markup.XamlReader.Load(template) as DataTemplate; #else System.IO.MemoryStream stream = new System.IO.MemoryStream( System.Text.UTF8Encoding.Default.GetBytes(template)); DefaultTickMarkTemplate = System.Windows.Markup.XamlReader.Load(stream) as DataTemplate; #endif } TickMarkTemplate = DefaultTickMarkTemplate; } /// /// Provides the behavior for the Arrange pass of Silverlight layout. /// Classes can override this method to define their own Arrange pass behavior. /// /// The final area within the parent that this /// object should use to arrange itself and its children. /// /// The actual size used once the element is arranged. /// protected override Size ArrangeOverride(Size finalSize) { if (TickMarkPositions == null || TickMarkPositions.Length < 2) return finalSize; Rect childBounds = new Rect(0, 0, finalSize.Width, finalSize.Height); foreach (UIElement child in Children) { FrameworkElement c = (child as FrameworkElement); if (c == null) continue; double position = (double)c.GetValue(PositionProperty); if (Orientation == Orientation.Horizontal) { position = finalSize.Width * position; childBounds.X = position - c.DesiredSize.Width * .5; childBounds.Width = c.DesiredSize.Width; } else { position = finalSize.Height * position; childBounds.Y = position - c.DesiredSize.Height * .5; childBounds.Height = c.DesiredSize.Height; } child.Arrange(childBounds); } return finalSize; } /// /// Provides the behavior for the Measure pass of Silverlight layout. /// Classes can override this method to define their own Measure pass behavior. /// /// The available size that this object /// can give to child objects. Infinity can be specified as a value /// to indicate that the object will size to whatever content is available. /// /// The size that this object determines it needs during layout, /// based on its calculations of child object allotted sizes. /// protected override Size MeasureOverride(Size availableSize) { double width = availableSize.Width == double.PositiveInfinity ? this.Width : availableSize.Width; double height = availableSize.Height == double.PositiveInfinity ? this.Height : availableSize.Height; foreach (UIElement d in this.Children) { d.Measure(availableSize); } if (double.IsNaN(height)) { height = 0; if (this.Orientation == System.Windows.Controls.Orientation.Horizontal) { foreach (UIElement d in this.Children) { height = System.Math.Max(d.DesiredSize.Height, height); } } } if (double.IsNaN(width)) { width = 0; if(this.Orientation == System.Windows.Controls.Orientation.Vertical) { foreach (UIElement d in this.Children) { width = System.Math.Max(d.DesiredSize.Width, width); } } } return new Size(width, height); } /// /// Gets or sets the tick mark positions. /// /// The tick mark positions. public double[] TickMarkPositions { get { return (double[])GetValue(TickMarkPositionsProperty); } set { SetValue(TickMarkPositionsProperty, value); } } /// /// Identifies the dependency property. /// public static readonly DependencyProperty TickMarkPositionsProperty = DependencyProperty.Register("TickMarkPositions", typeof(double[]), typeof(TickBar), new PropertyMetadata( OnTickMarkPositionsPropertyChanged)); private static void OnTickMarkPositionsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TickBar bar = (TickBar)d; double[] newValue = (double[])e.NewValue; double[] oldValue = (double[])e.OldValue; int now = newValue == null ? 0 : newValue.Length; int before = oldValue == null ? 0 : oldValue.Length; if (now < before) { while (bar.Children.Count > now) bar.Children.RemoveAt(bar.Children.Count - 1); } else if(newValue != null) { for (int i = before; i < now; i++) { bar.AddTickmark(newValue[i]); } } bar.InvalidateMeasure(); bar.InvalidateArrange(); } private void AddTickmark(double position) { ContentPresenter c = new ContentPresenter(); c.SetValue(PositionProperty, position); c.SetBinding(ContentPresenter.ContentTemplateProperty, new System.Windows.Data.Binding() { Source = this, BindsDirectlyToSource = true, Path = new PropertyPath("TickMarkTemplate") }); Children.Add(c); } /// /// Gets or sets the item template for each tick mark. /// /// The item template. public DataTemplate TickMarkTemplate { get { return (DataTemplate)GetValue(TickMarkTemplateProperty); } set { SetValue(TickMarkTemplateProperty, value); } } /// /// Identifies the dependency property. /// public static readonly DependencyProperty TickMarkTemplateProperty = DependencyProperty.Register("TickMarkTemplate", typeof(DataTemplate), typeof(TickBar), null); /// /// Gets or sets the orientation. /// /// The orientation. public Orientation Orientation { get { return (Orientation)GetValue(OrientationProperty); } set { SetValue(OrientationProperty, value); } } /// /// Identifies the dependency property. /// public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(TickBar), new PropertyMetadata(Orientation.Horizontal, OnOrientationPropertyChanged)); private static void OnOrientationPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TickBar bar = (TickBar)d; bar.InvalidateMeasure(); bar.InvalidateArrange(); } } }