这是我的自定义控件,它是一种简单的进度条:
using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace eg.BJM.Controls
{
public class HorizontalBarGauge : Canvas
{
public HorizontalBarGauge()
{
IsSigned = true;
MinValue = -100;
MaxValue = 100;
Value = 25;
MarkerValue = -1;
BorderColor = Colors.Black;
MarkerColor = Colors.Red;
BarColor = Colors.SkyBlue;
BaseColor = Colors.DodgerBlue;
ValueColor = Colors.White;
}
#region Dependecy Properties
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(int), typeof(HorizontalBarGauge));
public static readonly DependencyProperty MinValueProperty =
DependencyProperty.Register("MinValue", typeof(int), typeof(HorizontalBarGauge));
public static readonly DependencyProperty MaxValueProperty =
DependencyProperty.Register("MaxValue", typeof(int), typeof(HorizontalBarGauge));
public static readonly DependencyProperty MarkerValueProperty =
DependencyProperty.Register("MarkerValue", typeof(int), typeof(HorizontalBarGauge));
public static readonly DependencyProperty MarkerColorProperty =
DependencyProperty.Register("MarkerColor", typeof(Color), typeof(HorizontalBarGauge));
public static readonly DependencyProperty BaseColorProperty =
DependencyProperty.Register("BaseColor", typeof(Color), typeof(HorizontalBarGauge));
public static readonly DependencyProperty BarColorProperty =
DependencyProperty.Register("BarColor", typeof(Color), typeof(HorizontalBarGauge));
public static readonly DependencyProperty BorderColorProperty =
DependencyProperty.Register("BorderColor", typeof(Color), typeof(HorizontalBarGauge));
public static readonly DependencyProperty BorderThicknessProperty =
DependencyProperty.Register("BorderThickness", typeof(double), typeof(HorizontalBarGauge));
public static readonly DependencyProperty IsSignedProperty =
DependencyProperty.Register("IsSigned", typeof(bool), typeof(HorizontalBarGauge));
public static readonly DependencyProperty ShowValueProperty =
DependencyProperty.Register("ShowValue", typeof(bool), typeof(HorizontalBarGauge));
public static readonly DependencyProperty ValueColorProperty =
DependencyProperty.Register("ValueColor", typeof(Color), typeof(HorizontalBarGauge));
#endregion
[Description("Determines whether the bar shows [min,max] or [-max,+max]")]
public bool IsSigned
{
get { return (bool)GetValue( IsSignedProperty ); }
set
{
SetValue( IsSignedProperty, value );
if (value)
{
MinValue = -MaxValue;
}
else
{
MinValue = 0;
}
reassertValues();
InvalidateVisual();
}
}
[Description("Get/set the current value to show.")]
public int Value
{
get { return (int)GetValue(ValueProperty); }
set
{
SetValue( ValueProperty, value );
InvalidateVisual();
}
}
[Description("Get/set the minimum value to show.")]
public int MinValue
{
get { return (int)GetValue(MinValueProperty); }
set
{
SetValue(MinValueProperty, value);
reassertValues();
InvalidateVisual();
}
}
[Description("Get/set the maximum value to show.")]
public int MaxValue
{
get { return (int)GetValue(MaxValueProperty); }
set
{
value = Math.Max(value, 1);
SetValue(MaxValueProperty, value);
reassertValues();
InvalidateVisual();
}
}
[Description("Get/set the marker value to show. Negative => no marker.")]
public int MarkerValue
{
get { return (int)GetValue(MarkerValueProperty); }
set
{
SetValue(MaxValueProperty, value);
reassertValues();
InvalidateVisual();
}
}
[Description("Get/set the color of the marker.")]
public Color MarkerColor
{
get { return (Color)GetValue(MarkerColorProperty); }
set
{
SetValue(MarkerColorProperty, value);
Brush penBrush = new SolidColorBrush( value );
_markerPen = new Pen( penBrush, 3 );
}
}
[Description("Get/set the value text color.")]
public Color ValueColor
{
get { return (Color)GetValue(ValueColorProperty); }
set
{
SetValue(ValueColorProperty, value);
_textBrush = new SolidColorBrush(value);
}
}
[Description("Get/set the base color.")]
public Color BaseColor
{
get { return (Color)GetValue(BaseColorProperty); }
set
{
SetValue(BaseColorProperty, value);
_bodyBrush = new SolidColorBrush( value );
}
}
[Description("Get/set the bar color.")]
public Color BarColor
{
get { return (Color)GetValue(BarColorProperty); }
set
{
SetValue(BarColorProperty, value);
_barBrush = new SolidColorBrush( value );
}
}
[Description("Get/set the border color.")]
public Color BorderColor
{
get { return (Color)GetValue(BorderColorProperty); }
set
{
SetValue(BorderColorProperty, value);
var brush = new SolidColorBrush( value );
_borderPen = new Pen( brush, BorderThickness );
}
}
[Description("Get/set the border thickness.")]
public double BorderThickness
{
get { return (double)GetValue(BorderThicknessProperty); }
set
{
SetValue(BorderThicknessProperty, value);
var brush = new SolidColorBrush( BorderColor );
_borderPen = new Pen( brush, value );
}
}
[Description("Get/set whether values are displayed in the control.")]
public bool ShowValue
{
get { return (bool)GetValue( ShowValueProperty ); }
set { SetValue( ShowValueProperty, value );}
}
protected override void OnRender(DrawingContext drawingContext)
{
base.OnRender(drawingContext);
// Background.
drawingContext.DrawRectangle(_bodyBrush, null, _rectangle);
// Bar.
int value = Value;
if (value != 0)
{
Rect barRect;
if (IsSigned)
{
double frac = Convert.ToDouble(value)/Convert.ToDouble(MaxValue*2);
if (value < 0)
{
barRect = new Rect(_rectangle.Width/2-frac*_rectangle.Width, 0, _rectangle.Width/2, _rectangle.Height);
}
else
{
barRect = new Rect( _rectangle.Width/2, 0, frac*_rectangle.Width, _rectangle.Height );
}
drawingContext.DrawRectangle( _barBrush, null, barRect );
}
else
{
double x = (_rectangle.Width*value)/(MaxValue - MinValue);
if (x > 0)
{
barRect = new Rect( 0, 0, x, _rectangle.Height );
drawingContext.DrawRectangle( _barBrush, null, barRect );
}
}
}
// Marker.
if (MarkerValue >= 0)
{
if (IsSigned)
{
double frac = Convert.ToDouble( MarkerValue )/Convert.ToDouble( MaxValue );
double markerX1 = 0.5*_rectangle.Width*(1 + frac);
Point p0 = new Point( markerX1, 0 );
Point p1 = new Point( markerX1, _rectangle.Height );
drawingContext.DrawLine( _markerPen, p0, p1 );
double markerX2 = 0.5*_rectangle.Width*(1 - frac);
Point p2 = new Point( markerX2, 0 );
Point p3 = new Point( markerX2, _rectangle.Height );
drawingContext.DrawLine( _markerPen, p2, p3 );
}
else
{
double markerX = (_rectangle.Width*MarkerValue)/(MaxValue - MinValue);
Point p0 = new Point( markerX, 0 );
Point p1 = new Point( markerX, _rectangle.Height );
drawingContext.DrawLine( _markerPen, p0, p1 );
}
}
// Border.
drawingContext.DrawRectangle(null, _borderPen, _rectangle);
// Text.
if (ShowValue)
{
FormattedText text = new FormattedText( value.ToString(), CultureInfo.CurrentCulture,
FlowDirection.LeftToRight, s_typeface, 12, _textBrush );
Point pos = new Point( (_rectangle.Width - text.Width)/2, (_rectangle.Height - text.Height)/2 );
drawingContext.DrawText( text, pos );
}
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
_rectangle = new Rect( sizeInfo.NewSize );
InvalidateVisual();
}
private int clamp(int value)
{
return (value < MinValue ? MinValue : value > MaxValue ? MaxValue : value);
}
private void reassertValues()
{
// Make sure max and min are correct.
int oldMin = MinValue;
int newMin = oldMin;
int oldMax = MaxValue;
int newMax = oldMax;
if (oldMin > oldMax)
{
newMin = oldMax;
newMax = oldMin;
}
if (newMin != oldMin)
{
SetValue(MinValueProperty, newMin);
}
if (newMax != oldMax)
{
SetValue(MaxValueProperty, newMax);
}
// Make sure value is in [min,max].
int oldValue = Value;
int newValue = clamp(oldValue);
if (newValue != oldValue)
{
Value = newValue;
}
// Make sure marker is correctly placed.
int marker = MarkerValue;
if (marker >= 0)
{
int newMarker = clamp(marker);
if (newMarker != marker)
{
SetValue(MarkerValueProperty, newMarker);
}
}
}
private Pen _borderPen;
private Pen _markerPen;
private Brush _barBrush;
private Brush _bodyBrush;
private Rect _rectangle;
private Brush _textBrush;
private static readonly Typeface s_typeface = new Typeface( "Verdana" );
}
}
这是绑定它的XAML:
<controls:HorizontalBarGauge Grid.Row="1" Grid.Column="1"
Margin="8" Width="130" Height="18"
IsSigned="False"
MinValue="0"
MaxValue="100"
BorderThickness="2"
BorderColor="MidnightBlue"
ShowValue="True"
Value="{Binding StepperPosition}"
/>
当控件初始化时,控件显示正确的值。但是当我在以后的代码中更改“StepperPosition”属性时,没有任何变化。对代码进行断点显示,即使StepperPosition执行并触发OnPropertyChanged(“StepperPosition”),也不会调用ValueProperty setter。 INPC属于基类。所以我想我已经排除了绑定的通常原因而不是令人耳目一新,现在我有点难过了。
星期一。对,转了一下。现在可以通过挂钩DepedencyPropertyChanged回调来刷新视觉效果。 @HighCore这就是他们的样子:
条形图有两种模式:速度(需要+/-)和位置(总是+ ve)。速度表中的红线显示其他地方设置的最大速度。它们是近实时更新的,因为它们是步进电机状态的指标。