PageRenderTime 47ms CodeModel.GetById 14ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/V4/ChartControls/ContinuousAxisPanel.cs

#
C# | 687 lines | 561 code | 74 blank | 52 comment | 115 complexity | fc2fa078c379bc3eac00a5a0b195b268 MD5 | raw file
  1//===================================================================================
  2// Microsoft patterns & practices
  3// Composite Application Guidance for Windows Presentation Foundation and Silverlight
  4//===================================================================================
  5// Copyright (c) Microsoft Corporation.  All rights reserved.
  6// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
  7// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
  8// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  9// FITNESS FOR A PARTICULAR PURPOSE.
 10//===================================================================================
 11// The example companies, organizations, products, domain names,
 12// e-mail addresses, logos, people, places, and events depicted
 13// herein are fictitious.  No association with any real company,
 14// organization, product, domain name, email address, logo, person,
 15// places, or events is intended or should be inferred.
 16//===================================================================================
 17using System.Windows.Controls;
 18using System.Windows;
 19using System.Windows.Media;
 20using System.Collections.ObjectModel;
 21using System;
 22using System.Windows.Data;
 23using System.Collections;
 24using System.ComponentModel;
 25using System.Collections.Specialized;
 26
 27namespace StockTraderRI.ChartControls
 28{
 29    public class ContinuousAxisPanel : Panel
 30    {
 31        public ContinuousAxisPanel()
 32        {
 33            _largestLabelSize = new Size();
 34            SetValue(ItemsSourceKey, new ObservableCollection<String>());
 35            YValues = new ObservableCollection<double>();
 36            SetValue(TickPositionsKey, new ObservableCollection<double>());
 37        }
 38
 39        protected override void OnInitialized(EventArgs e)
 40        {
 41            base.OnInitialized(e);
 42
 43            _parentControl = ((ContinuousAxis)((FrameworkElement)VisualTreeHelper.GetParent(this)).TemplatedParent);
 44
 45            if (_parentControl != null)
 46            {
 47                Binding valueBinding = new Binding();
 48                valueBinding.Source = _parentControl;
 49                valueBinding.Path = new PropertyPath(ContinuousAxis.SourceValuesProperty);
 50                this.SetBinding(ContinuousAxisPanel.DataValuesProperty, valueBinding);
 51
 52                Binding itemsBinding = new Binding();
 53                itemsBinding.Source = this;
 54                itemsBinding.Path = new PropertyPath(ContinuousAxisPanel.ItemsSourceProperty);
 55                _parentControl.SetBinding(ContinuousAxis.ItemsSourceProperty, itemsBinding);
 56
 57                Binding refLineBinding = new Binding();
 58                refLineBinding.Source = _parentControl;
 59                refLineBinding.Path = new PropertyPath(ContinuousAxis.ReferenceLineSeperationProperty);
 60                this.SetBinding(ContinuousAxisPanel.ReferenceLineSeperationProperty, refLineBinding);
 61
 62                Binding outputBinding = new Binding();
 63                outputBinding.Source = this;
 64                outputBinding.Path = new PropertyPath(ContinuousAxisPanel.YValuesProperty);
 65                _parentControl.SetBinding(ContinuousAxis.ValuesProperty, outputBinding);
 66
 67                Binding tickPositionBinding = new Binding();
 68                tickPositionBinding.Source = this;
 69                tickPositionBinding.Path = new PropertyPath(ContinuousAxisPanel.TickPositionsProperty);
 70                _parentControl.SetBinding(ContinuousAxis.TickPositionsProperty, tickPositionBinding);
 71
 72                Binding zerobinding = new Binding();
 73                zerobinding.Source = this;
 74                zerobinding.Path = new PropertyPath(ContinuousAxisPanel.OriginProperty);
 75                _parentControl.SetBinding(ContinuousAxis.OriginProperty, zerobinding);
 76            }
 77        }
 78
 79        public static void OnDataValuesChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
 80        {
 81            ContinuousAxisPanel p = sender as ContinuousAxisPanel;
 82            if (p != null && p.DataValues != null)
 83            {
 84                ((INotifyCollectionChanged)p.DataValues).CollectionChanged += new NotifyCollectionChangedEventHandler(p.Axis2Panel_CollectionChanged);
 85                p.GenerateItemsSource();
 86            }
 87        }
 88
 89        public void Axis2Panel_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
 90        {
 91            GenerateItemsSource();
 92        }
 93
 94        private void GenerateItemsSource()
 95        {
 96            if (DataValues==null || DataValues.Count==0)
 97            {
 98                return;
 99            }
100            CalculateValueIncrement(_arrangeSize);
101            
102            ObservableCollection<String> tempItemsSource = ItemsSource;
103            tempItemsSource.Clear();
104            int referenceLinesCreated = 0;
105            while (referenceLinesCreated != _numReferenceLines)
106            {
107                if (Orientation.Equals(Orientation.Vertical))
108                    tempItemsSource.Add(((double)(_startingIncrement + referenceLinesCreated * _valueIncrement)).ToString());
109                else
110                    tempItemsSource.Add(((double)(_startingIncrement + (_numReferenceLines - 1 - referenceLinesCreated) * _valueIncrement)).ToString());
111                referenceLinesCreated++;
112            }
113            _highValue = _startingIncrement + (_numReferenceLines - 1) * _valueIncrement;
114            _lowValue = _startingIncrement;
115        }
116
117        protected override Size MeasureOverride(Size availableSize)
118        {
119            _largestLabelSize.Height = 0.0;
120            _largestLabelSize.Width = 0.0;
121            UIElementCollection tempInternalChildren = InternalChildren;
122            for (int i = 0; i < tempInternalChildren.Count; i++)
123            {
124                tempInternalChildren[i].Measure(availableSize);
125                _largestLabelSize.Height = _largestLabelSize.Height > tempInternalChildren[i].DesiredSize.Height
126                    ? _largestLabelSize.Height : tempInternalChildren[i].DesiredSize.Height;
127                _largestLabelSize.Width = _largestLabelSize.Width > tempInternalChildren[i].DesiredSize.Width
128                    ? _largestLabelSize.Width : tempInternalChildren[i].DesiredSize.Width;
129            }
130            if (Orientation.Equals(Orientation.Vertical))
131            {
132                double fitAllLabelSize = _largestLabelSize.Height * InternalChildren.Count;
133                availableSize.Height = fitAllLabelSize < availableSize.Height ? fitAllLabelSize : availableSize.Height;
134                availableSize.Width = _largestLabelSize.Width;
135            }
136            else
137            {
138                double fitAllLabelsSize = _largestLabelSize.Width * InternalChildren.Count;
139                availableSize.Width = fitAllLabelsSize < availableSize.Width ? fitAllLabelsSize : availableSize.Width;
140                availableSize.Height = _largestLabelSize.Height;
141            }
142            return availableSize;
143        }
144
145        protected override Size ArrangeOverride(Size finalSize)
146        {
147            if (!_arrangeSize.Equals(finalSize))
148            {
149                _arrangeSize = finalSize;
150                GenerateItemsSource();
151            }
152            _arrangeSize = finalSize;
153            if (InternalChildren.Count > 0)
154            {
155                if (Orientation.Equals(Orientation.Vertical))
156                {
157                    ArrangeVerticalLabels(finalSize);
158                    CalculateYOutputValues(finalSize);
159                }
160                else
161                {
162                    ArrangeHorizontalLabels(finalSize);
163                    CalculateXOutputValues(finalSize);
164                }
165
166            }
167            return base.ArrangeOverride(finalSize);
168        }
169
170        private void ArrangeHorizontalLabels(Size constraint)
171        {
172            double rectWidth = _largestLabelSize.Width;
173            double rectHeight = _largestLabelSize.Height;
174            double increments = CalculatePixelIncrements(constraint, _largestLabelSize);
175            double start_width = constraint.Width - _largestLabelSize.Width / 2;
176            double end_width = start_width - (InternalChildren.Count - 1) * increments;
177            ObservableCollection<double> tempTickPositions = TickPositions;
178
179            if (start_width > end_width)
180            {
181                tempTickPositions.Clear();
182                Rect r = new Rect(start_width - rectWidth / 2, 0, rectWidth, rectHeight);
183                InternalChildren[0].Arrange(r);
184                tempTickPositions.Add(start_width);
185                int count = InternalChildren.Count - 1;
186                r = new Rect(start_width - count * increments - rectWidth / 2, 0, rectWidth, rectHeight);
187                InternalChildren[count].Arrange(r);
188                tempTickPositions.Add(start_width - count * increments);
189
190                if (constraint.Width > 3 * rectWidth)
191                {
192                    _skipFactor = (int)Math.Ceiling((InternalChildren.Count - 2) / Math.Floor((constraint.Width - 2 * rectWidth) / rectWidth));
193                    if ((InternalChildren.Count - 2) != 2.0)
194                        _skipFactor = Math.Min(_skipFactor, (int)Math.Ceiling((double)(InternalChildren.Count - 2.0) / 2.0));
195                    _canDisplayAllLabels = true;
196                    if (_skipFactor > 1)
197                    {
198                        _canDisplayAllLabels = false;
199                    }
200
201                    for (int i = 2; i <= InternalChildren.Count - 1; i++)
202                    {
203                        tempTickPositions.Add(start_width - (i - 1) * increments);
204                        if (_canDisplayAllLabels || (i + 1) % _skipFactor == 0)
205                        {
206                            r = new Rect(start_width - (i - 1) * increments - rectWidth / 2, 0, rectWidth, rectHeight);
207                            InternalChildren[i-1].Arrange(r);
208                        }
209                        else
210                        {
211                            InternalChildren[i-1].Arrange(new Rect(0, 0, 0, 0));
212                        }
213                    }
214                }
215            }
216        }
217
218        private void ArrangeVerticalLabels(Size constraint)
219        {
220            double rectWidth = _largestLabelSize.Width;
221            double rectHeight = _largestLabelSize.Height;
222            double increments = CalculatePixelIncrements(constraint, _largestLabelSize);
223            double start_height = constraint.Height - _largestLabelSize.Height / 2;
224            double end_height = start_height - (InternalChildren.Count - 1) * increments;
225            ObservableCollection<double> tempTickPositions = TickPositions;
226
227            if(start_height > end_height)
228            {
229                tempTickPositions.Clear();
230                Rect r = new Rect(constraint.Width - rectWidth, (start_height - rectHeight / 2), rectWidth, rectHeight);
231                InternalChildren[0].Arrange(r);
232                tempTickPositions.Add(start_height);
233                int count = InternalChildren.Count-1;
234                r = new Rect(constraint.Width - rectWidth, (start_height - count*increments - rectHeight / 2), rectWidth, rectHeight);
235                InternalChildren[count].Arrange(r);
236                tempTickPositions.Add(start_height - count * increments);
237
238                if (constraint.Height > 3 * rectHeight)
239                {
240                    _skipFactor = (int)Math.Ceiling((InternalChildren.Count - 2) / Math.Floor((constraint.Height - 2 * rectHeight) / rectHeight));
241                    if ((InternalChildren.Count - 2) != 2.0)
242                        _skipFactor = Math.Min(_skipFactor, (int)Math.Ceiling((double)(InternalChildren.Count - 2.0) / 2.0));
243                    _canDisplayAllLabels = true;
244                    if (_skipFactor > 1)
245                    {
246                        _canDisplayAllLabels = false;
247                    }
248                    
249                    for (int i = 2; i <= InternalChildren.Count-1; i++)
250                    {
251                        tempTickPositions.Add(start_height - (i - 1) * increments);
252                        if (_canDisplayAllLabels || (i + 1) % _skipFactor == 0 )
253                        {
254                            r = new Rect(constraint.Width - rectWidth, (start_height - (i - 1) * increments - rectHeight / 2), rectWidth, rectHeight);
255                            InternalChildren[i - 1].Arrange(r);
256                        }
257                        else
258                        {
259                            InternalChildren[i - 1].Arrange(new Rect(0, 0, 0, 0));
260                        }
261                    }
262                }
263            }
264        }
265
266        private void CalculateYOutputValues(Size constraint)
267        {
268            YValues.Clear();
269            double start_val, lowPixel, highPixel;
270            double pixelIncrement = CalculatePixelIncrements(constraint, _largestLabelSize);
271            if (Orientation.Equals(Orientation.Vertical))
272            {
273                start_val = constraint.Height - _largestLabelSize.Height / 2;
274                lowPixel = start_val - (InternalChildren.Count - 1) * pixelIncrement;
275                highPixel = start_val;
276            }
277            else
278            {
279                start_val = constraint.Width - _largestLabelSize.Width / 2;
280                lowPixel = start_val - (InternalChildren.Count - 1) * pixelIncrement;
281                highPixel = start_val;
282            }
283            if (highPixel < lowPixel)
284                return;
285            for (int i = 0; i < DataValues.Count; i++)
286            {
287                double outVal = highPixel - ((highPixel - lowPixel) / (_highValue - _lowValue)) * (DataValues[i] - _lowValue);
288                YValues.Add(outVal);
289            }
290            if (_startsAtZero || (!_allNegativeValues && !_allPositiveValues))
291                Origin = highPixel - ((highPixel - lowPixel) / (_highValue - _lowValue)) * (0.0 - _lowValue);
292            else if (!_startsAtZero && _allPositiveValues)
293                Origin = highPixel;
294            else
295                Origin = lowPixel;
296        }
297
298        private void CalculateXOutputValues(Size constraint)
299        {
300            YValues.Clear();
301            double start_width = constraint.Width - _largestLabelSize.Width / 2;
302            double pixelIncrement = CalculatePixelIncrements(constraint, _largestLabelSize);
303            double lowPixel = start_width - (InternalChildren.Count - 1) * pixelIncrement;
304            double highPixel = start_width;
305            if (highPixel < lowPixel)
306                return;
307            for (int i = 0; i < DataValues.Count; i++)
308            {
309                double output = lowPixel + ((highPixel - lowPixel) / (_highValue - _lowValue)) * (DataValues[i] - _lowValue);
310                YValues.Add(output);
311            }
312            if (_startsAtZero || (!_allNegativeValues && !_allPositiveValues))
313                Origin = lowPixel + ((highPixel - lowPixel) / (_highValue - _lowValue)) * (0.0 - _lowValue);
314            else if (!_startsAtZero && _allPositiveValues)
315                Origin = lowPixel;
316            else
317                Origin = highPixel;
318        }
319
320        /// <summary>
321        /// Calculate the pixel distance between each tick mark on the vertical axis
322        /// </summary>
323        /// <param name="constraint"></param>
324        /// <returns></returns>
325        private double CalculatePixelIncrements(Size constraint, Size labelSize)
326        {
327            if(Orientation.Equals(Orientation.Vertical))
328                return (constraint.Height - _largestLabelSize.Height) / (_numReferenceLines - 1);
329            else
330                return (constraint.Width - _largestLabelSize.Width) / (_numReferenceLines - 1);
331        }
332
333        private double CalculateValueIncrement(Size size)
334        {
335            // Determine if the starting value is 0 or not
336            bool startsAtZero = false;
337            bool allPositiveValues = true;
338            bool allNegativeValues = true;
339            double increment_value = 0;
340            int multiplier = 1;
341            if (DataValues.Count == 0)
342                return 0.0;
343            //double low = ((DoubleHolder)DataValues[0]).DoubleValue;
344            //double high = ((DoubleHolder)DataValues[0]).DoubleValue;
345
346            double low = DataValues[0];
347            double high = DataValues[0];
348
349            for (int i = 0; i < DataValues.Count; i++)
350            {
351                //double temp = ((DoubleHolder)DataValues[i]).DoubleValue;
352                double temp = DataValues[i];
353
354                // Check for positive and negative values
355                if (temp > 0)
356                {
357                    allNegativeValues = false;
358                }
359                else if (temp < 0)
360                {
361                    allPositiveValues = false;
362                }
363
364                // Reset low and high if necessary
365                if (temp < low)
366                {
367                    low = temp;
368                }
369                else if (temp > high)
370                {
371                    high = temp;
372                }
373            }
374
375            // Determine whether or not the increments will start at zero
376            if (allPositiveValues && (low < (high / 2)) ||
377                (allNegativeValues && high > (low / 2)))
378            {
379                _startsAtZero = true;
380                startsAtZero = true;
381            }
382
383            // If all values in dataset are 0, draw one reference line and label it 0
384            if (high == 0 && low == 0)
385            {
386                _valueIncrement = 0;
387                _startingIncrement = 0;
388                _numReferenceLines = 1;
389                _startsAtZero = startsAtZero;
390                return increment_value;
391            }
392
393            // Find an increment value that is in the set {1*10^x, 2*10^x, 5*10^x, where x is an integer 
394            //  (positive, negative, or zero)}
395
396            if (!allNegativeValues)
397            {
398                if (startsAtZero)
399                {
400                    int exp = 0;
401                    while (true)
402                    {
403                        multiplier = IsWithinRange(high, exp, size);
404                        if (multiplier != -1)
405                        {
406                            break;
407                        }
408                        multiplier = IsWithinRange(high, (-1 * exp), size);
409                        if (multiplier != -1)
410                        {
411                            exp = -1 * exp;
412                            break;
413                        }
414                        exp++;
415                    }
416                    increment_value = multiplier * Math.Pow(10, exp);
417                }
418                else
419                {
420                    int exp = 0;
421                    while (true)
422                    {
423                        multiplier = IsWithinRange((high - low), exp, size);
424                        if (multiplier != -1)
425                        {
426                            break;
427                        }
428                        multiplier = IsWithinRange((high - low), (-1 * exp), size);
429                        if (multiplier != -1)
430                        {
431                            exp = -1 * exp;
432                            break;
433                        }
434                        if (high == low)
435                        {
436                            increment_value = high;
437                            _valueIncrement = increment_value;
438                            _numReferenceLines = 1;
439                            break;
440                        }
441
442                        exp++;
443                    }
444                    if (increment_value == 0)
445                    {
446                        increment_value = multiplier * Math.Pow(10, exp);
447                    }
448                }
449            }
450            else
451            {
452                if (startsAtZero)
453                {
454                    int exp = 0;
455                    while (true)
456                    {
457                        multiplier = IsWithinRange(low, exp, size);
458                        if (multiplier != -1)
459                        {
460                            break;
461                        }
462                        multiplier = IsWithinRange(low, (-1 * exp), size);
463                        if (multiplier != -1)
464                        {
465                            exp = -1 * exp;
466                            break;
467                        }
468                        exp++;
469                    }
470                    increment_value = multiplier * Math.Pow(10, exp);
471                }
472                else
473                {
474                    int exp = 0;
475                    if (low - high == 0.0)
476                        increment_value = 1.0;
477                    else
478                    {
479                        while (true)
480                        {
481                            multiplier = IsWithinRange((low - high), exp, size);
482                            if (multiplier != -1)
483                            {
484                                break;
485                            }
486                            multiplier = IsWithinRange((low - high), (-1 * exp), size);
487                            if (multiplier != -1)
488                            {
489                                exp = -1 * exp;
490                                break;
491                            }
492                            exp++;
493                        }
494                        increment_value = multiplier * Math.Pow(10, exp);
495                    }
496                }
497            }
498
499
500
501            double starting_value = 0;
502
503            // Determine starting value if it is nonzero
504            if (!startsAtZero)
505            {
506                if (allPositiveValues)
507                {
508                    if (low % increment_value == 0)
509                    {
510                        starting_value = low;
511                    }
512                    else
513                    {
514                        starting_value = (int)(low / increment_value) * increment_value;
515                    }
516                }
517                else
518                {
519                    if (low % increment_value == 0)
520                    {
521                        starting_value = low;
522                    }
523                    else
524                    {
525                        starting_value = (int)((low - increment_value) / increment_value) * increment_value;
526                    }
527                }
528            }
529            else if (startsAtZero && allNegativeValues)
530            {
531                if (low % increment_value == 0)
532                {
533                    starting_value = low;
534                }
535                else
536                {
537                    starting_value = (int)((low - increment_value) / increment_value) * increment_value;
538                }
539            }
540
541            // Determine the number of reference lines
542            //int numRefLines = 0;
543            int numRefLines = (int)Math.Ceiling((high - starting_value) / increment_value) + 1;
544
545            _valueIncrement = increment_value;
546            _startingIncrement = starting_value;
547            _numReferenceLines = numRefLines;
548            _startsAtZero = startsAtZero;
549            _allPositiveValues = allPositiveValues;
550            _allNegativeValues = allNegativeValues;
551            return increment_value;
552        }
553
554        /// <summary>
555        /// Checks to see if the calculated increment value is between the low and high passed in, 
556        /// then returns the multiplier used
557        /// </summary>
558        /// <param name="numerator"></param>
559        /// <param name="exponent"></param>
560        /// <param name="lowRange"></param>
561        /// <param name="highRange"></param>
562        /// <returns></returns>
563        private int IsWithinRange(double numerator, int exponent, Size size)
564        {
565            int highRange, lowRange;
566           // highRange = (int)Math.Min(10, (int)(size.Height / labelSize.Height)) -2;
567            if(Orientation.Equals(Orientation.Vertical))
568                highRange = (int)(size.Height / ReferenceLineSeperation);
569            else
570                highRange = (int)(size.Width / ReferenceLineSeperation);
571
572            lowRange = 1;
573            highRange = (int)Math.Max(highRange, 3);
574            
575            if ((Math.Abs(numerator) / (1 * Math.Pow(10, exponent))) >= lowRange && (Math.Abs(numerator) / (1 * Math.Pow(10, exponent))) <= highRange)
576            {
577                return 1;
578            }
579            if ((Math.Abs(numerator) / (2 * Math.Pow(10, exponent))) >= lowRange && (Math.Abs(numerator) / (2 * Math.Pow(10, exponent))) <= highRange)
580            {
581                return 2;
582            }
583            if ((Math.Abs(numerator) / (5 * Math.Pow(10, exponent))) >= lowRange && (Math.Abs(numerator) / (5 * Math.Pow(10, exponent))) <= highRange)
584            {
585                return 5;
586            }
587            return -1;
588        }
589
590
591        public ObservableCollection<double> YValues
592        {
593            get { return (ObservableCollection<double>)GetValue(YValuesProperty); }
594            set { SetValue(YValuesProperty, value); }
595        }
596
597        // Using a DependencyProperty as the backing store for YValues.  This enables animation, styling, binding, etc...
598        public static readonly DependencyProperty YValuesProperty =
599            DependencyProperty.Register("YValues", typeof(ObservableCollection<double>), typeof(ContinuousAxisPanel), new UIPropertyMetadata(null));
600
601
602
603        public ObservableCollection<String> ItemsSource
604        {
605            get { return (ObservableCollection<String>)GetValue(ItemsSourceProperty); }
606        }
607
608        // Using a DependencyProperty as the backing store for Axis2Panel.  This enables animation, styling, binding, etc...
609        private static readonly DependencyPropertyKey ItemsSourceKey =
610            DependencyProperty.RegisterReadOnly("ItemsSource", typeof(ObservableCollection<String>), typeof(ContinuousAxisPanel), new UIPropertyMetadata());
611
612        public static readonly DependencyProperty ItemsSourceProperty = ItemsSourceKey.DependencyProperty;
613        
614
615        private ObservableCollection<double> DataValues
616        {
617            get { return (ObservableCollection<double>)GetValue(DataValuesProperty); }
618            set { SetValue(DataValuesProperty, value); }
619        }
620
621        // Using a DependencyProperty as the backing store for DataValues.  This enables animation, styling, binding, etc...
622        private static readonly DependencyProperty DataValuesProperty =
623            DependencyProperty.Register("DataValues", typeof(ObservableCollection<double>), typeof(ContinuousAxisPanel), new FrameworkPropertyMetadata(OnDataValuesChanged));
624
625
626        public ObservableCollection<double> TickPositions
627        {
628            get { return (ObservableCollection<double>)GetValue(TickPositionsProperty); }
629            //set { SetValue(TickPositionsProperty, value); }
630        }
631
632        // Using a DependencyProperty as the backing store for TickPositions.  This enables animation, styling, binding, etc...
633        private static readonly DependencyPropertyKey TickPositionsKey =
634            DependencyProperty.RegisterReadOnly("TickPositions", typeof(ObservableCollection<double>), typeof(ContinuousAxisPanel), new UIPropertyMetadata(null));
635
636        public static readonly DependencyProperty TickPositionsProperty = TickPositionsKey.DependencyProperty;
637
638        public double Origin
639        {
640            get { return (double)GetValue(OriginProperty); }
641            set { SetValue(OriginProperty, value); }
642        }
643
644        // Using a DependencyProperty as the backing store for ZeroReferenceLinePosition.  This enables animation, styling, binding, etc...
645        public static readonly DependencyProperty OriginProperty =
646            DependencyProperty.Register("Origin", typeof(double), typeof(ContinuousAxisPanel), new UIPropertyMetadata(0.0));
647
648
649        public Orientation Orientation
650        {
651            get { return (Orientation)GetValue(OrientationProperty); }
652            set { SetValue(OrientationProperty, value); }
653        }
654
655        // Using a DependencyProperty as the backing store for Orientation.  This enables animation, styling, binding, etc...
656        public static readonly DependencyProperty OrientationProperty =
657            DependencyProperty.Register("Orientation", typeof(Orientation), typeof(ContinuousAxisPanel), new UIPropertyMetadata(Orientation.Vertical));
658
659
660
661
662        public double ReferenceLineSeperation
663        {
664            get { return (double)GetValue(ReferenceLineSeperationProperty); }
665            set { SetValue(ReferenceLineSeperationProperty, value); }
666        }
667
668        // Using a DependencyProperty as the backing store for ReferenceLineSeperation.  This enables animation, styling, binding, etc...
669        public static readonly DependencyProperty ReferenceLineSeperationProperty =
670            DependencyProperty.Register("ReferenceLineSeperation", typeof(double), typeof(ContinuousAxisPanel), new UIPropertyMetadata(null));
671
672
673
674        private Size _largestLabelSize;
675        private bool _canDisplayAllLabels;
676        private int _skipFactor;
677        private double _lowValue, _highValue;
678        private Size _arrangeSize;
679        public ItemsControl _parentControl;
680        private bool _startsAtZero;
681        private double _startingIncrement;
682        private double _valueIncrement;
683        private int _numReferenceLines;
684        private bool _allPositiveValues;
685        private bool _allNegativeValues;
686    }
687}