/Main/src/DynamicDataDisplay/Charts/Axes/StackCanvas.cs
C# | 237 lines | 199 code | 36 blank | 2 comment | 33 complexity | 527dc53f9e38897aacccf9efabc881c5 MD5 | raw file
Possible License(s): CC-BY-SA-3.0
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Text; 5using System.Windows.Controls; 6using System.Windows; 7using System.Windows.Media; 8using System.Diagnostics; 9using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary; 10 11namespace Microsoft.Research.DynamicDataDisplay.Charts 12{ 13 public class StackCanvas : Panel 14 { 15 public StackCanvas() 16 { 17 } 18 19 #region EndCoordinate attached property 20 21 [AttachedPropertyBrowsableForChildren] 22 public static double GetEndCoordinate(DependencyObject obj) 23 { 24 return (double)obj.GetValue(EndCoordinateProperty); 25 } 26 27 public static void SetEndCoordinate(DependencyObject obj, double value) 28 { 29 obj.SetValue(EndCoordinateProperty, value); 30 } 31 32 public static readonly DependencyProperty EndCoordinateProperty = DependencyProperty.RegisterAttached( 33 "EndCoordinate", 34 typeof(double), 35 typeof(StackCanvas), 36 new PropertyMetadata(Double.NaN, OnCoordinateChanged)); 37 38 #endregion 39 40 #region Coordinate attached property 41 42 [AttachedPropertyBrowsableForChildren] 43 public static double GetCoordinate(DependencyObject obj) 44 { 45 return (double)obj.GetValue(CoordinateProperty); 46 } 47 48 public static void SetCoordinate(DependencyObject obj, double value) 49 { 50 obj.SetValue(CoordinateProperty, value); 51 } 52 53 public static readonly DependencyProperty CoordinateProperty = DependencyProperty.RegisterAttached( 54 "Coordinate", 55 typeof(double), 56 typeof(StackCanvas), 57 new PropertyMetadata(0.0, OnCoordinateChanged)); 58 59 private static void OnCoordinateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 60 { 61 UIElement reference = d as UIElement; 62 if (reference != null) 63 { 64 StackCanvas parent = VisualTreeHelper.GetParent(reference) as StackCanvas; 65 if (parent != null) 66 { 67 parent.InvalidateArrange(); 68 } 69 } 70 } 71 #endregion 72 73 #region AxisPlacement property 74 75 public AxisPlacement Placement 76 { 77 get { return (AxisPlacement)GetValue(PlacementProperty); } 78 set { SetValue(PlacementProperty, value); } 79 } 80 81 public static readonly DependencyProperty PlacementProperty = 82 DependencyProperty.Register( 83 "Placement", 84 typeof(AxisPlacement), 85 typeof(StackCanvas), 86 new FrameworkPropertyMetadata( 87 AxisPlacement.Bottom, 88 FrameworkPropertyMetadataOptions.AffectsArrange)); 89 90 #endregion 91 92 private bool IsHorizontal 93 { 94 get { return Placement == AxisPlacement.Top || Placement == AxisPlacement.Bottom; } 95 } 96 97 protected override Size MeasureOverride(Size constraint) 98 { 99 Size availableSize = constraint; 100 Size size = new Size(); 101 102 bool isHorizontal = IsHorizontal; 103 104 if (isHorizontal) 105 { 106 availableSize.Width = Double.PositiveInfinity; 107 size.Width = constraint.Width; 108 } 109 else 110 { 111 availableSize.Height = Double.PositiveInfinity; 112 size.Height = constraint.Height; 113 } 114 115 // measuring all children and determining self width and height 116 foreach (UIElement element in base.Children) 117 { 118 if (element != null) 119 { 120 Size childSize = GetChildSize(element, availableSize); 121 element.Measure(childSize); 122 Size desiredSize = element.DesiredSize; 123 124 if (isHorizontal) 125 { 126 size.Height = Math.Max(size.Height, desiredSize.Height); 127 } 128 else 129 { 130 size.Width = Math.Max(size.Width, desiredSize.Width); 131 } 132 } 133 } 134 135 if (Double.IsPositiveInfinity(size.Width)) size.Width = 0; 136 if (Double.IsPositiveInfinity(size.Height)) size.Height = 0; 137 138 return size; 139 } 140 141 private Size GetChildSize(UIElement element, Size availableSize) 142 { 143 var coordinate = GetCoordinate(element); 144 var endCoordinate = GetEndCoordinate(element); 145 146 if (coordinate.IsNotNaN() && endCoordinate.IsNotNaN()) 147 { 148 if (Placement.IsBottomOrTop()) 149 { 150 availableSize.Width = Math.Abs(endCoordinate - coordinate); 151 } 152 else 153 { 154 availableSize.Height = Math.Abs(endCoordinate - coordinate); 155 } 156 } 157 158 return availableSize; 159 } 160 161 protected override Size ArrangeOverride(Size finalSize) 162 { 163 bool isHorizontal = IsHorizontal; 164 165 foreach (FrameworkElement element in base.Children) 166 { 167 if (element == null) 168 { 169 continue; 170 } 171 172 Size elementSize = element.DesiredSize; 173 double x = 0.0; 174 double y = 0.0; 175 176 switch (Placement) 177 { 178 case AxisPlacement.Left: 179 x = finalSize.Width - elementSize.Width; 180 break; 181 case AxisPlacement.Right: 182 x = 0; 183 break; 184 case AxisPlacement.Top: 185 y = finalSize.Height - elementSize.Height; 186 break; 187 case AxisPlacement.Bottom: 188 y = 0; 189 break; 190 default: 191 break; 192 } 193 194 double coordinate = GetCoordinate(element); 195 196 if (!Double.IsNaN(GetEndCoordinate(element))) 197 { 198 double endCoordinate = GetEndCoordinate(element); 199 double size = endCoordinate - coordinate; 200 if (size < 0) 201 { 202 size = -size; 203 coordinate -= size; 204 } 205 if (isHorizontal) 206 elementSize.Width = size; 207 else 208 elementSize.Height = size; 209 } 210 211 212 // shift for common tick labels, not for major ones. 213 if (isHorizontal) 214 { 215 x = coordinate; 216 if (element.HorizontalAlignment == HorizontalAlignment.Center) 217 x = coordinate - elementSize.Width / 2; 218 } 219 else 220 { 221 y = coordinate; 222 if (element.VerticalAlignment == VerticalAlignment.Center) 223 y = coordinate - elementSize.Height / 2; 224 else if (element.VerticalAlignment == VerticalAlignment.Bottom) 225 y = coordinate - elementSize.Height; 226 else if (element.VerticalAlignment == VerticalAlignment.Top) 227 y = coordinate; 228 } 229 230 Rect bounds = new Rect(new Point(x, y), elementSize); 231 element.Arrange(bounds); 232 } 233 234 return finalSize; 235 } 236 } 237}