我在MVVM模式项目中使用了此custom control的改编版本 校准微观框架。
<gauge:STGaugeControl x:Name="Gauge"
Radius="120"
ScaleRadius="105"
ScaleStartAngle="120"
ResetPointer1OnStartUp="True"
ScaleSweepAngle="300"
Pointer1Length="95"
Pointer2Length="95"
Pointer3Length="95"
PointerCapRadius="25"
MinValue="{Binding MinGauge, FallbackValue=-6000}"
MaxValue="{Binding MaxGauge, FallbackValue=6000}"
MajorDivisionsCount="{Binding DivCount, FallbackValue=12}"
MinorDivisionsCount="5"
CurrentValue1="{Binding Value1}"
CurrentValue2="{Binding Value2}"
CurrentValue3="{Binding Value3}"
ScaleLabelRadius="80"
...
>
这是我的观点的一部分。现在,当代码运行时,值将被绑定并按预期工作。但是,缩放是在自定义控件的OnApplyTemplate()中调用的方法中绘制的,并且由于某种原因无法访问绑定值。当我删除回退时,它使用FallbackValue或默认的零值。
例如,当我使用鼠标悬停在事件上时调用缩放绘制方法时,它按预期工作。
是否早期调用OnApplyTemplate()来访问绑定值,还是在我的所有教程中还有其他错误和错过的内容?
自定义控制代码
[TemplatePart(Name = "LayoutRoot", Type = typeof(Grid))]
[TemplatePart(Name = "Pointer1", Type = typeof(Path))]
[TemplatePart(Name = "Pointer2", Type = typeof(Path))]
[TemplatePart(Name = "Pointer3", Type = typeof(Path))]
[TemplatePart(Name = "RangeIndicatorLight", Type = typeof(Ellipse))]
[TemplatePart(Name = "PointerCap", Type = typeof(Ellipse))]
public class STGaugeControl : Control
{
#region Private variables
private Grid rootGrid;
*snip*
#region Dependency properties
public static readonly DependencyProperty MinValueProperty =
DependencyProperty.Register("MinValue", typeof(double), typeof(STGaugeControl), null);
public static readonly DependencyProperty MaxValueProperty =
DependencyProperty.Register("MaxValue", typeof(double), typeof(STGaugeControl), null);
public static readonly DependencyProperty MajorDivisionsCountProperty =
DependencyProperty.Register("MajorDivisionsCount", typeof(double), typeof(STGaugeControl), null);
public static readonly DependencyProperty MinorDivisionsCountProperty =
DependencyProperty.Register("MinorDivisionsCount", typeof(double), typeof(STGaugeControl), null);
*snip*
#region Wrapper properties
public double MinValue
{
get
{
return (double)GetValue(MinValueProperty);
}
set
{
SetValue(MinValueProperty, value);
}
}
public double MaxValue
{
get
{
return (double)GetValue(MaxValueProperty);
}
set
{
SetValue(MaxValueProperty, value);
}
}
*snip*
#region Constructor
static STGaugeControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(STGaugeControl), new FrameworkPropertyMetadata(typeof(STGaugeControl)));
}
#region Methods
private static void OnCurrentValue1PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Get access to the instance of CircularGaugeConrol whose property value changed
STGaugeControl gauge = d as STGaugeControl;
gauge.OnCurrentValue1Changed(e);
}
*snip*
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
//Get reference to known elements on the control template
rootGrid = GetTemplateChild("LayoutRoot") as Grid;
pointer1 = GetTemplateChild("Pointer1") as Path;
pointer2 = GetTemplateChild("Pointer2") as Path;
pointer3 = GetTemplateChild("Pointer3") as Path;
pointerCap = GetTemplateChild("PointerCap") as Ellipse;
lightIndicator = GetTemplateChild("RangeIndicatorLight") as Ellipse;
//Draw scale and range indicator
DrawScale();
//Set Zindex of pointer and pointer cap to a really high number so that it stays on top of the
//scale and the range indicator
Canvas.SetZIndex(pointer1, 100001);
Canvas.SetZIndex(pointer2, 100002);
Canvas.SetZIndex(pointer3, 100003);
Canvas.SetZIndex(pointerCap, 100005);
if (ResetPointer1OnStartUp)
{
//Reset Pointer
MovePointer1(ScaleStartAngle);
}
if (ResetPointer2OnStartUp)
{
//Reset Pointer
MovePointer2(ScaleStartAngle);
}
if (ResetPointer3OnStartUp)
{
//Reset Pointer
MovePointer3(ScaleStartAngle);
}
}
*snip*
//Drawing the scale with the Scale Radius
public void DrawScale()
{
//Calculate one major tick angle
Double majorTickUnitAngle = ScaleSweepAngle / MajorDivisionsCount;
//Obtaining One minor tick angle
Double minorTickUnitAngle = ScaleSweepAngle / MinorDivisionsCount;
//Obtaining One major ticks value
Double majorTicksUnitValue = (MaxValue - MinValue) / MajorDivisionsCount;
majorTicksUnitValue = Math.Round(majorTicksUnitValue, ScaleValuePrecision);
Double minvalue = MinValue; ;
// Drawing Major scale ticks
for (Double i = ScaleStartAngle; i <= (ScaleStartAngle + ScaleSweepAngle); i = i + majorTickUnitAngle)
{
//Majortick is drawn as a rectangle
Rectangle majortickrect = new Rectangle();
majortickrect.Height = MajorTickSize.Height;
majortickrect.Width = MajorTickSize.Width;
majortickrect.Fill = new SolidColorBrush(MajorTickColor);
Point p = new Point(0.5, 0.5);
majortickrect.RenderTransformOrigin = p;
majortickrect.HorizontalAlignment = HorizontalAlignment.Center;
majortickrect.VerticalAlignment = VerticalAlignment.Center;
TransformGroup majortickgp = new TransformGroup();
RotateTransform majortickrt = new RotateTransform();
//Obtaining the angle in radians for calulating the points
Double i_radian = (i * Math.PI) / 180;
majortickrt.Angle = i;
majortickgp.Children.Add(majortickrt);
TranslateTransform majorticktt = new TranslateTransform();
//Finding the point on the Scale where the major ticks are drawn
//here drawing the points with center as (0,0)
majorticktt.X = (int)((ScaleRadius) * Math.Cos(i_radian));
majorticktt.Y = (int)((ScaleRadius) * Math.Sin(i_radian));
//Points for the textblock which hold the scale value
TranslateTransform majorscalevaluett = new TranslateTransform();
//here drawing the points with center as (0,0)
majorscalevaluett.X = (int)((ScaleLabelRadius) * Math.Cos(i_radian));
majorscalevaluett.Y = (int)((ScaleLabelRadius) * Math.Sin(i_radian));
//Defining the properties of the scale value textbox
TextBlock tb = new TextBlock();
tb.Height = ScaleLabelSize.Height;
tb.Width = ScaleLabelSize.Width;
tb.FontSize = ScaleLabelFontSize;
tb.Foreground = new SolidColorBrush(ScaleLabelForeground);
tb.TextAlignment = TextAlignment.Center;
tb.VerticalAlignment = VerticalAlignment.Center;
tb.HorizontalAlignment = HorizontalAlignment.Center;
//Writing and appending the scale value
//checking minvalue < maxvalue w.r.t scale precion value
if (Math.Round(minvalue, ScaleValuePrecision) <= Math.Round(MaxValue, ScaleValuePrecision))
{
minvalue = Math.Round(minvalue, ScaleValuePrecision);
tb.Text = minvalue.ToString();
minvalue = minvalue + majorTicksUnitValue;
}
else
{
break;
}
majortickgp.Children.Add(majorticktt);
majortickrect.RenderTransform = majortickgp;
tb.RenderTransform = majorscalevaluett;
rootGrid.Children.Add(majortickrect);
rootGrid.Children.Add(tb);
//Drawing the minor axis ticks
Double onedegree = ((i + majorTickUnitAngle) - i) / (MinorDivisionsCount);
if ((i < (ScaleStartAngle + ScaleSweepAngle)) && (Math.Round(minvalue, ScaleValuePrecision) <= Math.Round(MaxValue, ScaleValuePrecision)))
{
//Drawing the minor scale
for (Double mi = i + onedegree; mi < (i + majorTickUnitAngle); mi = mi + onedegree)
{
//here the minortick is drawn as a rectangle
Rectangle mr = new Rectangle();
mr.Height = MinorTickSize.Height;
mr.Width = MinorTickSize.Width;
mr.Fill = new SolidColorBrush(MinorTickColor);
mr.HorizontalAlignment = HorizontalAlignment.Center;
mr.VerticalAlignment = VerticalAlignment.Center;
Point p1 = new Point(0.5, 0.5);
mr.RenderTransformOrigin = p1;
TransformGroup minortickgp = new TransformGroup();
RotateTransform minortickrt = new RotateTransform();
minortickrt.Angle = mi;
minortickgp.Children.Add(minortickrt);
TranslateTransform minorticktt = new TranslateTransform();
//Obtaining the angle in radians for calulating the points
Double mi_radian = (mi * Math.PI) / 180;
//Finding the point on the Scale where the minor ticks are drawn
minorticktt.X = (int)((ScaleRadius) * Math.Cos(mi_radian));
minorticktt.Y = (int)((ScaleRadius) * Math.Sin(mi_radian));
minortickgp.Children.Add(minorticktt);
mr.RenderTransform = minortickgp;
rootGrid.Children.Add(mr);
}
}
}
}
}
}
Generic.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SpeedTorque">
*snip*
<Style TargetType="local:STGaugeControl" >
<Setter Property="ResetPointer1OnStartUp" Value="True" />
<Setter Property="ResetPointer2OnStartUp" Value="True" />
<Setter Property="ResetPointer3OnStartUp" Value="True" />
<Setter Property="ScaleValuePrecision" Value="5" />
*snip*
<Setter Property="GaugeBackgroundColor" Value="Black" />
<Setter Property="DialTextColor" Value="White" />
<Setter Property="DialTextFontSize" Value="8" />
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="local:STGaugeControl">
<!-- Root Grid-->
<Grid x:Name="LayoutRoot"
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource radiusToDiameterConverter}}"
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource radiusToDiameterConverter}}" >
<Ellipse x:Name="OuterFrame" StrokeThickness="8"
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource radiusToDiameterConverter}}"
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource radiusToDiameterConverter}}"
Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=GaugeBackgroundColor, Converter={StaticResource backgroundColorConverter}}">
<Ellipse.Stroke>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF636060" Offset="1"/>
<GradientStop Color="#FF5F5C5C" Offset="0"/>
<GradientStop Color="#FFEEDEDE" Offset="0.35"/>
<GradientStop Color="#FFA09595" Offset="0.705"/>
</LinearGradientBrush>
</Ellipse.Stroke>
</Ellipse>
*snip*
<!-- Pointer1 -->
<Path x:Name="Pointer1" Stroke="#FFE91C1C" StrokeThickness="2"
Width="{TemplateBinding Pointer1Length}"
Height="{TemplateBinding Pointer1Thickness}" HorizontalAlignment="Center"
Data="M1,1 L1,10 L156,6 z" Stretch="Fill" RenderTransformOrigin="0,0.5"
RenderTransform="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=Pointer1Length, Converter={StaticResource pointerCenterConverter}}"
Visibility="{TemplateBinding Pointer2Visibility}" >
<Path.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#33890A0A" Offset="0.197"/>
<GradientStop Color="#33C40808" Offset="1"/>
<GradientStop Color="#33E32323" Offset="0.61"/>
</LinearGradientBrush>
</Path.Fill>
</Path>
*snip*
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
答案 0 :(得分:0)
我觉得您需要将您的比例绑定到VM属性,并在每次更改它所依赖的参数时重新计算它。 我想每次将新值设置为MinGauge或MaxGauge时,您都需要更新VM中的Scale属性。