@ -0,0 +1,191 @@ |
|||||
|
using System; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Input; |
||||
|
using System.Windows.Markup; |
||||
|
using System.Windows.Controls.Primitives; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents a spinner control that includes two Buttons.
|
||||
|
/// </summary>
|
||||
|
[ContentProperty("Content")] |
||||
|
public class ButtonSpinner : Spinner |
||||
|
{ |
||||
|
#region Properties
|
||||
|
|
||||
|
#region Content
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies the Content dependency property.
|
||||
|
/// </summary>
|
||||
|
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(object), typeof(ButtonSpinner), new PropertyMetadata(null, OnContentPropertyChanged)); |
||||
|
public object Content |
||||
|
{ |
||||
|
get { return GetValue(ContentProperty) as object; } |
||||
|
set { SetValue(ContentProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// ContentProperty property changed handler.
|
||||
|
/// </summary>
|
||||
|
/// <param name="d">ButtonSpinner that changed its Content.</param>
|
||||
|
/// <param name="e">Event arguments.</param>
|
||||
|
private static void OnContentPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
ButtonSpinner source = d as ButtonSpinner; |
||||
|
source.OnContentChanged(e.OldValue, e.NewValue); |
||||
|
} |
||||
|
|
||||
|
#endregion //Content
|
||||
|
|
||||
|
private ButtonBase _increaseButton; |
||||
|
/// <summary>
|
||||
|
/// Gets or sets the IncreaseButton template part.
|
||||
|
/// </summary>
|
||||
|
private ButtonBase IncreaseButton |
||||
|
{ |
||||
|
get { return _increaseButton; } |
||||
|
set |
||||
|
{ |
||||
|
if (_increaseButton != null) |
||||
|
{ |
||||
|
_increaseButton.Click -= OnButtonClick; |
||||
|
} |
||||
|
|
||||
|
_increaseButton = value; |
||||
|
|
||||
|
if (_increaseButton != null) |
||||
|
{ |
||||
|
_increaseButton.Click += OnButtonClick; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private ButtonBase _decreaseButton; |
||||
|
/// <summary>
|
||||
|
/// Gets or sets the DecreaseButton template part.
|
||||
|
/// </summary>
|
||||
|
private ButtonBase DecreaseButton |
||||
|
{ |
||||
|
get { return _decreaseButton; } |
||||
|
set |
||||
|
{ |
||||
|
if (_decreaseButton != null) |
||||
|
{ |
||||
|
_decreaseButton.Click -= OnButtonClick; |
||||
|
} |
||||
|
|
||||
|
_decreaseButton = value; |
||||
|
|
||||
|
if (_decreaseButton != null) |
||||
|
{ |
||||
|
_decreaseButton.Click += OnButtonClick; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion //Properties
|
||||
|
|
||||
|
#region Constructors
|
||||
|
|
||||
|
static ButtonSpinner() |
||||
|
{ |
||||
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(ButtonSpinner), new FrameworkPropertyMetadata(typeof(ButtonSpinner))); |
||||
|
} |
||||
|
|
||||
|
#endregion //Constructors
|
||||
|
|
||||
|
#region Base Class Overrides
|
||||
|
|
||||
|
public override void OnApplyTemplate() |
||||
|
{ |
||||
|
base.OnApplyTemplate(); |
||||
|
|
||||
|
IncreaseButton = GetTemplateChild("IncreaseButton") as ButtonBase; |
||||
|
DecreaseButton = GetTemplateChild("DecreaseButton") as ButtonBase; |
||||
|
|
||||
|
SetButtonUsage(); |
||||
|
} |
||||
|
|
||||
|
#endregion //Base Class Overrides
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Occurs when the Content property value changed.
|
||||
|
/// </summary>
|
||||
|
/// <param name="oldValue">The old value of the Content property.</param>
|
||||
|
/// <param name="newValue">The new value of the Content property.</param>
|
||||
|
protected virtual void OnContentChanged(object oldValue, object newValue) { } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Handle click event of IncreaseButton and DecreaseButton template parts,
|
||||
|
/// translating Click to appropriate Spin event.
|
||||
|
/// </summary>
|
||||
|
/// <param name="sender">Event sender, should be either IncreaseButton or DecreaseButton template part.</param>
|
||||
|
/// <param name="e">Event args.</param>
|
||||
|
private void OnButtonClick(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
SpinDirection direction = sender == IncreaseButton ? SpinDirection.Increase : SpinDirection.Decrease; |
||||
|
OnSpin(new SpinEventArgs(direction)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Cancel LeftMouseButtonUp events originating from a button that has
|
||||
|
/// been changed to disabled.
|
||||
|
/// </summary>
|
||||
|
/// <param name="e">The data for the event.</param>
|
||||
|
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) |
||||
|
{ |
||||
|
base.OnMouseLeftButtonUp(e); |
||||
|
|
||||
|
Point mousePosition; |
||||
|
if (IncreaseButton != null && IncreaseButton.IsEnabled == false) |
||||
|
{ |
||||
|
mousePosition = e.GetPosition(IncreaseButton); |
||||
|
if (mousePosition.X > 0 && mousePosition.X < IncreaseButton.ActualWidth && |
||||
|
mousePosition.Y > 0 && mousePosition.Y < IncreaseButton.ActualHeight) |
||||
|
{ |
||||
|
e.Handled = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (DecreaseButton != null && DecreaseButton.IsEnabled == false) |
||||
|
{ |
||||
|
mousePosition = e.GetPosition(DecreaseButton); |
||||
|
if (mousePosition.X > 0 && mousePosition.X < DecreaseButton.ActualWidth && |
||||
|
mousePosition.Y > 0 && mousePosition.Y < DecreaseButton.ActualHeight) |
||||
|
{ |
||||
|
e.Handled = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Called when valid spin direction changed.
|
||||
|
/// </summary>
|
||||
|
/// <param name="oldValue">The old value.</param>
|
||||
|
/// <param name="newValue">The new value.</param>
|
||||
|
protected override void OnValidSpinDirectionChanged(ValidSpinDirections oldValue, ValidSpinDirections newValue) |
||||
|
{ |
||||
|
SetButtonUsage(); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Disables or enables the buttons based on the valid spin direction.
|
||||
|
/// </summary>
|
||||
|
private void SetButtonUsage() |
||||
|
{ |
||||
|
// buttonspinner adds buttons that spin, so disable accordingly.
|
||||
|
if (IncreaseButton != null) |
||||
|
{ |
||||
|
IncreaseButton.IsEnabled = ((ValidSpinDirection & ValidSpinDirections.Increase) == ValidSpinDirections.Increase); |
||||
|
} |
||||
|
|
||||
|
if (DecreaseButton != null) |
||||
|
{ |
||||
|
DecreaseButton.IsEnabled = ((ValidSpinDirection & ValidSpinDirections.Decrease) == ValidSpinDirections.Decrease); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents spin directions that could be initiated by the end-user.
|
||||
|
/// </summary>
|
||||
|
/// <QualityBand>Preview</QualityBand>
|
||||
|
public enum SpinDirection |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents a spin initiated by the end-user in order to Increase a value.
|
||||
|
/// </summary>
|
||||
|
Increase = 0, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Represents a spin initiated by the end-user in order to Decrease a value.
|
||||
|
/// </summary>
|
||||
|
Decrease = 1 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,28 @@ |
|||||
|
using System; |
||||
|
using System.Windows; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Provides data for the Spinner.Spin event.
|
||||
|
/// </summary>
|
||||
|
/// <QualityBand>Preview</QualityBand>
|
||||
|
public class SpinEventArgs : RoutedEventArgs |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets the SpinDirection for the spin that has been initiated by the
|
||||
|
/// end-user.
|
||||
|
/// </summary>
|
||||
|
public SpinDirection Direction { get; private set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the SpinEventArgs class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="direction">Spin direction.</param>
|
||||
|
public SpinEventArgs(SpinDirection direction) |
||||
|
: base() |
||||
|
{ |
||||
|
Direction = direction; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,77 @@ |
|||||
|
using System; |
||||
|
using System.Windows.Controls; |
||||
|
using System.Windows; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Base class for controls that represents controls that can spin.
|
||||
|
/// </summary>
|
||||
|
public abstract class Spinner : Control |
||||
|
{ |
||||
|
#region Properties
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Identifies the ValidSpinDirection dependency property.
|
||||
|
/// </summary>
|
||||
|
public static readonly DependencyProperty ValidSpinDirectionProperty = DependencyProperty.Register("ValidSpinDirection", typeof(ValidSpinDirections), typeof(Spinner), new PropertyMetadata(ValidSpinDirections.Increase | ValidSpinDirections.Decrease, OnValidSpinDirectionPropertyChanged)); |
||||
|
public ValidSpinDirections ValidSpinDirection |
||||
|
{ |
||||
|
get { return (ValidSpinDirections)GetValue(ValidSpinDirectionProperty); } |
||||
|
set { SetValue(ValidSpinDirectionProperty, value); } |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// ValidSpinDirectionProperty property changed handler.
|
||||
|
/// </summary>
|
||||
|
/// <param name="d">ButtonSpinner that changed its ValidSpinDirection.</param>
|
||||
|
/// <param name="e">Event arguments.</param>
|
||||
|
private static void OnValidSpinDirectionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
Spinner source = (Spinner)d; |
||||
|
ValidSpinDirections oldvalue = (ValidSpinDirections)e.OldValue; |
||||
|
ValidSpinDirections newvalue = (ValidSpinDirections)e.NewValue; |
||||
|
source.OnValidSpinDirectionChanged(oldvalue, newvalue); |
||||
|
} |
||||
|
|
||||
|
#endregion //Properties
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Occurs when spinning is initiated by the end-user.
|
||||
|
/// </summary>
|
||||
|
public event EventHandler<SpinEventArgs> Spin; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the Spinner class.
|
||||
|
/// </summary>
|
||||
|
protected Spinner() { } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Raises the OnSpin event when spinning is initiated by the end-user.
|
||||
|
/// </summary>
|
||||
|
/// <param name="e">Spin event args.</param>
|
||||
|
protected virtual void OnSpin(SpinEventArgs e) |
||||
|
{ |
||||
|
ValidSpinDirections valid = e.Direction == SpinDirection.Increase ? ValidSpinDirections.Increase : ValidSpinDirections.Decrease; |
||||
|
|
||||
|
if ((ValidSpinDirection & valid) != valid) |
||||
|
{ |
||||
|
// spin is not allowed.
|
||||
|
throw new InvalidOperationException("Spin action is not valid at this moment."); |
||||
|
} |
||||
|
|
||||
|
EventHandler<SpinEventArgs> handler = Spin; |
||||
|
if (handler != null) |
||||
|
{ |
||||
|
handler(this, e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Called when valid spin direction changed.
|
||||
|
/// </summary>
|
||||
|
/// <param name="oldValue">The old value.</param>
|
||||
|
/// <param name="newValue">The new value.</param>
|
||||
|
protected virtual void OnValidSpinDirectionChanged(ValidSpinDirections oldValue, ValidSpinDirections newValue) { } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents spin directions that are valid.
|
||||
|
/// </summary>
|
||||
|
[Flags] |
||||
|
public enum ValidSpinDirections |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Can not increase nor decrease.
|
||||
|
/// </summary>
|
||||
|
None = 0, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Can increase.
|
||||
|
/// </summary>
|
||||
|
Increase = 1, |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Can decrease.
|
||||
|
/// </summary>
|
||||
|
Decrease = 2 |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,215 @@ |
|||||
|
using System; |
||||
|
using System.Collections; |
||||
|
using System.Windows.Media; |
||||
|
using System.Windows.Documents; |
||||
|
using System.Windows; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls.Core |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// An adorner that can display one and only one UIElement.
|
||||
|
/// That element can be a panel, which contains multiple other elements.
|
||||
|
/// The element is added to the adorner's visual and logical trees, enabling it to
|
||||
|
/// particpate in dependency property value inheritance, amongst other things.
|
||||
|
/// </summary>
|
||||
|
internal class UIElementAdorner<TElement> |
||||
|
: Adorner |
||||
|
where TElement : UIElement |
||||
|
{ |
||||
|
#region Fields
|
||||
|
|
||||
|
TElement _child = null; |
||||
|
double _offsetLeft = 0; |
||||
|
double _offsetTop = 0; |
||||
|
|
||||
|
#endregion // Fields
|
||||
|
|
||||
|
#region Constructor
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Constructor.
|
||||
|
/// </summary>
|
||||
|
/// <param name="adornedElement">The element to which the adorner will be bound.</param>
|
||||
|
public UIElementAdorner(UIElement adornedElement) |
||||
|
: base(adornedElement) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
#endregion // Constructor
|
||||
|
|
||||
|
#region Public Interface
|
||||
|
|
||||
|
#region Child
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets/sets the child element hosted in the adorner.
|
||||
|
/// </summary>
|
||||
|
public TElement Child |
||||
|
{ |
||||
|
get { return _child; } |
||||
|
set |
||||
|
{ |
||||
|
if (value == _child) |
||||
|
return; |
||||
|
|
||||
|
if (_child != null) |
||||
|
{ |
||||
|
base.RemoveLogicalChild(_child); |
||||
|
base.RemoveVisualChild(_child); |
||||
|
} |
||||
|
|
||||
|
_child = value; |
||||
|
|
||||
|
if (_child != null) |
||||
|
{ |
||||
|
base.AddLogicalChild(_child); |
||||
|
base.AddVisualChild(_child); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion // Child
|
||||
|
|
||||
|
#region GetDesiredTransform
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Override.
|
||||
|
/// </summary>
|
||||
|
/// <param name="transform"></param>
|
||||
|
/// <returns></returns>
|
||||
|
public override GeneralTransform GetDesiredTransform(GeneralTransform transform) |
||||
|
{ |
||||
|
GeneralTransformGroup result = new GeneralTransformGroup(); |
||||
|
result.Children.Add(base.GetDesiredTransform(transform)); |
||||
|
result.Children.Add(new TranslateTransform(_offsetLeft, _offsetTop)); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
#endregion // GetDesiredTransform
|
||||
|
|
||||
|
#region OffsetLeft
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets/sets the horizontal offset of the adorner.
|
||||
|
/// </summary>
|
||||
|
public double OffsetLeft |
||||
|
{ |
||||
|
get { return _offsetLeft; } |
||||
|
set |
||||
|
{ |
||||
|
_offsetLeft = value; |
||||
|
UpdateLocation(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion // OffsetLeft
|
||||
|
|
||||
|
#region SetOffsets
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Updates the location of the adorner in one atomic operation.
|
||||
|
/// </summary>
|
||||
|
public void SetOffsets(double left, double top) |
||||
|
{ |
||||
|
_offsetLeft = left; |
||||
|
_offsetTop = top; |
||||
|
this.UpdateLocation(); |
||||
|
} |
||||
|
|
||||
|
#endregion // SetOffsets
|
||||
|
|
||||
|
#region OffsetTop
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets/sets the vertical offset of the adorner.
|
||||
|
/// </summary>
|
||||
|
public double OffsetTop |
||||
|
{ |
||||
|
get { return _offsetTop; } |
||||
|
set |
||||
|
{ |
||||
|
_offsetTop = value; |
||||
|
UpdateLocation(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion // OffsetTop
|
||||
|
|
||||
|
#endregion // Public Interface
|
||||
|
|
||||
|
#region Protected Overrides
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Override.
|
||||
|
/// </summary>
|
||||
|
/// <param name="constraint"></param>
|
||||
|
/// <returns></returns>
|
||||
|
protected override Size MeasureOverride(Size constraint) |
||||
|
{ |
||||
|
if (_child == null) |
||||
|
return base.MeasureOverride(constraint); |
||||
|
|
||||
|
_child.Measure(constraint); |
||||
|
return _child.DesiredSize; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Override.
|
||||
|
/// </summary>
|
||||
|
/// <param name="finalSize"></param>
|
||||
|
/// <returns></returns>
|
||||
|
protected override Size ArrangeOverride(Size finalSize) |
||||
|
{ |
||||
|
if (_child == null) |
||||
|
return base.ArrangeOverride(finalSize); |
||||
|
|
||||
|
_child.Arrange(new Rect(finalSize)); |
||||
|
return finalSize; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Override.
|
||||
|
/// </summary>
|
||||
|
protected override IEnumerator LogicalChildren |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
ArrayList list = new ArrayList(); |
||||
|
if (_child != null) |
||||
|
list.Add(_child); |
||||
|
return list.GetEnumerator(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Override.
|
||||
|
/// </summary>
|
||||
|
/// <param name="index"></param>
|
||||
|
/// <returns></returns>
|
||||
|
protected override Visual GetVisualChild(int index) |
||||
|
{ |
||||
|
return _child; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Override.
|
||||
|
/// </summary>
|
||||
|
protected override int VisualChildrenCount |
||||
|
{ |
||||
|
get { return _child == null ? 0 : 1; } |
||||
|
} |
||||
|
|
||||
|
#endregion // Protected Overrides
|
||||
|
|
||||
|
#region Private Helpers
|
||||
|
|
||||
|
void UpdateLocation() |
||||
|
{ |
||||
|
AdornerLayer adornerLayer = base.Parent as AdornerLayer; |
||||
|
if (adornerLayer != null) |
||||
|
adornerLayer.Update(base.AdornedElement); |
||||
|
} |
||||
|
|
||||
|
#endregion // Private Helpers
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,187 @@ |
|||||
|
using System; |
||||
|
using System.Windows; |
||||
|
using System.Globalization; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls |
||||
|
{ |
||||
|
|
||||
|
public class NumericUpDown : UpDownBase<double> |
||||
|
{ |
||||
|
#region Properties
|
||||
|
|
||||
|
#region Minimum
|
||||
|
|
||||
|
public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(Double.MinValue, OnMinimumPropertyChanged)); |
||||
|
public double Minimum |
||||
|
{ |
||||
|
get { return (double)GetValue(MinimumProperty); } |
||||
|
set { SetValue(MinimumProperty, value); } |
||||
|
} |
||||
|
|
||||
|
private static void OnMinimumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnMinimumChanged(double oldValue, double newValue) |
||||
|
{ |
||||
|
} |
||||
|
#endregion Minimum
|
||||
|
|
||||
|
#region Maximum
|
||||
|
|
||||
|
public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(NumericUpDown), new PropertyMetadata(Double.MaxValue, OnMaximumPropertyChanged)); |
||||
|
public double Maximum |
||||
|
{ |
||||
|
get { return (double)GetValue(MaximumProperty); } |
||||
|
set { SetValue(MaximumProperty, value); } |
||||
|
} |
||||
|
|
||||
|
private static void OnMaximumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnMaximumChanged(double oldValue, double newValue) |
||||
|
{ |
||||
|
} |
||||
|
#endregion Maximum
|
||||
|
|
||||
|
#region Increment
|
||||
|
|
||||
|
public static readonly DependencyProperty IncrementProperty = DependencyProperty.Register("Increment", typeof(double), typeof(NumericUpDown), new PropertyMetadata(1d, OnIncrementPropertyChanged)); |
||||
|
public double Increment |
||||
|
{ |
||||
|
get { return (double)GetValue(IncrementProperty); } |
||||
|
set { SetValue(IncrementProperty, value); } |
||||
|
} |
||||
|
|
||||
|
private static void OnIncrementPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnIncrementChanged(double oldValue, double newValue) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region FormatString
|
||||
|
|
||||
|
public static readonly DependencyProperty StringFormatProperty = DependencyProperty.Register("FormatString", typeof(string), typeof(NumericUpDown), new PropertyMetadata("F0", OnStringFormatPropertyPropertyChanged)); |
||||
|
public string FormatString |
||||
|
{ |
||||
|
get { return (string)GetValue(StringFormatProperty); } |
||||
|
set { SetValue(StringFormatProperty, value); } |
||||
|
} |
||||
|
|
||||
|
private static void OnStringFormatPropertyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
NumericUpDown nud = d as NumericUpDown; |
||||
|
nud.OnStringFormatChanged(e.OldValue.ToString(), e.NewValue.ToString()); |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnStringFormatChanged(string oldValue, string newValue) |
||||
|
{ |
||||
|
Text = FormatValue(); |
||||
|
} |
||||
|
|
||||
|
#endregion //FormatString
|
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region Constructors
|
||||
|
|
||||
|
public NumericUpDown() |
||||
|
: base() |
||||
|
{ |
||||
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericUpDown), new FrameworkPropertyMetadata(typeof(NumericUpDown))); |
||||
|
} |
||||
|
|
||||
|
#endregion //Constructors
|
||||
|
|
||||
|
#region Base Class Overrides
|
||||
|
|
||||
|
public override void OnApplyTemplate() |
||||
|
{ |
||||
|
base.OnApplyTemplate(); |
||||
|
SetValidSpinDirection(); |
||||
|
} |
||||
|
|
||||
|
protected override void OnValueChanged(RoutedPropertyChangedEventArgs<double> e) |
||||
|
{ |
||||
|
SetValidSpinDirection(); |
||||
|
} |
||||
|
|
||||
|
protected override double ParseValue(string text) |
||||
|
{ |
||||
|
NumberFormatInfo info = NumberFormatInfo.GetInstance(CultureInfo.CurrentCulture); |
||||
|
if (text.Contains(info.PercentSymbol)) |
||||
|
return TryParcePercent(text, info); |
||||
|
else |
||||
|
return TryParceDouble(text, info); |
||||
|
} |
||||
|
|
||||
|
protected internal override string FormatValue() |
||||
|
{ |
||||
|
return Value.ToString(FormatString, CultureInfo.CurrentCulture); |
||||
|
} |
||||
|
|
||||
|
protected override void OnIncrement() |
||||
|
{ |
||||
|
Value = (double)((decimal)Value + (decimal)Increment); |
||||
|
} |
||||
|
|
||||
|
protected override void OnDecrement() |
||||
|
{ |
||||
|
Value = (double)((decimal)Value - (decimal)Increment); |
||||
|
} |
||||
|
|
||||
|
#endregion //Base Class Overrides
|
||||
|
|
||||
|
#region Methods
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Sets the valid spin direction based on current value, minimum and maximum.
|
||||
|
/// </summary>
|
||||
|
private void SetValidSpinDirection() |
||||
|
{ |
||||
|
ValidSpinDirections validDirections = ValidSpinDirections.None; |
||||
|
|
||||
|
if (Value < Maximum) |
||||
|
{ |
||||
|
validDirections = validDirections | ValidSpinDirections.Increase; |
||||
|
} |
||||
|
|
||||
|
if (Value > Minimum) |
||||
|
{ |
||||
|
validDirections = validDirections | ValidSpinDirections.Decrease; |
||||
|
} |
||||
|
|
||||
|
if (Spinner != null) |
||||
|
{ |
||||
|
Spinner.ValidSpinDirection = validDirections; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private double TryParcePercent(string text, NumberFormatInfo info) |
||||
|
{ |
||||
|
double result; |
||||
|
text = text.Replace(info.PercentSymbol, null); |
||||
|
result = TryParceDouble(text, info); |
||||
|
return result / 100; |
||||
|
} |
||||
|
|
||||
|
private double TryParceDouble(string text, NumberFormatInfo info) |
||||
|
{ |
||||
|
double result; |
||||
|
if (!double.TryParse(text, NumberStyles.Any, info, out result)) |
||||
|
{ |
||||
|
//an error occured now lets reset our value, text, and the text in the textbox
|
||||
|
result = Value; |
||||
|
TextBox.Text = Text = FormatValue(); |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
#endregion //Methods
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls |
||||
|
{ |
||||
|
public interface IRichTextBoxFormatBar |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents the RichTextBox that will be the target for all text manipulations in the format bar.
|
||||
|
/// </summary>
|
||||
|
global::System.Windows.Controls.RichTextBox Target { get; set; } |
||||
|
} |
||||
|
} |
||||
|
After Width: | Height: | Size: 175 B |
|
After Width: | Height: | Size: 172 B |
|
After Width: | Height: | Size: 183 B |
|
After Width: | Height: | Size: 169 B |
|
After Width: | Height: | Size: 186 B |
|
After Width: | Height: | Size: 181 B |
|
After Width: | Height: | Size: 197 B |
@ -0,0 +1,203 @@ |
|||||
|
<UserControl x:Class="Microsoft.Windows.Controls.RichTextBoxFormatBar" |
||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
Background="Transparent" |
||||
|
IsTabStop="False" |
||||
|
x:Name="_window"> |
||||
|
<UserControl.Effect> |
||||
|
<DropShadowEffect BlurRadius="5" Opacity=".25" /> |
||||
|
</UserControl.Effect> |
||||
|
|
||||
|
<UserControl.Resources> |
||||
|
|
||||
|
<Style TargetType="{x:Type Separator}" BasedOn="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}"/> |
||||
|
|
||||
|
<ControlTemplate x:Key="ThumbControlTemplate" TargetType="{x:Type Thumb}"> |
||||
|
<Border Background="Transparent" Cursor="Hand" ToolTip="Click to Drag"> |
||||
|
<StackPanel VerticalAlignment="Center" Width="75"> |
||||
|
<Line SnapsToDevicePixels="True" Stretch="Fill" StrokeDashArray="1,2" StrokeThickness="1" X1="0" X2="1" Margin=".5" > |
||||
|
<Line.Stroke> |
||||
|
<SolidColorBrush Color="Gray" /> |
||||
|
</Line.Stroke> |
||||
|
</Line> |
||||
|
<Line SnapsToDevicePixels="True" Stretch="Fill" StrokeDashArray="1,2" StrokeThickness="1" X1="0" X2="1" Margin=".5"> |
||||
|
<Line.Stroke> |
||||
|
<SolidColorBrush Color="Gray" /> |
||||
|
</Line.Stroke> |
||||
|
</Line> |
||||
|
<Line SnapsToDevicePixels="True" Stretch="Fill" StrokeDashArray="1,2" StrokeThickness="1" X1="0" X2="1" Margin=".5"> |
||||
|
<Line.Stroke> |
||||
|
<SolidColorBrush Color="Gray" /> |
||||
|
</Line.Stroke> |
||||
|
</Line> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
</ControlTemplate> |
||||
|
|
||||
|
<SolidColorBrush x:Key="MouseOverBorderBrush" Color="#FFFFB700" /> |
||||
|
<LinearGradientBrush x:Key="MouseOverBackgroundBrush" StartPoint="0,0" EndPoint="0,1" > |
||||
|
<GradientStop Offset="0" Color="#FFFEFBF4" /> |
||||
|
<GradientStop Offset="0.19" Color="#FFFDE7CE" /> |
||||
|
<GradientStop Offset="0.39" Color="#FFFDDEB8" /> |
||||
|
<GradientStop Offset="0.39" Color="#FFFFCE6B" /> |
||||
|
<GradientStop Offset="0.79" Color="#FFFFDE9A" /> |
||||
|
<GradientStop Offset="1" Color="#FFFFEBAA" /> |
||||
|
</LinearGradientBrush> |
||||
|
|
||||
|
<SolidColorBrush x:Key="CheckedBorderBrush" Color="#FFC29B29" /> |
||||
|
<LinearGradientBrush x:Key="CheckedBackgroundBrush" StartPoint="0,0" EndPoint="0,1" > |
||||
|
<GradientStop Offset="0" Color="#FFFFDCA0" /> |
||||
|
<GradientStop Offset="0.18" Color="#FFFFD692" /> |
||||
|
<GradientStop Offset="0.39" Color="#FFFFC45D" /> |
||||
|
<GradientStop Offset="1" Color="#FFFFD178" /> |
||||
|
</LinearGradientBrush> |
||||
|
|
||||
|
<SolidColorBrush x:Key="PressedBorderBrush" Color="#FFC29B29" /> |
||||
|
<LinearGradientBrush x:Key="PressedBackgroundBrush" StartPoint="0,0" EndPoint="0,1" > |
||||
|
<GradientStop Offset="0" Color="#FFE3C085" /> |
||||
|
<GradientStop Offset="0.19" Color="#FFF4CC89" /> |
||||
|
<GradientStop Offset="0.36" Color="#FFF5C777" /> |
||||
|
<GradientStop Offset="0.36" Color="#FFF5BB56" /> |
||||
|
<GradientStop Offset="0.79" Color="#FFF4CE9A" /> |
||||
|
<GradientStop Offset="1" Color="#FFF3E28D" /> |
||||
|
</LinearGradientBrush> |
||||
|
|
||||
|
<Style x:Key="FormatBarToggleButtonStyle" TargetType="{x:Type ToggleButton}"> |
||||
|
<Setter Property="Background" Value="Transparent"/> |
||||
|
<Setter Property="BorderBrush" Value="Transparent"/> |
||||
|
<Setter Property="BorderThickness" Value="1"/> |
||||
|
<Setter Property="FocusVisualStyle" Value="{x:Null}"/> |
||||
|
<Setter Property="Height" Value="22" /> |
||||
|
<Setter Property="HorizontalContentAlignment" Value="Center"/> |
||||
|
<Setter Property="ToolTipService.InitialShowDelay" Value="900"/> |
||||
|
<Setter Property="ToolTipService.ShowDuration" Value="20000"/> |
||||
|
<Setter Property="ToolTipService.BetweenShowDelay" Value="0"/> |
||||
|
<Setter Property="Template"> |
||||
|
<Setter.Value> |
||||
|
<ControlTemplate TargetType="{x:Type ToggleButton}"> |
||||
|
<Grid SnapsToDevicePixels="True"> |
||||
|
<Border x:Name="OuterBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="2"/> |
||||
|
<Border x:Name="MiddleBorder" BorderBrush="Transparent" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent" CornerRadius="2"> |
||||
|
<Border x:Name="InnerBorder" BorderBrush="Transparent" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent" CornerRadius="2" Padding="{TemplateBinding Padding}"> |
||||
|
<StackPanel x:Name="StackPanel" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"> |
||||
|
<ContentPresenter x:Name="Content" Content="{TemplateBinding Content}" Margin="1" |
||||
|
RenderOptions.BitmapScalingMode="NearestNeighbor" |
||||
|
VerticalAlignment="Center" |
||||
|
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" /> |
||||
|
</StackPanel> |
||||
|
</Border> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
<ControlTemplate.Triggers> |
||||
|
<Trigger Property="IsMouseOver" Value="True"> |
||||
|
<Setter Property="Background" TargetName="OuterBorder" Value="{StaticResource MouseOverBackgroundBrush}"/> |
||||
|
<Setter Property="BorderBrush" TargetName="OuterBorder" Value="{StaticResource MouseOverBorderBrush}"/> |
||||
|
<Setter Property="BorderBrush" TargetName="InnerBorder" Value="#80FFFFFF"/> |
||||
|
</Trigger> |
||||
|
|
||||
|
<Trigger Property="IsEnabled" Value="False"> |
||||
|
<Setter Property="Opacity" TargetName="Content" Value="0.5"/> |
||||
|
<Setter Property="TextElement.Foreground" TargetName="OuterBorder" Value="#FF9E9E9E"/> |
||||
|
</Trigger> |
||||
|
|
||||
|
<Trigger Property="IsChecked" Value="True"> |
||||
|
<Setter Property="Background" TargetName="OuterBorder" Value="{StaticResource CheckedBackgroundBrush}"/> |
||||
|
<Setter Property="BorderBrush" TargetName="OuterBorder" Value="{StaticResource CheckedBorderBrush}"/> |
||||
|
<Setter Property="BorderBrush" TargetName="InnerBorder"> |
||||
|
<Setter.Value> |
||||
|
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0"> |
||||
|
<GradientStop Color="#FFE7CBAD" Offset="0"/> |
||||
|
<GradientStop Color="#FFF7D7B5" Offset="0.1"/> |
||||
|
<GradientStop Color="#FFFFD38C" Offset="0.36"/> |
||||
|
<GradientStop Color="#FFFFC75A" Offset="0.36"/> |
||||
|
<GradientStop Color="#FFFFEFA5" Offset="1"/> |
||||
|
</LinearGradientBrush> |
||||
|
</Setter.Value> |
||||
|
</Setter> |
||||
|
</Trigger> |
||||
|
|
||||
|
<Trigger Property="IsPressed" Value="True"> |
||||
|
<Setter Property="Background" TargetName="OuterBorder" Value="{StaticResource PressedBackgroundBrush}"/> |
||||
|
<Setter Property="BorderBrush" TargetName="OuterBorder" Value="{StaticResource PressedBorderBrush}"/> |
||||
|
<Setter Property="BorderBrush" TargetName="InnerBorder" Value="Transparent"/> |
||||
|
</Trigger> |
||||
|
|
||||
|
<MultiTrigger> |
||||
|
<MultiTrigger.Conditions> |
||||
|
<Condition Property="IsChecked" Value="True"/> |
||||
|
<Condition Property="IsMouseOver" Value="True"/> |
||||
|
</MultiTrigger.Conditions> |
||||
|
<Setter Property="Background" TargetName="MiddleBorder"> |
||||
|
<Setter.Value> |
||||
|
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0"> |
||||
|
<GradientStop Color="#40FFFEFE" Offset="0"/> |
||||
|
<GradientStop Color="#40FFFEFE" Offset="0.39"/> |
||||
|
<GradientStop Color="#20FFCE68" Offset="0.39"/> |
||||
|
<GradientStop Color="#20FFCE68" Offset="0.69"/> |
||||
|
<GradientStop Color="#10FFFFFF" Offset="1"/> |
||||
|
</LinearGradientBrush> |
||||
|
</Setter.Value> |
||||
|
</Setter> |
||||
|
</MultiTrigger> |
||||
|
</ControlTemplate.Triggers> |
||||
|
</ControlTemplate> |
||||
|
</Setter.Value> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
|
||||
|
</UserControl.Resources> |
||||
|
|
||||
|
<Border CornerRadius="3" BorderThickness="1" BorderBrush="Gray" Background="WhiteSmoke"> |
||||
|
<Grid Margin="5,0,5,5"> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition /> |
||||
|
<RowDefinition /> |
||||
|
</Grid.RowDefinitions> |
||||
|
|
||||
|
<Thumb x:Name="_dragWidget" Height="10" |
||||
|
Template="{StaticResource ThumbControlTemplate}" |
||||
|
DragDelta="DragWidget_DragDelta"/> |
||||
|
|
||||
|
<StackPanel Grid.Row="1"> |
||||
|
<StackPanel Orientation="Horizontal"> |
||||
|
<ComboBox x:Name="_cmbFontFamilies" IsEditable="True" Width="110" |
||||
|
SelectionChanged="FontFamily_SelectionChanged"/> |
||||
|
<ComboBox x:Name="_cmbFontSizes" IsEditable="True" Width="45" |
||||
|
SelectionChanged="FontSize_SelectionChanged"/> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Orientation="Horizontal" Margin="0,3,0,0"> |
||||
|
<ToggleButton x:Name="_btnBold" Style="{StaticResource FormatBarToggleButtonStyle}" |
||||
|
Command="EditingCommands.ToggleBold" CommandTarget="{Binding ElementName=_window, Path=Target}"> |
||||
|
<Image Source="/WPFToolkit.Extended;component/RichTextBoxFormatBar/Images/Bold16.png" /> |
||||
|
</ToggleButton> |
||||
|
<ToggleButton x:Name="_btnItalic" Style="{StaticResource FormatBarToggleButtonStyle}" |
||||
|
Command="{x:Static EditingCommands.ToggleItalic}" CommandTarget="{Binding ElementName=_window, Path=Target}"> |
||||
|
<Image Source="/WPFToolkit.Extended;component/RichTextBoxFormatBar/Images/Italic16.png" /> |
||||
|
</ToggleButton> |
||||
|
<ToggleButton x:Name="_btnUnderline" Style="{StaticResource FormatBarToggleButtonStyle}" |
||||
|
Command="{x:Static EditingCommands.ToggleUnderline}" CommandTarget="{Binding ElementName=_window, Path=Target}"> |
||||
|
<Image Source="/WPFToolkit.Extended;component/RichTextBoxFormatBar/Images/Underline16.png" /> |
||||
|
</ToggleButton> |
||||
|
|
||||
|
<Separator /> |
||||
|
|
||||
|
<RadioButton x:Name="_btnAlignLeft" Style="{StaticResource FormatBarToggleButtonStyle}" |
||||
|
Command="{x:Static EditingCommands.AlignLeft}" CommandTarget="{Binding ElementName=_window, Path=Target}" > |
||||
|
<Image Source="/WPFToolkit.Extended;component/RichTextBoxFormatBar/Images/LeftAlign16.png" /> |
||||
|
</RadioButton> |
||||
|
<RadioButton x:Name="_btnAlignCenter" Style="{StaticResource FormatBarToggleButtonStyle}" |
||||
|
Command="{x:Static EditingCommands.AlignCenter}" CommandTarget="{Binding ElementName=_window, Path=Target}" > |
||||
|
<Image Source="/WPFToolkit.Extended;component/RichTextBoxFormatBar/Images/CenterAlign16.png" /> |
||||
|
</RadioButton> |
||||
|
<RadioButton x:Name="_btnAlignRight" Style="{StaticResource FormatBarToggleButtonStyle}" |
||||
|
Command="{x:Static EditingCommands.AlignRight}" CommandTarget="{Binding ElementName=_window, Path=Target}" > |
||||
|
<Image Source="/WPFToolkit.Extended;component/RichTextBoxFormatBar/Images/RightAlign16.png" /> |
||||
|
</RadioButton> |
||||
|
|
||||
|
</StackPanel> |
||||
|
|
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
</UserControl> |
||||
@ -0,0 +1,162 @@ |
|||||
|
using System; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Controls; |
||||
|
using System.Windows.Documents; |
||||
|
using System.Windows.Media; |
||||
|
using System.Windows.Controls.Primitives; |
||||
|
using Microsoft.Windows.Controls.Core; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Interaction logic for RichTextBoxFormatBar.xaml
|
||||
|
/// </summary>
|
||||
|
public partial class RichTextBoxFormatBar : UserControl, IRichTextBoxFormatBar |
||||
|
{ |
||||
|
#region Properties
|
||||
|
|
||||
|
#region RichTextBox
|
||||
|
|
||||
|
public static readonly DependencyProperty TargetProperty = DependencyProperty.Register("Target", typeof(global::System.Windows.Controls.RichTextBox), typeof(RichTextBoxFormatBar), new PropertyMetadata(null, OnRichTextBoxPropertyChanged)); |
||||
|
public global::System.Windows.Controls.RichTextBox Target |
||||
|
{ |
||||
|
get { return (global::System.Windows.Controls.RichTextBox)GetValue(TargetProperty); } |
||||
|
set { SetValue(TargetProperty, value); } |
||||
|
} |
||||
|
|
||||
|
private static void OnRichTextBoxPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
RichTextBoxFormatBar formatBar = d as RichTextBoxFormatBar; |
||||
|
formatBar.HookupRichTextBoxEvents(); |
||||
|
} |
||||
|
|
||||
|
private void HookupRichTextBoxEvents() |
||||
|
{ |
||||
|
Target.SelectionChanged += RichTextBox_SelectionChanged; |
||||
|
} |
||||
|
|
||||
|
#endregion //RichTextBox
|
||||
|
|
||||
|
public static double[] FontSizes |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
return new double[] { |
||||
|
3.0, 4.0, 5.0, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5, |
||||
|
10.0, 10.5, 11.0, 11.5, 12.0, 12.5, 13.0, 13.5, 14.0, 15.0, |
||||
|
16.0, 17.0, 18.0, 19.0, 20.0, 22.0, 24.0, 26.0, 28.0, 30.0, |
||||
|
32.0, 34.0, 36.0, 38.0, 40.0, 44.0, 48.0, 52.0, 56.0, 60.0, 64.0, 68.0, 72.0, 76.0, |
||||
|
80.0, 88.0, 96.0, 104.0, 112.0, 120.0, 128.0, 136.0, 144.0 |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
#region Constructors
|
||||
|
|
||||
|
public RichTextBoxFormatBar() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
Loaded += FormatToolbar_Loaded; |
||||
|
} |
||||
|
|
||||
|
#endregion //Constructors
|
||||
|
|
||||
|
#region Event Hanlders
|
||||
|
|
||||
|
void FormatToolbar_Loaded(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
_cmbFontFamilies.ItemsSource = Fonts.SystemFontFamilies; |
||||
|
_cmbFontSizes.ItemsSource = FontSizes; |
||||
|
} |
||||
|
|
||||
|
private void FontFamily_SelectionChanged(object sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.AddedItems.Count == 0) |
||||
|
return; |
||||
|
|
||||
|
FontFamily editValue = (FontFamily)e.AddedItems[0]; |
||||
|
ApplyPropertyValueToSelectedText(TextElement.FontFamilyProperty, editValue); |
||||
|
} |
||||
|
|
||||
|
private void FontSize_SelectionChanged(object sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.AddedItems.Count == 0) |
||||
|
return; |
||||
|
|
||||
|
ApplyPropertyValueToSelectedText(TextElement.FontSizeProperty, e.AddedItems[0]); |
||||
|
} |
||||
|
|
||||
|
void RichTextBox_SelectionChanged(object sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
UpdateVisualState(); |
||||
|
} |
||||
|
|
||||
|
private void DragWidget_DragDelta(object sender, DragDeltaEventArgs e) |
||||
|
{ |
||||
|
ProcessMove(e); |
||||
|
} |
||||
|
|
||||
|
#endregion //Event Hanlders
|
||||
|
|
||||
|
#region Methods
|
||||
|
|
||||
|
private void UpdateVisualState() |
||||
|
{ |
||||
|
UpdateToggleButtonState(); |
||||
|
UpdateSelectedFontFamily(); |
||||
|
UpdateSelectedFontSize(); |
||||
|
} |
||||
|
|
||||
|
private void UpdateToggleButtonState() |
||||
|
{ |
||||
|
UpdateItemCheckedState(_btnBold, TextElement.FontWeightProperty, FontWeights.Bold); |
||||
|
UpdateItemCheckedState(_btnItalic, TextElement.FontStyleProperty, FontStyles.Italic); |
||||
|
UpdateItemCheckedState(_btnUnderline, Inline.TextDecorationsProperty, TextDecorations.Underline); |
||||
|
|
||||
|
UpdateItemCheckedState(_btnAlignLeft, Paragraph.TextAlignmentProperty, TextAlignment.Left); |
||||
|
UpdateItemCheckedState(_btnAlignCenter, Paragraph.TextAlignmentProperty, TextAlignment.Center); |
||||
|
UpdateItemCheckedState(_btnAlignRight, Paragraph.TextAlignmentProperty, TextAlignment.Right); |
||||
|
} |
||||
|
|
||||
|
void UpdateItemCheckedState(ToggleButton button, DependencyProperty formattingProperty, object expectedValue) |
||||
|
{ |
||||
|
object currentValue = Target.Selection.GetPropertyValue(formattingProperty); |
||||
|
button.IsChecked = (currentValue == DependencyProperty.UnsetValue) ? false : currentValue != null && currentValue.Equals(expectedValue); |
||||
|
} |
||||
|
|
||||
|
private void UpdateSelectedFontFamily() |
||||
|
{ |
||||
|
object value = Target.Selection.GetPropertyValue(TextElement.FontFamilyProperty); |
||||
|
FontFamily currentFontFamily = (FontFamily)((value == DependencyProperty.UnsetValue) ? null : value); |
||||
|
if (currentFontFamily != null) |
||||
|
{ |
||||
|
_cmbFontFamilies.SelectedItem = currentFontFamily; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void UpdateSelectedFontSize() |
||||
|
{ |
||||
|
object value = Target.Selection.GetPropertyValue(TextElement.FontSizeProperty); |
||||
|
_cmbFontSizes.SelectedValue = (value == DependencyProperty.UnsetValue) ? null : value; |
||||
|
} |
||||
|
|
||||
|
void ApplyPropertyValueToSelectedText(DependencyProperty formattingProperty, object value) |
||||
|
{ |
||||
|
if (value == null) |
||||
|
return; |
||||
|
|
||||
|
Target.Selection.ApplyPropertyValue(formattingProperty, value); |
||||
|
} |
||||
|
|
||||
|
private void ProcessMove(DragDeltaEventArgs e) |
||||
|
{ |
||||
|
AdornerLayer layer = AdornerLayer.GetAdornerLayer(Target); |
||||
|
UIElementAdorner<Control> adorner = layer.GetAdorners(Target)[0] as UIElementAdorner<Control>; |
||||
|
adorner.SetOffsets(adorner.OffsetLeft + e.HorizontalChange, adorner.OffsetTop + e.VerticalChange); |
||||
|
} |
||||
|
|
||||
|
#endregion //Methods
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,187 @@ |
|||||
|
using System; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Controls; |
||||
|
using System.Windows.Documents; |
||||
|
using Microsoft.Windows.Controls.Core; |
||||
|
using System.Windows.Input; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls |
||||
|
{ |
||||
|
public class RichTextBoxFormatBarManager : DependencyObject |
||||
|
{ |
||||
|
#region Members
|
||||
|
|
||||
|
private global::System.Windows.Controls.RichTextBox _richTextBox; |
||||
|
private UIElementAdorner<Control> _adorner; |
||||
|
private IRichTextBoxFormatBar _toolbar; |
||||
|
|
||||
|
#endregion //Members
|
||||
|
|
||||
|
#region Properties
|
||||
|
|
||||
|
#region FormatBar
|
||||
|
|
||||
|
public static readonly DependencyProperty FormatBarProperty = DependencyProperty.RegisterAttached("FormatBar", typeof(IRichTextBoxFormatBar), typeof(RichTextBox), new PropertyMetadata(null, OnFormatBarPropertyChanged)); |
||||
|
public static void SetFormatBar(UIElement element, IRichTextBoxFormatBar value) |
||||
|
{ |
||||
|
element.SetValue(FormatBarProperty, value); |
||||
|
} |
||||
|
public static IRichTextBoxFormatBar GetFormatBar(UIElement element) |
||||
|
{ |
||||
|
return (IRichTextBoxFormatBar)element.GetValue(FormatBarProperty); |
||||
|
} |
||||
|
|
||||
|
private static void OnFormatBarPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
global::System.Windows.Controls.RichTextBox rtb = d as global::System.Windows.Controls.RichTextBox; |
||||
|
if (rtb == null) |
||||
|
throw new Exception("A FormatBar can only be applied to a RichTextBox."); |
||||
|
|
||||
|
RichTextBoxFormatBarManager manager = new RichTextBoxFormatBarManager(); |
||||
|
manager.AttachFormatBarToRichtextBox(rtb, e.NewValue as IRichTextBoxFormatBar); |
||||
|
} |
||||
|
|
||||
|
#endregion //FormatBar
|
||||
|
|
||||
|
bool AdornerIsVisible |
||||
|
{ |
||||
|
get { return _adorner.Visibility == Visibility.Visible; } |
||||
|
} |
||||
|
|
||||
|
#endregion //Properties
|
||||
|
|
||||
|
#region Event Handlers
|
||||
|
|
||||
|
void RichTextBox_MouseButtonUp(object sender, MouseButtonEventArgs e) |
||||
|
{ |
||||
|
if (e.LeftButton == MouseButtonState.Released) |
||||
|
{ |
||||
|
TextRange selectedText = new TextRange(_richTextBox.Selection.Start, _richTextBox.Selection.End); |
||||
|
if (selectedText.Text.Length > 0 && !String.IsNullOrEmpty(selectedText.Text)) |
||||
|
{ |
||||
|
ShowAdorner(); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
HideAdorner(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
e.Handled = true; |
||||
|
} |
||||
|
|
||||
|
void RichTextBox_PreviewMouseMove(object sender, MouseEventArgs e) |
||||
|
{ |
||||
|
//if the mouse moves outside the richtextbox bounds hide the adorner
|
||||
|
//though this deosn't always work, especially if the user moves the mouse very quickly.
|
||||
|
//need to find a better solution, but this will work for now.
|
||||
|
Point p = e.GetPosition(_richTextBox); |
||||
|
if (p.X <= 5.0 || p.X >= _richTextBox.ActualWidth - 5 || p.Y <= 3.0 || p.Y >= _richTextBox.ActualHeight - 3) |
||||
|
HideAdorner(); |
||||
|
} |
||||
|
|
||||
|
void RichTextBox_TextChanged(object sender, TextChangedEventArgs e) |
||||
|
{ |
||||
|
//this fixes the bug when applying text transformations the text would lose it's highlight. That was because the RichTextBox was losing focus
|
||||
|
//so we just give it focus again and it seems to do the trick of re-highlighting it.
|
||||
|
if (!_richTextBox.IsFocused) |
||||
|
_richTextBox.Focus(); |
||||
|
} |
||||
|
|
||||
|
#endregion //Event Handlers
|
||||
|
|
||||
|
#region Methods
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Attaches a FormatBar to a RichtextBox
|
||||
|
/// </summary>
|
||||
|
/// <param name="richTextBox">The RichtextBox to attach to.</param>
|
||||
|
/// <param name="formatBar">The Formatbar to attach.</param>
|
||||
|
private void AttachFormatBarToRichtextBox(global::System.Windows.Controls.RichTextBox richTextBox, IRichTextBoxFormatBar formatBar) |
||||
|
{ |
||||
|
_richTextBox = richTextBox; |
||||
|
_richTextBox.PreviewMouseMove += RichTextBox_PreviewMouseMove; |
||||
|
//we cannot use the PreviewMouseLeftButtonUp event because of selection bugs.
|
||||
|
//we cannot use the MouseLeftButtonUp event because it is handled by the RichTextBox and does not bubble up to here, so we must
|
||||
|
//add a hander to the MouseUpEvent using the Addhandler syntax, and specify to listen for handled events too.
|
||||
|
_richTextBox.AddHandler(Mouse.MouseUpEvent, new MouseButtonEventHandler(RichTextBox_MouseButtonUp), true); |
||||
|
_richTextBox.TextChanged += RichTextBox_TextChanged; |
||||
|
|
||||
|
_adorner = new UIElementAdorner<Control>(_richTextBox); |
||||
|
|
||||
|
formatBar.Target = _richTextBox; |
||||
|
_toolbar = formatBar; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Shows the FormatBar
|
||||
|
/// </summary>
|
||||
|
void ShowAdorner() |
||||
|
{ |
||||
|
VerifyAdornerLayer(); |
||||
|
|
||||
|
Control adorningEditor = _toolbar as Control; |
||||
|
_adorner.Child = adorningEditor; |
||||
|
_adorner.Visibility = Visibility.Visible; |
||||
|
|
||||
|
PositionFormatBar(adorningEditor); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Positions the FormatBar so that is does not go outside the bounds of the RichTextBox or covers the selected text
|
||||
|
/// </summary>
|
||||
|
/// <param name="adorningEditor"></param>
|
||||
|
private void PositionFormatBar(Control adorningEditor) |
||||
|
{ |
||||
|
Point mousePosition = Mouse.GetPosition(_richTextBox); |
||||
|
|
||||
|
double left = mousePosition.X; |
||||
|
double top = (mousePosition.Y - 15) - adorningEditor.ActualHeight; |
||||
|
|
||||
|
//top
|
||||
|
if (top < 0) |
||||
|
{ |
||||
|
top = mousePosition.Y + 10; |
||||
|
} |
||||
|
|
||||
|
//right boundary
|
||||
|
if (left + adorningEditor.ActualWidth > _richTextBox.ActualWidth - 20) |
||||
|
{ |
||||
|
left = left - (adorningEditor.ActualWidth - (_richTextBox.ActualWidth - left)); |
||||
|
} |
||||
|
|
||||
|
_adorner.SetOffsets(left, top); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Ensures that the IRichTextFormatBar is in the adorner layer.
|
||||
|
/// </summary>
|
||||
|
/// <returns>True if the IRichTextFormatBar is in the adorner layer, else false.</returns>
|
||||
|
bool VerifyAdornerLayer() |
||||
|
{ |
||||
|
if (_adorner.Parent != null) |
||||
|
return true; |
||||
|
|
||||
|
AdornerLayer layer = AdornerLayer.GetAdornerLayer(_richTextBox); |
||||
|
if (layer == null) |
||||
|
return false; |
||||
|
|
||||
|
layer.Add(_adorner); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Hides the IRichTextFormatBar that is in the adornor layer.
|
||||
|
/// </summary>
|
||||
|
void HideAdorner() |
||||
|
{ |
||||
|
if (AdornerIsVisible) |
||||
|
{ |
||||
|
_adorner.Visibility = Visibility.Collapsed; |
||||
|
_adorner.Child = null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion //Methods
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,321 @@ |
|||||
|
using System; |
||||
|
using System.Windows.Input; |
||||
|
using System.Windows.Controls; |
||||
|
using System.Windows; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls |
||||
|
{ |
||||
|
public abstract class UpDownBase<T> : Control |
||||
|
{ |
||||
|
#region Members
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Name constant for Text template part.
|
||||
|
/// </summary>
|
||||
|
internal const string ElementTextName = "Text"; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Name constant for Spinner template part.
|
||||
|
/// </summary>
|
||||
|
internal const string ElementSpinnerName = "Spinner"; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Flags if the Text and Value properties are in the process of being sync'd
|
||||
|
/// </summary>
|
||||
|
bool _isSyncingTextAndValueProperties; |
||||
|
|
||||
|
#endregion //Members
|
||||
|
|
||||
|
#region Properties
|
||||
|
|
||||
|
#region Value
|
||||
|
|
||||
|
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(T), typeof(UpDownBase<T>), new FrameworkPropertyMetadata(default(T), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnValuePropertyChanged)); |
||||
|
public virtual T Value |
||||
|
{ |
||||
|
get { return (T)GetValue(ValueProperty); } |
||||
|
set { SetValue(ValueProperty, value); } |
||||
|
} |
||||
|
|
||||
|
private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
UpDownBase<T> udb = (UpDownBase<T>)d; |
||||
|
T oldValue = (T)e.OldValue; |
||||
|
T newValue = (T)e.NewValue; |
||||
|
|
||||
|
udb.SyncTextAndValueProperties(e.Property, e.NewValue); |
||||
|
|
||||
|
RoutedPropertyChangedEventArgs<T> changedArgs = new RoutedPropertyChangedEventArgs<T>(oldValue, newValue); |
||||
|
udb.OnValueChanged(changedArgs); |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnValueChanged(RoutedPropertyChangedEventArgs<T> e) |
||||
|
{ |
||||
|
if (ValueChanged != null) |
||||
|
ValueChanged(this, e); |
||||
|
} |
||||
|
|
||||
|
#endregion //Value
|
||||
|
|
||||
|
#region Text
|
||||
|
|
||||
|
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(UpDownBase<T>), new FrameworkPropertyMetadata("0", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnTextPropertyChanged)); |
||||
|
public string Text |
||||
|
{ |
||||
|
get { return (string)GetValue(TextProperty); } |
||||
|
set { SetValue(TextProperty, value); } |
||||
|
} |
||||
|
|
||||
|
private static void OnTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
UpDownBase<T> udb = (UpDownBase<T>)d; |
||||
|
udb.SyncTextAndValueProperties(e.Property, e.NewValue); |
||||
|
} |
||||
|
|
||||
|
#endregion //Text
|
||||
|
|
||||
|
#region IsEditable
|
||||
|
|
||||
|
public static readonly DependencyProperty IsEditableProperty = DependencyProperty.Register("IsEditable", typeof(bool), typeof(UpDownBase<T>), new PropertyMetadata(true, OnIsEditablePropertyChanged)); |
||||
|
public bool IsEditable |
||||
|
{ |
||||
|
get { return (bool)GetValue(IsEditableProperty); } |
||||
|
set { SetValue(IsEditableProperty, value); } |
||||
|
} |
||||
|
|
||||
|
private static void OnIsEditablePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
UpDownBase<T> source = d as UpDownBase<T>; |
||||
|
source.OnIsEditableChanged((bool)e.OldValue, (bool)e.NewValue); |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnIsEditableChanged(bool oldValue, bool newValue) |
||||
|
{ |
||||
|
if (TextBox != null) |
||||
|
TextBox.IsReadOnly = !IsEditable; |
||||
|
} |
||||
|
|
||||
|
#endregion //IsEditable
|
||||
|
|
||||
|
internal TextBox TextBox { get; private set; } |
||||
|
|
||||
|
private Spinner _spinner; |
||||
|
internal Spinner Spinner |
||||
|
{ |
||||
|
get { return _spinner; } |
||||
|
private set |
||||
|
{ |
||||
|
_spinner = value; |
||||
|
_spinner.Spin += OnSpinnerSpin; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion //Properties
|
||||
|
|
||||
|
#region Constructors
|
||||
|
|
||||
|
protected UpDownBase() { } |
||||
|
|
||||
|
#endregion //Constructors
|
||||
|
|
||||
|
#region Base Class Overrides
|
||||
|
|
||||
|
public override void OnApplyTemplate() |
||||
|
{ |
||||
|
base.OnApplyTemplate(); |
||||
|
|
||||
|
TextBox = GetTemplateChild(ElementTextName) as TextBox; |
||||
|
Spinner = GetTemplateChild(ElementSpinnerName) as Spinner; |
||||
|
|
||||
|
if (TextBox != null) |
||||
|
TextBox.IsReadOnly = !IsEditable; |
||||
|
} |
||||
|
|
||||
|
protected override void OnPreviewKeyDown(KeyEventArgs e) |
||||
|
{ |
||||
|
switch (e.Key) |
||||
|
{ |
||||
|
case Key.Up: |
||||
|
{ |
||||
|
DoIncrement(); |
||||
|
e.Handled = true; |
||||
|
break; |
||||
|
} |
||||
|
case Key.Down: |
||||
|
{ |
||||
|
DoDecrement(); |
||||
|
e.Handled = true; |
||||
|
break; |
||||
|
} |
||||
|
case Key.Enter: |
||||
|
{ |
||||
|
SyncTextAndValueProperties(UpDownBase<T>.TextProperty, TextBox.Text); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected override void OnMouseWheel(MouseWheelEventArgs e) |
||||
|
{ |
||||
|
base.OnMouseWheel(e); |
||||
|
|
||||
|
if (!e.Handled) |
||||
|
{ |
||||
|
if (e.Delta < 0) |
||||
|
{ |
||||
|
DoDecrement(); |
||||
|
} |
||||
|
else if (0 < e.Delta) |
||||
|
{ |
||||
|
DoIncrement(); |
||||
|
} |
||||
|
|
||||
|
e.Handled = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion //Base Class Overrides
|
||||
|
|
||||
|
#region Methods
|
||||
|
|
||||
|
#region Abstract
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Called by ApplyValue to parse user input.
|
||||
|
/// </summary>
|
||||
|
/// <param name="text">User input.</param>
|
||||
|
/// <returns>Value parsed from user input.</returns>
|
||||
|
protected abstract T ParseValue(string text); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Renders the value property into the textbox text.
|
||||
|
/// </summary>
|
||||
|
/// <returns>Formatted Value.</returns>
|
||||
|
protected internal abstract string FormatValue(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Called by OnSpin when the spin direction is SpinDirection.Increase.
|
||||
|
/// </summary>
|
||||
|
protected abstract void OnIncrement(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Called by OnSpin when the spin direction is SpinDirection.Descrease.
|
||||
|
/// </summary>
|
||||
|
protected abstract void OnDecrement(); |
||||
|
|
||||
|
#endregion //Abstract
|
||||
|
|
||||
|
#region Protected
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// GetValue override to return Value property as object type.
|
||||
|
/// </summary>
|
||||
|
/// <returns>The Value property as object type.</returns>
|
||||
|
protected object GetValue() |
||||
|
{ |
||||
|
return Value; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// SetValue override to set value to Value property.
|
||||
|
/// </summary>
|
||||
|
/// <param name="value">New value.</param>
|
||||
|
protected void SetValue(object value) |
||||
|
{ |
||||
|
Value = (T)value; |
||||
|
} |
||||
|
|
||||
|
#endregion //Protected
|
||||
|
|
||||
|
#region Private
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Performs an increment if conditions allow it.
|
||||
|
/// </summary>
|
||||
|
private void DoDecrement() |
||||
|
{ |
||||
|
if (Spinner == null || (Spinner.ValidSpinDirection & ValidSpinDirections.Decrease) == ValidSpinDirections.Decrease) |
||||
|
{ |
||||
|
OnDecrement(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Performs a decrement if conditions allow it.
|
||||
|
/// </summary>
|
||||
|
private void DoIncrement() |
||||
|
{ |
||||
|
if (Spinner == null || (Spinner.ValidSpinDirection & ValidSpinDirections.Increase) == ValidSpinDirections.Increase) |
||||
|
{ |
||||
|
OnIncrement(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected void SyncTextAndValueProperties(DependencyProperty p, object newValue) |
||||
|
{ |
||||
|
//prevents recursive syncing properties
|
||||
|
if (_isSyncingTextAndValueProperties) |
||||
|
return; |
||||
|
|
||||
|
_isSyncingTextAndValueProperties = true; |
||||
|
|
||||
|
//this only occures when the user typed in the value
|
||||
|
if (UpDownBase<T>.TextProperty == p) |
||||
|
{ |
||||
|
SetValue(UpDownBase<T>.ValueProperty, ParseValue(newValue.ToString())); |
||||
|
} |
||||
|
|
||||
|
//we need to update the text no matter what because the user could have used the spin buttons to change dthe value
|
||||
|
//or typed in the textbox so we need to reformat the entered value.
|
||||
|
SetValue(UpDownBase<T>.TextProperty, FormatValue()); |
||||
|
|
||||
|
_isSyncingTextAndValueProperties = false; |
||||
|
} |
||||
|
|
||||
|
#endregion //Private
|
||||
|
|
||||
|
#region Virtual
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Occurs when the spinner spins.
|
||||
|
/// </summary>
|
||||
|
/// <param name="e">Event args.</param>
|
||||
|
protected virtual void OnSpin(SpinEventArgs e) |
||||
|
{ |
||||
|
if (e == null) |
||||
|
throw new ArgumentNullException("e"); |
||||
|
|
||||
|
if (e.Direction == SpinDirection.Increase) |
||||
|
DoIncrement(); |
||||
|
else |
||||
|
DoDecrement(); |
||||
|
} |
||||
|
|
||||
|
#endregion //Virtual
|
||||
|
|
||||
|
#endregion //Methods
|
||||
|
|
||||
|
#region Event Handlers
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Event handler for Spinner template part's Spin event.
|
||||
|
/// </summary>
|
||||
|
/// <param name="sender">The Spinner template part.</param>
|
||||
|
/// <param name="e">Event args.</param>
|
||||
|
private void OnSpinnerSpin(object sender, SpinEventArgs e) |
||||
|
{ |
||||
|
OnSpin(e); |
||||
|
} |
||||
|
|
||||
|
#endregion //Event Handlers
|
||||
|
|
||||
|
#region Events
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Occurs when Value property has changed.
|
||||
|
/// </summary>
|
||||
|
public event RoutedPropertyChangedEventHandler<T> ValueChanged; |
||||
|
|
||||
|
#endregion //Events
|
||||
|
} |
||||
|
} |
||||