|
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfCustomRGBHisto
{
/// <summary>
/// Control for slider with 2 thumbs to implement image levels adjustment.
/// 2 dependency properties, WhiteValue & BlackValue ranging from 0-255.
/// Control is resizable.
/// </summary>
[TemplatePart(Name="PART_TwoThumbContainer", Type=typeof(StackPanel))]
[TemplatePart(Name = "PART_BlackThumb", Type = typeof(Thumb))]
[TemplatePart(Name = "PART_WhiteThumb", Type = typeof(Thumb))]
[TemplatePart(Name = "PART_RangeRect", Type = typeof(Rectangle))]
[TemplatePart(Name = "PART_TwoThumbCanvas", Type = typeof(Canvas))]
public class TwoThumb : Control
{
public static readonly DependencyProperty BlackValueProperty; //also readonly????
public static readonly DependencyProperty WhiteValueProperty;
// non Routed event for external consumtion
public event DependencyPropertyChangedEventHandler BlackValueChanged;
public event DependencyPropertyChangedEventHandler WhiteValueChanged;
//controls included in TwoThumb
protected Thumb whiteThumb;
protected Thumb blackThumb;
private Rectangle rangeRect;
private Canvas canvas; //whiteThumb, blackThumb and rangeRect reside in canvas
private double minTrack = 0.0; //min thumb position Inited by OnCanvasSizeChanged
private double maxTrack = 0.0; //max thumb position Inited by OnCanvasSizeChanged
private double minRangeRectX; //rangeRect is one thumbnail width smaller than track
private double maxRangeRectX;
static TwoThumb()
{
//tell WPF providing new style which will provide control template
DefaultStyleKeyProperty.OverrideMetadata(typeof(TwoThumb), new FrameworkPropertyMetadata(typeof(TwoThumb)));
BlackValueProperty = DependencyProperty.Register(
"BlackValue", typeof(double), typeof(TwoThumb),
new FrameworkPropertyMetadata(0.0, new PropertyChangedCallback(OnBlackValueChanged)));
//new PropertyMetadata(0.0));
WhiteValueProperty = DependencyProperty.Register(
"WhiteValue", typeof(double), typeof(TwoThumb),
new FrameworkPropertyMetadata(255.0, new PropertyChangedCallback(OnWhiteValueChanged)));
//new PropertyMetadata(255.0));
} //static ctor
public double BlackValue
{
get { return (double)GetValue(BlackValueProperty); }
set { SetValue(BlackValueProperty, value); }
}
public double WhiteValue
{
get { return (double)GetValue(WhiteValueProperty); }
set { SetValue(WhiteValueProperty, value); }
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
//attach the Thumb drag events to the StackPanel (topmost control in twoThumb tree)
StackPanel sp = GetTemplateChild("PART_TwoThumbContainer") as StackPanel;
if (sp != null)
{
sp.AddHandler(Thumb.DragStartedEvent, new DragStartedEventHandler(OnDragStarted));
sp.AddHandler(Thumb.DragDeltaEvent, new DragDeltaEventHandler(OnDragDelta));
sp.AddHandler(Thumb.DragCompletedEvent, new DragCompletedEventHandler(OnDragCompleted));
}
//Get the parts composing the control by name
whiteThumb = GetTemplateChild("PART_WhiteThumb") as Thumb;
blackThumb = GetTemplateChild("PART_BlackThumb") as Thumb;
rangeRect = GetTemplateChild("PART_RangeRect") as Rectangle;
canvas = GetTemplateChild("PART_TwoThumbCanvas") as Canvas;
//Allow twoThumb to change in size
if (canvas != null)
{
canvas.AddHandler(SizeChangedEvent, new SizeChangedEventHandler(OnCanvasSizeChanged));
}
} //OnApplyTemplate()
void OnDragStarted(object sender, DragStartedEventArgs e)
{
Thumb thumb = (Thumb)e.OriginalSource; //sender is StackPanel
thumb.Background = Brushes.Orange;
} //OnDragStarted()
virtual protected void OnDragDelta(object sender, DragDeltaEventArgs e)
{
Thumb thumb = (Thumb)e.OriginalSource; //sender is StackPanel
double newHPos = Canvas.GetLeft(thumb) + e.HorizontalChange;
newHPos = ConstrainToTrack(newHPos);
newHPos = CoerceThumbPos(thumb, newHPos);
double value = PosToValue(newHPos);
if (thumb.Name == "PART_BlackThumb")
BlackValue = value;
else
WhiteValue = value;
Canvas.SetLeft(thumb, newHPos);
if (WhiteValue == BlackValue)
{
Canvas.SetZIndex(thumb, 1); //moved thumb goes on top
if (thumb.Name == "PART_BlackThumb") //other thumb goes below
Canvas.SetZIndex(whiteThumb, 0);
else Canvas.SetZIndex(blackThumb, 0);
}
} //OnDragDelta()
void OnDragCompleted(object sender, DragCompletedEventArgs e)
{
Thumb thumb = (Thumb)e.OriginalSource; //sender is StackPanel
thumb.Background = Brushes.BlueViolet;
} //OnDragCompleted()
protected double PosToValue(double pos)
{
if (pos > maxTrack) pos = maxTrack;
if (pos < minTrack) pos = minTrack;
return (255 * (pos - minTrack) / (maxTrack - minTrack));
} // PosToValue()
// minTrack >= pos <= maxTrack
protected double ConstrainToTrack(double pos)
{
if (pos > maxTrack) return maxTrack;
if (pos < minTrack) return minTrack;
return pos;
} //ConstrainToTrack()
//Convert thumb value to track position
//ONLY for black and white sliders.
protected double ValueToPos(double value)
{
return ConstrainToTrack(value / 255.0 * (maxTrack - minTrack) + minTrack);
} // ValueToPos()
//If new position of thumb is not valid, set it to a valid max or min
virtual protected double CoerceThumbPos(Thumb thumb, double newHpos)
{
if (thumb.Name == "PART_BlackThumb")
{
if (newHpos > ValueToPos(WhiteValue))
return ValueToPos(WhiteValue);
}
else if (newHpos < ValueToPos(BlackValue))
return ValueToPos(BlackValue);
return newHpos; // value ok
} //CoerceThumbPos()
void DrawRangeRect()
{
rangeRect.Width = maxRangeRectX - minRangeRectX;
} //DrawRect()
//Called on Canvas Size Change, assumes legitimate values already set
virtual protected void RepositionThumbs()
{
double thumbPos = ValueToPos(BlackValue);
Canvas.SetLeft(blackThumb, thumbPos);
thumbPos = ValueToPos(WhiteValue);
Canvas.SetLeft(whiteThumb, thumbPos);
}
void OnCanvasSizeChanged(object sender, SizeChangedEventArgs e)
{
Canvas myCanvas = sender as Canvas;
minRangeRectX = Canvas.GetLeft(rangeRect);
maxRangeRectX = e.NewSize.Width - minRangeRectX - blackThumb.ActualWidth/2.0; //?????????????????????????
minTrack = minRangeRectX - blackThumb.ActualWidth / 2.0;
maxTrack = maxRangeRectX - blackThumb.ActualWidth / 2.0;
DrawRangeRect();
RepositionThumbs();
} //OnCanvasSizeChanged()
//This gets called BOTH when external class set BlackValue and when BlackValue is set within the class.
static void OnBlackValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
TwoThumb tt = obj as WpfCustomRGBHisto.TwoThumb;
if (tt.blackThumb != null) //you may not have an instance yet
tt.OnBlackValueChanged( args); //call INSTANCE method passing args
}
void OnBlackValueChanged(DependencyPropertyChangedEventArgs args)
{
if (BlackValueChanged != null)
BlackValueChanged(this, args);
if (blackThumb.IsDragging) return; //thumb positions already set, internal op do nothing
//Have to decide if newValue is good
RepositionThumbs(); //value changed by client
}
//This gets called BOTH when external class set WhiteValue and when WhiteValue is set within the class.
static void OnWhiteValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
TwoThumb tt = obj as WpfCustomRGBHisto.TwoThumb;
if (tt.whiteThumb != null) //you may not have an instance yet
tt.OnWhiteValueChanged(args); //call INSTANCE method passing args
}
void OnWhiteValueChanged(DependencyPropertyChangedEventArgs args)
{
if (WhiteValueChanged != null)
WhiteValueChanged(this, args);
if (whiteThumb.IsDragging) return; //thumb positions already set, internal op do nothing
//Have to decide if newValue is good
RepositionThumbs(); //value changed by client
}
} //Class TwoThumb
} //namespace WpfCustomRGBHisto
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.