|
|
Comments and Discussions
|
|
 |

|
Thank you for your useful and nice Control
|
|
|
|

|
Very nice circular gauge article.
Just because the code works, it doesn't mean that it is good code.
|
|
|
|

|
I implement this control in my project.
the designer mode display the gauge but when i execute the code i have the XamlParseException.
I don't inderstand the wrong
thank you again for your solution. I hope to have an anwser
thank you
|
|
|
|

|
Hi, thank you very much for this nice Control!
I have a problem to set a Start Value for the Pointer. When my CurrentValue for the Pointer is at Application startup at 1000 the Pointer shows to 0 because the Storyboard isnt started.
Does anyone have an Idea how to fix this?
|
|
|
|

|
please help ,
how binding with Min/Max
thx
|
|
|
|

|
I wrote a method to refresh the scale at runtime.
public void RefreshScale()
{
rootGrid = GetTemplateChild("LayoutRoot") as Grid;
for (int i = rootGrid.Children.Count - 1; i >= 0 ; i-- )
{
TextBlock textblock = rootGrid.Children[i] as TextBlock;
if (textblock != null) {
if(textblock.Text != this.DialText) rootGrid.Children.Remove(textblock);
continue;
}
Rectangle rectangle = rootGrid.Children[i] as Rectangle;
if (rectangle != null) {
rootGrid.Children.Remove(rectangle);
continue;
}
}
this.OnApplyTemplate();
}
|
|
|
|

|
There is a bug in this code when the drawing the optimal range if the difference between MinValue and MaxValue is less than 1.0. So, for example, if you need a gauge where the MinValue is 0.05 and the MaxValue is 0.10, and your optimal range is 0.075 to 0.080, it will not draw your optimal range correctly.
The fix is in the DrawRangeIndicator function, in that it needs to scale some of the calculations in this case. I have posted an updated function below.
private void DrawRangeIndicator()
{
Double rangediff = MaxValue - MinValue;
Double realworldunit = (ScaleSweepAngle / rangediff);
Double optimalStartAngle;
Double optimalEndAngle;
double db;
double tmprangediff = rangediff;
for (int i = 1; i <= ScaleValuePrecision; i++)
{
if (tmprangediff < 1)
{
tmprangediff *= 10;
realworldunit /= 10;
}
else
{
break;
}
}
if (OptimalRangeStartValue < 0)
{
db = MinValue + Math.Abs(OptimalRangeStartValue);
optimalStartAngle = ((double)(Math.Abs(db * realworldunit)));
}
else
{
db = OptimalRangeStartValue - MinValue;
optimalStartAngle = ((double)(db * realworldunit));
}
if (OptimalRangeEndValue < 0)
{
db = MinValue + Math.Abs(OptimalRangeEndValue);
optimalEndAngle = ((double)(Math.Abs(db * realworldunit)));
}
else
{
db = OptimalRangeEndValue - MinValue;
optimalEndAngle = ((double)(db * realworldunit));
}
tmprangediff = rangediff;
for (int i = 1; i <= ScaleValuePrecision; i++)
{
if (tmprangediff < 1)
{
tmprangediff *= 10;
optimalStartAngle *= 10;
optimalEndAngle *= 10;
}
else
{
break;
}
}
Double optimalStartAngleFromStart = (ScaleStartAngle + optimalStartAngle);
Double optimalEndAngleFromStart = (ScaleStartAngle + optimalEndAngle);
arcradius1 = (RangeIndicatorRadius + RangeIndicatorThickness);
arcradius2 = RangeIndicatorRadius;
double endAngle = ScaleStartAngle + ScaleSweepAngle;
Point A = GetCircumferencePoint(ScaleStartAngle, arcradius1);
Point B = GetCircumferencePoint(ScaleStartAngle, arcradius2);
Point C = GetCircumferencePoint(optimalStartAngleFromStart, arcradius2);
Point D = GetCircumferencePoint(optimalStartAngleFromStart, arcradius1);
bool isReflexAngle = Math.Abs(optimalStartAngleFromStart - ScaleStartAngle) > 180.0;
DrawSegment(A, B, C, D, isReflexAngle, BelowOptimalRangeColor);
Point A1 = GetCircumferencePoint(optimalStartAngleFromStart, arcradius1);
Point B1 = GetCircumferencePoint(optimalStartAngleFromStart, arcradius2);
Point C1 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius2);
Point D1 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius1);
bool isReflexAngle1 = Math.Abs(optimalEndAngleFromStart - optimalStartAngleFromStart) > 180.0;
DrawSegment(A1, B1, C1, D1, isReflexAngle1, OptimalRangeColor);
Point A2 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius1);
Point B2 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius2);
Point C2 = GetCircumferencePoint(endAngle, arcradius2);
Point D2 = GetCircumferencePoint(endAngle, arcradius1);
bool isReflexAngle2 = Math.Abs(endAngle - optimalEndAngleFromStart) > 180.0;
DrawSegment(A2, B2, C2, D2, isReflexAngle2, AboveOptimalRangeColor);
}
|
|
|
|

|
Dim NewGrid1 As New Grid
NewGrid1.Name = "NewGrid1"
Dim NewKpi As New CircularGauge.CircularGaugeControl
With (NewKpi)
.Name = "NewKpi1"
.Radius = 150
.ScaleRadius = 110
.ScaleStartAngle = 120
.ScaleSweepAngle = 300
.PointerLength = 85
.PointerCapRadius = 35
.MinValue = 0
.MaxValue = 1000
.MajorDivisionsCount = 10
.MinorDivisionsCount = 5
.CurrentValue = 0
.ImageSize = New System.Windows.Size(40, 50)
.RangeIndicatorThickness = 8
.RangeIndicatorRadius = 120
.RangeIndicatorLightRadius = 10
.RangeIndicatorLightOffset = 80
.ScaleLabelRadius = 90
.ScaleLabelSize = New System.Windows.Size(40, 20)
.ScaleLabelFontSize = "10"
.ScaleLabelForeground = myGauge1.ScaleLabelForeground
.MajorTickSize = New System.Windows.Size(10, 3)
.MinorTickSize = New System.Windows.Size(3, 1)
.MajorTickColor = myGauge1.MajorTickColor
.MinorTickColor = myGauge1.MinorTickColor
.ImageOffset = "-50"
.GaugeBackgroundColor = myGauge1.GaugeBackgroundColor
.PointerThickness = "16"
.OptimalRangeStartValue = "300"
.OptimalRangeEndValue = "700"
.DialTextOffset = "40"
.DialText = "TextHere"
.DialTextColor = myGauge1.DialTextColor
End With
Dim Fuente1 As New FuenteDatosGauge
NewKpi.DataContext = Fuente1
Dim Bind As New Binding
Bind.Source = Fuente1
Bind.Path = New PropertyPath("ValorActual1")
NewKpi.SetBinding(CircularGauge.CircularGaugeControl.CurrentValueProperty, Bind)
Dim FinalValue As Decimal
FinalValue = Math.Round(250, 2)
Fuente1.ValorActual1 = FinalValue
NewKpi.DialText = FinalValue
|
|
|
|

|
dim MyGauge As CircularGauge.CircularGaugeControldim
and so on...
|
|
|
|

|
XAML & WPF newb here.
I'm having the same issues in C#.
I can get the grid to appear and run if I add it in designer view and XAML, but not if i try to do ti programaticaly in the xaml.c# code view.
CircularGaugeControl gauge = new CircularGaugeControl();
gauge.ScaleLabelFontSize = 10; Grid.SetRow(gauge, 1);
grid1.Children.Add(gauge);
The rest of the code compiles and runs, but still not getting the grid to appear.
Any help or suggestions would be appreciated.
EDIT
I ended up initializing values of the gauge and am starting to see it show.
CircularGaugeControl gauge = new CircularGaugeControl();
gauge.ScaleLabelFontSize = 10;
gauge.Radius = 150;
gauge.ScaleRadius= 110;
gauge.ScaleStartAngle = 120;
etc. etc.
now to read the thread on data binding.
modified 25-Jun-12 14:15pm.
|
|
|
|
|

|
I'm trying to get this to work in Visual Studio 2010 with silverlight 4, I'm sure this "should" work, just would like a confirmation...
|
|
|
|

|
Hi
Range is covering whole circle for some particular Max and Min Value.
If i set Max = 20 and Min = -200 and want to draw range from -200 to 20 (using Arc) then angle is dropped instead covering the circle.
|
|
|
|

|
Hi EvelynT,
I am using your gauge control, a nice application. In my project I want to split a gauge into three parts (one part to show gas left over, one for coolant, one for temperature). Each part should show the indicator by color change with out any pointer. Would you please guide me for this task.
Thanks
Reddy
|
|
|
|

|
Hi
Im using and testing this gauge control and it is pretty nice. How must I do it, when I want to change MaxValue, OptimalRangeStartValue and OptimalRangeEndValue on Runtime?
If I only change the properties nothing happens.
Thanks for the help!
|
|
|
|

|
1、 As described by GaborTorok, 2:02 10 Feb '10
The DrawRangeIndicator() function, that works for me is included below.
//double db;
////Checking whether the OptimalRangeStartvalue is -ve
//if (OptimalRangeStartValue < 0)
//{
// db = MinValue + Math.Abs(OptimalRangeStartValue);
// optimalStartAngle = ((double)(Math.Abs(db * realworldunit)));
//}
//else
//{
// db = Math.Abs(MinValue) + OptimalRangeStartValue;
// optimalStartAngle = ((double)(db * realworldunit));
//}
optimalStartAngle = realworldunit * (OptimalRangeStartValue - MinValue);
////Checking whether the OptimalRangeEndvalue is -ve
//if (OptimalRangeEndValue < 0)
//{
// db = MinValue + Math.Abs(OptimalRangeEndValue);
// optimalEndAngle = ((double)(Math.Abs(db * realworldunit)));
//}
//else
//{
// db = Math.Abs(MinValue) + OptimalRangeEndValue;
// optimalEndAngle = ((double)(db * realworldunit));
//}
// calculating the angle for optimal Start value
optimalEndAngle = realworldunit * (OptimalRangeEndValue - MinValue);
2、The OnCurrentValueChanged() Function ,should be modified as below:
if (pointer != null)
{
//double db1 = 0;
Double oldcurr_realworldunit = 0;
Double newcurr_realworldunit = 0;
Double realworldunit = (ScaleSweepAngle / (MaxValue - MinValue));
//Resetting the old value to min value the very first time.
if (oldValue == 0 && !isInitialValueSet)
{
oldValue = MinValue;
isInitialValueSet = true;
}
//if (oldValue < 0)
//{
// db1 = MinValue + Math.Abs(oldValue);
// oldcurr_realworldunit = ((double)(Math.Abs(db1 * realworldunit)));
//}
//else
//{
// db1 = Math.Abs(MinValue) + oldValue;
// oldcurr_realworldunit = ((double)(db1 * realworldunit));
//}
//Add one line
oldcurr_realworldunit = ((double)(realworldunit) *(oldValue-MinValue));
//if (newValue < 0)
//{
// db1 = MinValue + Math.Abs(newValue);
// newcurr_realworldunit = ((double)(Math.Abs(db1 * realworldunit)));
//}
//else
//{
// db1 = Math.Abs(MinValue) + newValue;
// newcurr_realworldunit = ((double)(db1 * realworldunit));
//}
//Add one line
newcurr_realworldunit = ((double)(realworldunit)*(newValue-MinValue));
Double oldcurrentvalueAngle = (ScaleStartAngle + oldcurr_realworldunit);
Double newcurrentvalueAngle = (ScaleStartAngle + newcurr_realworldunit);
//Animate the pointer from the old value to the new value
AnimatePointer(oldcurrentvalueAngle, newcurrentvalueAngle);
}
|
|
|
|

|
thank you for sharing your code. i am also trying to write some custom controls for one of my projects. Your code will help me a lot in finding the answer to some questions i have.
|
|
|
|

|
I have added a property ThickenessExsternalEllipse to control the thickness of the gauge border.
In generic.xaml I changed the StrokeThickess property
<Ellipse x:Name="OuterFrame" StrokeThickness="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ThickenessExsternalEllipse}"
Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource radiusToDiameterConverter}}"
Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Radius, Converter={StaticResource radiusToDiameterConverter}}"
...
In CircularGauceControl.cs I added the DependecyProperty ThickenessExsternalEllipseProperty
public static readonly DependencyProperty ThickenessExsternalEllipseProperty =
DependencyProperty.Register("ThickenessExsternalEllipse", typeof(int), typeof(CircularGaugeControl), null);
...
public int ThickenessExsternalEllipse
{
get
{
return (int)GetValue(ThickenessExsternalEllipseProperty);
}
set
{
SetValue(ThickenessExsternalEllipseProperty, value);
}
}
Enrico Oliva
|
|
|
|

|
Is it true it is not possible to change the properties ScaleRadius, ScaleLabelRadius, RangeIndicatorRadius while running the application.
|
|
|
|

|
Thanks a lot for this uber cool gauge control. You're the MAN!
|
|
|
|

|
Hi,
I use this control in Silverlight but I've tried to bind the MaxValue (by the MVVM pattern) but it doesn't work. How do it ?
|
|
|
|

|
Solves a display problem for me quickly and easily--elegant and flexible gadget.
modified on Sunday, August 29, 2010 1:16 PM
|
|
|
|

|
Evelyn,
First - I must say that this is an AWESOME control. Congrats for this. Now, on to my problem....
I am trying to use this as a WPF control using just the .dll. I need to use this outside of Visual Studio. As a test in Visual Studio, I attempted to use the WPF control by referencing the dll in a new VS C# project (works fine), adding the control to the toolkit (works fine), and then dragging and dropping the control onto the form (boom!!). I get a dialog box complaining about the font size of "0".
What am I missing?? Have you heard of this issue before?
Thank in advance for your help, and for a great control!!
Jamie
|
|
|
|

|
Hi Jamie,
I also had this error, I noticed that if I changed this function a little (basically tell it that if font size is 0 then default to 10.
private void DrawScale()
{
Double majorTickUnitAngle = ScaleSweepAngle / MajorDivisionsCount;
Double minorTickUnitAngle = ScaleSweepAngle / MinorDivisionsCount;
Double majorTicksUnitValue = (MaxValue - MinValue) / MajorDivisionsCount;
majorTicksUnitValue = Math.Round(majorTicksUnitValue, ScaleValuePrecision);
Double minvalue = MinValue; ;
for (Double i = ScaleStartAngle; i <= (ScaleStartAngle + ScaleSweepAngle); i = i + majorTickUnitAngle)
{
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();
Double i_radian = (i * Math.PI) / 180;
majortickrt.Angle = i;
majortickgp.Children.Add(majortickrt);
TranslateTransform majorticktt = new TranslateTransform();
majorticktt.X = (int)((ScaleRadius) * Math.Cos(i_radian));
majorticktt.Y = (int)((ScaleRadius) * Math.Sin(i_radian));
TranslateTransform majorscalevaluett = new TranslateTransform();
majorscalevaluett.X = (int)((ScaleLabelRadius) * Math.Cos(i_radian));
majorscalevaluett.Y = (int)((ScaleLabelRadius) * Math.Sin(i_radian));
TextBlock tb = new TextBlock();
tb.Height = ScaleLabelSize.Height;
tb.Width = ScaleLabelSize.Width;
if (ScaleLabelFontSize < 1)
{
tb.FontSize = 10;
}
else
{
tb.FontSize = ScaleLabelFontSize;
}
tb.Foreground = new SolidColorBrush(ScaleLabelForeground);
tb.TextAlignment = TextAlignment.Center;
tb.VerticalAlignment = VerticalAlignment.Center;
tb.HorizontalAlignment = HorizontalAlignment.Center;
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);
Double onedegree = ((i + majorTickUnitAngle) - i) / (MinorDivisionsCount);
if ((i < (ScaleStartAngle + ScaleSweepAngle)) && (Math.Round(minvalue, ScaleValuePrecision) <= Math.Round(MaxValue, ScaleValuePrecision)))
{
for (Double mi = i + onedegree; mi < (i + majorTickUnitAngle); mi = mi + onedegree)
{
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();
Double mi_radian = (mi * Math.PI) / 180;
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);
}
}
}
}
Doing that and rebuilding seemed to allow me to drag the control onto the WPF.
Problem being is that once you drag it on, nothing shows up. You need to set all the values in XAML.
Try setting them with...
<my:CircularGaugeControl x:Name="myGauge1" Radius="150"
ScaleRadius="110"
ScaleStartAngle="120"
ScaleSweepAngle="300"
PointerLength="85"
PointerCapRadius="35"
MinValue="0"
MaxValue="1000"
MajorDivisionsCount="10"
MinorDivisionsCount="5"
CurrentValue="{Binding Score}"
ImageSource="windowslogo.png"
ImageSize="40,50"
RangeIndicatorThickness="8"
RangeIndicatorRadius="120"
RangeIndicatorLightRadius="10"
RangeIndicatorLightOffset="80"
ScaleLabelRadius="90"
ScaleLabelSize="40,20"
ScaleLabelFontSize="10"
ScaleLabelForeground="LightGray"
MajorTickSize="10,3"
MinorTickSize="3,1"
MajorTickColor="LightGray"
MinorTickColor="LightGray"
ImageOffset="-50"
GaugeBackgroundColor="Black"
PointerThickness ="16"
OptimalRangeStartValue="300"
OptimalRangeEndValue="700"
DialTextOffset="40"
DialText="Black"
DialTextColor="Black" Margin="-46,-38,-42,-33">
</my:CircularGaugeControl>
Thats as far as I have got so far.
Love the control though! Very good looking!
|
|
|
|

|
Hi I like to use this in windows 8 , when I tried it is showing some type initialization exception in the generic.xaml which makes it difficult to use. is it possible for you to port in to windows 8 or fix the error and post it
dheeraj
|
|
|
|

|
For some reason I am unable to find the .dll in order to reference it...can anybody help? Where do I download it from?
|
|
|
|

|
I have a requirement to make this dial as hyperlink , so if user clicks on this dial needs to navigate to other page.Plz help me.
|
|
|
|

|
I think the live demo link needs updating? Possibly linking to the SL3 runtime? Controls look nice, will give them a run.
Best wishes
Jerry
|
|
|
|

|
Binding to CurrentValue (or just setting any value to it) does not work in my application. Upon debugging, I found out that the needle does not move because the pointer object is null when the code reaches AnimatePointer:
void AnimatePointer(double oldcurrentvalueAngle, double newcurrentvalueAngle)
{
if (pointer != null)
Also, I found out that OnApplyTemplate (where the pointer object is created) only fires after the AnimatePointer method is called (which explains why pointer was null?).
Other than that, the control looks very nice!
maybe one other thing to improve is to use default values for the dependencyproperties, so the control does not crash if you do not provide them and you do not have to specify so much in xaml.
|
|
|
|

|
Hi, fisrt very good work, very nice result!
i would like to know how to rezie a gauge?
|
|
|
|

|
I found that you need to adjust the radius and related values in the Gauge.xaml
Thanks
|
|
|
|

|
can you be more specific please? I have tried to modified those but the result is... weird...
what are the properties I have to change and should I change them in proportion or in delta difference? meaning if I reduce the radius from 150 to 100 do I reduce the other with 50 or with 30%?
|
|
|
|

|
Hello, contratulations for this sample.
With below scenario the RangeIndicator Bellow Optimal and Above Optimal lines are drawn wrong.
<gauge:CircularGaugeControl x:Name="myGauge2" Grid.Column="1" Grid.Row="0"
Radius="150"
ScaleRadius="100"
ScaleStartAngle="140"
ScaleSweepAngle="270"
PointerLength="90"
PointerCapRadius="35"
MinValue="30"
MaxValue="35"
MajorDivisionsCount="10"
MinorDivisionsCount="5"
OptimalRangeEndValue="32"
OptimalRangeStartValue="31"
CurrentValue="{Binding Score}"
ImageSource="windowslogo.png"
ImageSize="40,50"
RangeIndicatorThickness="9"
RangeIndicatorRadius="80"
RangeIndicatorLightRadius="10"
RangeIndicatorLightOffset="80"
ScaleLabelRadius="115"
ScaleLabelSize="40,20"
ScaleLabelFontSize="10"
ScaleLabelForeground="White"
MajorTickSize="10,3"
MinorTickSize="3,1"
MajorTickColor="White"
MinorTickColor="LightGray"
ImageOffset="-50"
GaugeBackgroundColor="CornflowerBlue"
PointerThickness ="5"
DialTextOffset="40"
DialText="Aqua Blue"
DialTextColor="DarkBlue"
/>
Here is the result image: http://dl.dropbox.com/u/3763901/gaugeError.PNG[^]
Any way how to solve this?
|
|
|
|

|
Did you have any luck resolving the drawing problem?
|
|
|
|

|
No
|
|
|
|

|
hi,
This is a quick solution that has been tested with the test cases listed below. The approach is to make calculations as if the Min value is always zero. Add/Modify the following code segment on this function:
CircularGauge.CircularGaugeControl.DrawRangeIndicator
Double tmpMaxValue = (MaxValue - MinValue); Double tmpStartValue = Math.Abs(OptimalRangeStartValue - MinValue); Double tmpEndValue = Math.Abs(OptimalRangeEndValue - MinValue);
Double realworldunit = (ScaleSweepAngle / tmpMaxValue);
Double optimalStartAngle = ((double)(tmpStartValue * realworldunit));
Double optimalEndAngle = ((double)(tmpEndValue * realworldunit));
Test Cases:
min,max,optimalStart, OptimalEnd
-10,10,2,4
-10,10,-5,-2
32,41,33,35
22000,38000,31600,34800
I hope this help.
|
|
|
|

|
Thank you for your help, but I cant put it working, maybe I missed something...
I get the same result gauge.
My result code is:
private void DrawRangeIndicator()
{
Double tmpMaxValue = (MaxValue - MinValue); Double tmpStartValue = Math.Abs(OptimalRangeStartValue - MinValue); Double tmpEndValue = Math.Abs(OptimalRangeEndValue - MinValue); Double realworldunit = (ScaleSweepAngle / tmpMaxValue);
Double optimalStartAngle = ((double)(tmpStartValue * realworldunit));
Double optimalEndAngle = ((double)(tmpEndValue * realworldunit));
double db;
if (OptimalRangeStartValue < 0)
{
db = MinValue + Math.Abs(OptimalRangeStartValue);
optimalStartAngle = ((double)(Math.Abs(db * realworldunit)));
}
else
{
db = Math.Abs(MinValue) + OptimalRangeStartValue;
optimalStartAngle = ((double)(db * realworldunit));
}
if (OptimalRangeEndValue < 0)
{
db = MinValue + Math.Abs(OptimalRangeEndValue);
optimalEndAngle = ((double)(Math.Abs(db * realworldunit)));
}
else
{
db = Math.Abs(MinValue) + OptimalRangeEndValue;
optimalEndAngle = ((double)(db * realworldunit));
}
Double optimalStartAngleFromStart = (ScaleStartAngle + optimalStartAngle);
Double optimalEndAngleFromStart = (ScaleStartAngle + optimalEndAngle);
arcradius1 = (RangeIndicatorRadius + RangeIndicatorThickness);
arcradius2 = RangeIndicatorRadius;
double endAngle = ScaleStartAngle + ScaleSweepAngle;
Point A = GetCircumferencePoint(ScaleStartAngle, arcradius1);
Point B = GetCircumferencePoint(ScaleStartAngle, arcradius2);
Point C = GetCircumferencePoint(optimalStartAngleFromStart, arcradius2);
Point D = GetCircumferencePoint(optimalStartAngleFromStart, arcradius1);
bool isReflexAngle = Math.Abs(optimalStartAngleFromStart - ScaleStartAngle) > 180.0;
DrawSegment(A, B, C, D, isReflexAngle, BelowOptimalRangeColor);
Point A1 = GetCircumferencePoint(optimalStartAngleFromStart, arcradius1);
Point B1 = GetCircumferencePoint(optimalStartAngleFromStart, arcradius2);
Point C1 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius2);
Point D1 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius1);
bool isReflexAngle1 = Math.Abs(optimalEndAngleFromStart - optimalStartAngleFromStart) > 180.0;
DrawSegment(A1, B1, C1, D1, isReflexAngle1, OptimalRangeColor);
Point A2 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius1);
Point B2 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius2);
Point C2 = GetCircumferencePoint(endAngle, arcradius2);
Point D2 = GetCircumferencePoint(endAngle, arcradius1);
bool isReflexAngle2 = Math.Abs(endAngle - optimalEndAngleFromStart) > 180.0;
DrawSegment(A2, B2, C2, D2, isReflexAngle2, AboveOptimalRangeColor);
}
maybe I missed something? where is the Min reset to zero?
|
|
|
|

|
The DrawRangeIndicator() function, that works for me is included below. I commented out the original code.
private void DrawRangeIndicator()
{
Double realworldunit = (ScaleSweepAngle / (MaxValue - MinValue));
Double optimalStartAngle;
Double optimalEndAngle;
optimalStartAngle = realworldunit * (OptimalRangeStartValue - MinValue);
optimalEndAngle = realworldunit * (OptimalRangeEndValue - MinValue);
Double optimalStartAngleFromStart = (ScaleStartAngle + optimalStartAngle);
Double optimalEndAngleFromStart = (ScaleStartAngle + optimalEndAngle);
arcradius1 = (RangeIndicatorRadius + RangeIndicatorThickness);
arcradius2 = RangeIndicatorRadius;
double endAngle = ScaleStartAngle + ScaleSweepAngle;
Point A = GetCircumferencePoint(ScaleStartAngle, arcradius1);
Point B = GetCircumferencePoint(ScaleStartAngle, arcradius2);
Point C = GetCircumferencePoint(optimalStartAngleFromStart, arcradius2);
Point D = GetCircumferencePoint(optimalStartAngleFromStart, arcradius1);
bool isReflexAngle = Math.Abs(optimalStartAngleFromStart - ScaleStartAngle) > 180.0;
DrawSegment(A, B, C, D, isReflexAngle, BelowOptimalRangeColor);
Point A1 = GetCircumferencePoint(optimalStartAngleFromStart, arcradius1);
Point B1 = GetCircumferencePoint(optimalStartAngleFromStart, arcradius2);
Point C1 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius2);
Point D1 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius1);
bool isReflexAngle1 = Math.Abs(optimalEndAngleFromStart - optimalStartAngleFromStart) > 180.0;
DrawSegment(A1, B1, C1, D1, isReflexAngle1, OptimalRangeColor);
Point A2 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius1);
Point B2 = GetCircumferencePoint(optimalEndAngleFromStart, arcradius2);
Point C2 = GetCircumferencePoint(endAngle, arcradius2);
Point D2 = GetCircumferencePoint(endAngle, arcradius1);
bool isReflexAngle2 = Math.Abs(endAngle - optimalEndAngleFromStart) > 180.0;
DrawSegment(A2, B2, C2, D2, isReflexAngle2, AboveOptimalRangeColor);
}
|
|
|
|

|
I want to modify the Min, Max and optimal range values at runtime using bindings; aim is to allow user to modify these values. Is it possible to do this? Has anyone tried doing this?
Any ideas, suggestions, comments...
|
|
|
|

|
I will also have to do modify them. I'll post my experiences here after I have a look at this. I'm new to WPF but my idea is that they can be modified but the gauge isn't redrawn, because there are no change handlers for these dependency properties.
|
|
|
|

|
Binding at build time in Silverlight 4 works (all code is from the downloadable sample), where I'm binding to a Parameter class that contains the referenced fields:
<gauge:CircularGaugeControl x:Name="myGauge1" Grid.Column="0" Grid.Row="0" Margin="5"
Radius="75"
: :
PointerCapRadius="10"
MinValue="{Binding Minimum}"
MaxValue="{Binding Maximum}"
MajorDivisionsCount="10"
: :
PointerThickness ="10"
OptimalRangeStartValue="{Binding OptimalRangeStart}"
OptimalRangeEndValue="{Binding OptimalRangeEnd}"
DialTextOffset="20"
DialText="{Binding Units}"
DialTextColor="Black"
></gauge:CircularGaugeControl>
There does seem to be a display problem in Silverlight 4 with this binding when the minimum value is not zero: both the range bands and pointer movement start getting strange. (You can see the new current value for each gauge in the demo by adding the line
DialText = newValue.ToString();
in OnCurrentValueChanged just after newValue is set.)
I'd like to suggest some small changes to CircularGaugeControl.cs to see what people think of them. They work nicely with the demo code as well as with my project, where I'm using ranges such as 1906..1980, -2..2, 65..300, etc.
There's a shared converter routine that the changes use. It involves redundant calculations, but it makes the changes clearer.
private double ValueToAngle(double value)
{
Double realworldunit = (ScaleSweepAngle / (MaxValue - MinValue));
double equivalentAngle = ScaleStartAngle + (value - MinValue) * realworldunit;
return equivalentAngle;
}
In OnCurrentValueChanged(), change the if (pointer != null) block to:
if (pointer != null)
{
AnimatePointer(ValueToAngle(oldValue), ValueToAngle(newValue));
}
Change the start of DrawRangeIndicator() to
private void DrawRangeIndicator()
{
Double optimalStartAngleFromStart = ValueToAngle(OptimalRangeStartValue);
Double optimalEndAngleFromStart = ValueToAngle(OptimalRangeEndValue);
arcradius1 = (RangeIndicatorRadius + RangeIndicatorThickness);
: :
On the purely stylistic side, I also changed OnApplyTemplate() so that the gauges start their display with their current value.
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
: :
Canvas.SetZIndex(pointerCap, 100001);
MovePointer(ScaleStartAngle);
AnimatePointer(ScaleStartAngle, ValueToAngle(CurrentValue));
}
modified on Sunday, August 15, 2010 5:17 PM
|
|
|
|

|
The solution to the strange RangeIndicator behaviour may be in my reply above to the post "problem with RangeIndicator".
For the binding part: if I remember well, I have solved the binding issue with WPF in .NET 3.5, but I have switched to another gauge, so I'll have to make a diff to see what changes I have made to the original code. When I have some time to do this, I'll share my enhacements.
|
|
|
|

|
Hi,
Has anyone else found this to consume huge amounts of CPU time ?? If so is there a way to fix it ?
I have this deployed on a test site and when the gauge is displayed, my CPU cycles goes to 100%. If I remove this control - I'm back down at a couple of % again.
Regards
Graham
|
|
|
|

|
This is really great, exactly what i was looking for.
I noticed a very small bug for the DialTextFontSize:
DependencyProperty.Register("DialTextFontSize", typeof(int)...
Should be a double:
DependencyProperty.Register("DialTextFontSize", typeof(double)...
(Also change the public property int DialTextFontSize to a double)
Thanks for this great control.
Greetings,
Patrick
|
|
|
|

|
Very good!! Thanks a lot to share with us!!
Gustavo Malheiros.
|
|
|
|

|
Hi,
The control is really excellent, but I need to apply different themes during run time. Is it possible?
Thanks in advance,
Matías
|
|
|
|

|
Yes. Remove the template, assign another one. Have onApplyTemplate() invoked. Worked for me. Actually, reassign the original template to have the whole control redrawn when I change the scale at run time (using a range slider).
|
|
|
|

|
Hi, thanks for this very cool control, I'm going to give it a try for my dashboard project.
cheers
sushibite
|
|
|
|

|
Hi EvelynT,
I found your control very use full but I would like add it from code behind but unable to do so.
I am getting emtpy gage with no MinValue or MaxValue and needle is always set to minValue.
here is my code.
this.myStackPanel.Children.Add(new CircularGaugeControl()
{
Radius = Convert.ToDouble(150),
ScaleRadius = Convert.ToDouble(110),
ScaleStartAngle = Convert.ToDouble(120),
ScaleSweepAngle = Convert.ToDouble(300),
PointerLength = Convert.ToDouble(85),
PointerCapRadius = Convert.ToDouble(35),
MinValue = Convert.ToDouble(0),
MaxValue = Convert.ToDouble(1000),
MajorDivisionsCount = Convert.ToDouble(10),
MinorDivisionsCount = Convert.ToDouble(5),
CurrentValue = Convert.ToDouble(50),
RangeIndicatorThickness = Convert.ToDouble(8),
RangeIndicatorRadius = Convert.ToDouble(120),
RangeIndicatorLightRadius = Convert.ToDouble(10),
RangeIndicatorLightOffset = Convert.ToDouble(80),
ScaleLabelRadius = Convert.ToDouble(90),
ScaleLabelSize = new Size(40, 20),
ScaleLabelFontSize = Convert.ToDouble(10),
ScaleLabelForeground = Colors.LightGray,
MajorTickSize = new Size(10, 3),
MinorTickSize = new Size(3, 1),
MajorTickColor = Colors.LightGray,
MinorTickColor = Colors.LightGray,
ImageOffset = Convert.ToDouble(-50),
GaugeBackgroundColor = Colors.LightGray,
PointerThickness = Convert.ToDouble(16),
OptimalRangeStartValue = Convert.ToDouble(300),
OptimalRangeEndValue = Convert.ToDouble(700),
DialTextOffset = Convert.ToDouble(40),
DialText = "Breach",
DialTextColor = Colors.Black
});
|
|
|
|

|
Please try changing the GaugeBackgroundColor to Colors.Black(any Dark Colors ) or
change the ScaleLabelForeground = Colors.Black,
MajorTickColor = Colors.Gray,
MinorTickColor = Colors.Gray,
also the needle or the pointer value is changed by the currentValue.
Thanks
|
|
|
|
 |
|
|
General News Suggestion Question Bug Answer Joke Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
An article on creating a circular gauge custom control for Silverlight 3.
| Type | Article |
| Licence | BSD |
| First Posted | 21 Jul 2009 |
| Views | 138,963 |
| Downloads | 8,343 |
| Bookmarked | 125 times |
|
|