Technorati-Tags:
telerik,
silverlight
In the first part of this series I describe the approach of this application.
The second part was about a class that reads server performance values.
The third part was about exposing the values.
In this part I’ll show how to consume the service.
For this I added a Silveright Application to my project.
Than I added a Service Reference to this application.
For test purposes I added the following code to my Page.xaml
<StackPanel Margin="6">
<Button Content="Get Values from Server" x:Name="btnTest" Click="btnTest_Click"/>
<TextBlock x:Name="txtErg" Text="??" Margin="0,3,0,0" />
</StackPanel>
The handler for the button looks like this:
private void btnTest_Click(object sender, RoutedEventArgs e) {
StartGetPerfInfos();
}
private void StartGetPerfInfos() {
if (m_bImInCall) { //one call is enough
return;
}
m_bImInCall = true; //we are on our way
try {
//use constructor with our endpoint
RefPerSvc.PerfSvcClient pC =
new SLPerfDisp.RefPerSvc.PerfSvcClient(new BasicHttpBinding(), m_epaServiceAddress);
//handler for the result - Silverlight==async :)
pC.GetPerfInfoCompleted +=
new EventHandler<SLPerfDisp.RefPerSvc.GetPerfInfoCompletedEventArgs>(pC_GetPerfInfoCompleted);
//start the call
pC.GetPerfInfoAsync();
//we are calling - and waiting for the result - adapt UI a little
btnTest.IsEnabled = false;
LastErg= "Calling Service - please wait";
}
catch (Exception eX) {
LastErg= eX.Message;
btnTest.IsEnabled = false;
m_bImInCall = false;
}
}
The button handler calls a function (I call this from another point also) which invokes the web service.
In Silverlight every service call is asynchronous – therefore I first add an event handler for the completed event and after this I call the service. LastErg is wired to txtErg.Text so it shows what’s going on in this textbox.
When the call is completed the event handler gets called – it looks like this:
void pC_GetPerfInfoCompleted(object sender, SLPerfDisp.RefPerSvc.GetPerfInfoCompletedEventArgs e) {
m_bImInCall = false; //done
btnTest.IsEnabled = true;
PerfInfos pI = e.Result;
//in producition environment check e.Error and e.Cancelled here also!!
if(pI.ErrMess=="OK") {
LastErg = string.Format("CPU: {0:0.00}% RAM - Total: {1}, Free: {2}, Used: {3} / {4:0.00}%",
pI.CPUPercent, pI.RamTotal, pI.RamFree, pI.RamUsed, pI.RamUsedPercent);
}
else{
LayoutRoot.DataContext = null;
LastErg="Error: " + pI.ErrMess;
}
}
This is simple – but it shows what’s going on.
The next step was to add some databinding.
<StackPanel Orientation="Horizontal">
<TextBlock Text="CPU used %:" HorizontalAlignment="Center" Margin="0,2,0,0" Foreground="White"/>
<TextBlock x:Name="txtCPUPercent"
Text="{Binding Path=CPUPercent}"
HorizontalAlignment="Center" Margin="3,2,0,0" FontWeight="Bold" Foreground="White"/>
</StackPanel>
</StackPanel>
And in code behind I changed the things to:
if(pI.ErrMess=="OK") {
//bind the object to the root grid
LayoutRoot.DataContext = pI;
...
Since LayoutRoot is the default grid which holds everything I bind the data to it.
BUT – the problem my text looks like 23,383847002 – not so good. Like usual in XAML there is an easy way out – a converter.
public class TwoDezimalDigitsConv : IValueConverter {
#region IValueConverter Member
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return ((double)value).ToString("0.00");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
#endregion
}
By the way – you don’t have to write it – add a class write : IValueConverter hit ALT+F10 and choose “implement IValueConverter”. VS does the rest – you only have to add a single line of code – return(…..
The next thing was to structure the UI a bit – I added some grid rows, a border for a “good looking” background and so on.
And than it comes to insert some Telerik things – I added three Gauge Controls.
This is done by dragging a control from the toolbox to the XAML – it adds the needed references by doing this.
Since the gauge is a very “I look what you like me to look” control you have to add some elements to make it look like you want.
The samples (or the online help) are good sources to give your Gauge Controls a good look.
It ended like this:
<control:RadGauge x:Name="radGaugeCPU" Width="100" Height="220" HorizontalAlignment="Stretch">
<gauge:LinearGauge Style="{StaticResource lgStyle1}">
<gauge:LinearScale x:Name="linearScaleCPU" Min="0" Max="100" MajorTickStep="20"
StrokeThickness="1" Top="0.05" Left="0.55" RelativeHeight="0.9" Width="Auto">
<gauge:LinearScale.MiddleTick>
<gauge:TickProperties Length="0.055"/>
</gauge:LinearScale.MiddleTick>
<gauge:LinearScale.MinorTick>
<gauge:TickProperties Length="0.0" />
</gauge:LinearScale.MinorTick>
<gauge:LinearScale.Label>
<gauge:LabelProperties FontSize="9" Location="Outside" />
</gauge:LinearScale.Label>
<gauge:RangeList>
<gauge:LinearRange Min="0" Max="60" StartWidth="0.04"
EndWidth="0.04" Location="OverCenter"
Background="{StaticResource green}" BorderBrush="#7FFFFFFF" />
<gauge:LinearRange Min="60" Max="75" StartWidth="0.04"
EndWidth="0.04" Location="OverCenter"
Background="{StaticResource yellow}" BorderBrush="#7FFFFFFF" />
<gauge:LinearRange Min="75" Max="100" StartWidth="0.04"
EndWidth="0.04" Location="OverCenter"
Background="{StaticResource red}" BorderBrush="#7FFFFFFF" />
</gauge:RangeList>
<gauge:IndicatorList>
<gauge:Marker x:Name="gauge_markerCPU" Location="OverCenter" RelativeHeight="0.04"
RelativeWidth="0.08" IsAnimated="True" RenderTransformOrigin="0.5,0.5" BorderBrush="#FFF38005" >
<gauge:Marker.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform X="11"/>
</TransformGroup>
</gauge:Marker.RenderTransform>
</gauge:Marker>
</gauge:IndicatorList>
</gauge:LinearScale>
</gauge:LinearGauge>
</control:RadGauge>
Notice the Style property of the linear gauge.
This gives the control the final look. BUT Visual Studio is not the right tool for this. Instead (after building the base gauge) I opened my project in Expression Blend an made the things “via mouse color dialogs”.
To explain the gauge:
There is an outer holder – the RadGauge (for sizing and code access to members). next comes a LinearGauge – this gives the things a style. Inside it is a LinearScale (TickSteps, and things like this) which holds four different things.
First some definitions for the ticks (the lines on the bar). Than a definition for the label style.
Followed by a range list – this makes the green, red, organe parts in the gauge.
And last not least the inidcator (marker). That is the “needle” which shows the current value.
There are two gauges like this (range 0 to 100) to show CPU and RAM percentage.
I also have a third gauge (the horizontal one) which shows the RAM-Situation.
While the percentage gauges are always he same (0 to 100 is the only possible range) the RAM can be very different.
So the ranges and the max depends on what you have in your server.
These values must be set dynamically – imagine you have 1gig of ram – so the scale would be 200 megs (let’s say).
When you hit a box with 8gigs a scale of 200 would be unreadable (to many labels). Also “red range” would not start at 800megs – instead it would be something like 6gig.
So setting these values is done in code:
void pC_GetPerfInfoCompleted(object sender, SLPerfDisp.RefPerSvc.GetPerfInfoCompletedEventArgs e) {
m_bImInCall = false; //done
btnTest.IsEnabled = true;
PerfInfos pI = e.Result;
//in producition environment check e.Error and e.Cancelled here also!!
if (pI.ErrMess == "OK") {
//bind the object to the root grid
LayoutRoot.DataContext = pI;
linearScaleRamUsed.MajorTickStep = pI.RamTotal / 4; //if you have a lot of ram 5 could be better
//next assign values - TAKE CARE - the control checks if Max>Min
//so assure that this does not occure - the safe way - set min to the lowest expectable value - in this case 0
redRange.Min = yellowRange.Min = greenRange.Min = 0;
//max of the red range is the total of the scale == max ram available
redRange.Max = linearScaleRamUsed.Max = pI.RamTotal;
//min of red is the same as max of yellow - let's say 2/3 usage is "critical"
redRange.Min = yellowRange.Max = pI.RamTotal - (pI.RamTotal / 3);
//yellow range min is the same as green max - let's say 50% usage is end of green
yellowRange.Min = greenRange.Max = pI.RamTotal / 2;
//now assigne the values to the markers
gauge_markerRAM.Value = pI.RamUsedPercent;
gauge_markerCPU.Value = pI.CPUPercent;
gauge_markerRAMUsed.Value = pI.RamUsed;
The only thing interesting here is the fact that Gauge Controls check the values of min and max for ranges.
So I had to ensure that min / max never gets wrong values.
And generally there is another thing to notice: It took me about 2 Hours to add those three gauges.
The time comes from:
- Adding the gauges and setting the “first look” – about 10 Minutes
- Adding data to the controls – about 5 Minutes
- Using Expression Blend to change the look – 1.5 Hours
To be true – after about 15 Minutes I had a working (with data) thing which looks almost like on the top picture (the dashboard) here: Gauge Controls.
Is it so difficult to work with blend? NO but there are three things which made me waste more than an hour.
- I’m a developer not a designer (I’m not able to quantify this)
- I had to find out how the gauges are made (the layout system) 10 Minutes
- I tried a lot with different colors and transformations (1 hour at least)
- I made a different layout for the horizontal gauge (5 minutes – I knew now how it works)
- I was tired and could not find a satisfying look (all the rest)
In fact a designer (I guess from what I have seen when a friend of mine did something like this) would need (like I) – about 10 minutes to find out how the control is designed and another 5 minutes to make something good looking.
What I want to point out is the following: with a “ready made control” like the Gauge Control it takes just a few minutes to add good looking content to your Silverlight application. And it is a matter of facts that Developer!=Designer 
By thinking about the control I came to the idea that the surrounding HTML could have a need to interact with the control.
So I decided to expand the Silverlight control with some properties to make it accessible to HTML.
I will discuss this in the last part of this series.