WynApse Home Page
Home    Blog    About    Contact       
Latest Article:


My Tags:
My Sponsors:






Lifetime Member:

Silverlight Checkboxes And Radio Buttons





Beta 1 Conversion

This was one of the simpler conversions... either that or I'm finally getting used to them :) Since this had no animation blocks, I avoided that whole mess. The only difficulty I had was the addition in Beta 1 of "Visibility" and how that has an affect on how we were all using Opacity in the February CTP. After I got that done, it worked fine.

Original Text

Ever since I did the Reflection Builder application, I've wanted to spend at least a little time and come up with a way to do radio buttons with wingdings. I had played around at one point using the Path command to build a checkbox that I can change the color of the check with, but never did anything with it. Now is the time!

Glyphs vs Path

Why would I choose using a Path over a Glyph since the Glyph artwork can be so nice? I can think of three things pretty quickly:
  • You have to have the font on-site and there's always that whole copyright thing.
  • At least for now, the Glyph doesn't play as nice with the mouse.
  • The Glyph is all one color, and I think it's cool to have a red X inside the box
As a comparison, I have a mix of Glyph and Path radio buttons and checkboxes on this canvas. As usual (for good or bad), I ended up getting more elaborate than I had originally intended. The left-hand set of radio buttons uses Glyphs, and they look great. The right-hand set of radio buttons uses a Path, explained below, and I like them a lot because of the color.

If you select "Use wingdings" from the "Checkbox Style" radio buttons, you'll see a checkbox that uses Glyphs and again, it looks very nice. If you select "Use Path", you'll see a checkbox that uses a Path, and again, I like the color in it.

The "Path Check Color" radio buttons select the color used in the "Path" checkbox.

Path Checkbox

Since I've already used the Glyph Checkbox in the past, most everyone has seen that and is familiar with it. The Glyph works great in this regard because instead of having a method to get the checkbox status from the control, you simply check to see which indice is being displayed.

With the Path Checkbox, you have no such indice, and have to use some other method of keeping track of the status of the checkbox. A local variable would work, but I wanted to try to have the "control" retain the information. To that end, I added a TextBlock to the Canvas associated with the checkbox that retains the "checked/unchecked" status in a field with Opacity of 0 [Beta 1: Visibility="Hidden"]. This is an extra bit of messing around, but if you use a local variable, you have to do that as well, so I don't consider it to be a huge difference.

The Path checkbox then consists of the following xaml objects:
  • Container Canvas
  • Path Container Canvas -- not necessarily required, but certainly makes the Path statement make more sense
  • Path for the box
  • A path for each half of the check-mark
  • TextBlock for the checkbox Text
  • Invisible TextBlock for the checkbox status, if you decide to do that
The Path object itself is pretty simple in this situation, because we're doing a box and two slashes. The basic Path statement has Stroke, Fill, and StrokeThickness values like the Rectangle object does.

The Path object also has a set of directions that describe how the object is drawn. In the case of the box for the checkbox, I played around with the size and decided I liked a 10X10 square.

I already have the Path objects in a canvas to control the location, so:
  1. I start off by moving the logical starting point to (0,0),
  2. then draw a line to (10,0),
  3. from there draw a line to (10,10),
  4. and to (0,10),
  5. and back to (0,0) completing the square,
or in xaml:

Data="M0,0 L10,0 L10,10 L0,10z"

Note the "M" moves to a point on the canvas without drawing. "L" draws a line from where we are to the coordinates given. the "z" after the 3rd set of points tells the object to complete the object by drawing back to the starting point.

For the "X", I chose to also use Path objects and draw an angled line in each direction:

Data="M2,2 L8,8"

Data="M2,8 L8,2"

Since there is no "z" after the Line directive, the path ends at the point given.

Could I have used Line objects for these? Yes... and I could have used 4 line objects for the box as well, but I figured this was a good time to experiment with something I hadn't used before.

Radio Buttons and Groups

I wrote MS Windows desktop applications from Visual Studio V 1.0 beta through VC6 and I have to say I can only think of two instances that I had to deal with multiple radio button groups. Both instances had to do with option setup pages. I decided to try to work out a way to do groups with the radio buttons I'm displaying here. This is "a" way, and the way I decided to do it today. Tomorrow I may have a better idea, and so may you. Feel free to use this idea if you don't want to take the time to consider another!

Looking at the first radio button in the Checkbox Style group:

<Canvas x:Name="ctlRB0" Canvas.Top="10" Canvas.Left="10"  Cursor="Hand"&lt;br />
MouseLeftButtonDown="RadioButtonGrp1" ><br />
<Glyphs x:Name="ctlRB0Glyph" Canvas.Left="0" Canvas.Top="2" &lt;br />
Fill="Black" FontUri="./wingding.ttf" FontRenderingEmSize="16" Indices="124" /><br />
<TextBlock x:Name="ctlRB0Text" FontSize="14" Canvas.Left="17" Foreground="Black" Text="Use wingdings" /><br />
</Canvas>

Notice I use the prefix "ctlRB" for the 3 Object names in the group: the container Canvas (ctlRB0), the Glyph (ctlRB0Glyph), and the TextBlock (ctlRB0Text).

The second radio button was "ctlRB1", etc. This gives me the capability of using the prefix "ctlRB" to identify the group, and the post-fix indice as the exact radio button selected.

The Path Check Color radio button group has the prefix "ctlRB2" and is used similarly.

Like I said, this is "a" way to accomplish this, but it does work :)

Ellipse Radio Buttons

To make this complete, I worked out a radio button using two ellipses. This is a similar concept to the path checkbox, only more lightweight because of the ellipse objects instead of three path objects. A representative radio button is:

<Canvas x:Name="ctlRB20" Canvas.Top="10" Canvas.Left="10"  Cursor="Hand"
MouseLeftButtonDown="RadioButtonGrp2" >
<Canvas Canvas.Top="4">
<Ellipse Stroke="Black" Fill="White" StrokeThickness="2" Canvas.Top="1" Width="12" Height="12" />
<Ellipse x:Name="ctlRB20Center" Fill="White" Canvas.Top="5" Canvas.Left="4" Width="4" Height="4" />
</Canvas>
<TextBlock x:Name="ctlRB20Text" FontSize="14" Canvas.Left="17" Foreground="Black" Text="Red Check" />
</Canvas>

Group Boxes

I'm far from thinking we should try to create WPF/E applications that mimic desktop or web applications, but while thinking outside the box, sometimes it's nice to fall back on familiar concepts. As an example of that situation, I decided to put group boxes around the two sets of radio buttons just to see how hard it would be. The group boxes consist of 4 elements:
  • A dark-bordered rectangle
  • A white-bordered rectangle to give an etched look
  • A white rectangle to cover a block of the rectangle
  • The text
All-in-all I like the looks of the path checkboxes and ellipse radio buttons and will probably use them as I continue forward, and while I also like the way the group boxes came out, I'm not sure about using them in WPF/E applications.

JavaScript for producing this page:

<script>
var sXColor="Red";

// Checkbox to show/hide the bottom part
function WingdingCheckBox(sender, args){
// 95 is checked
if (sender.findName("WingdingCheckbox").Indices=="95")
{
sender.findName("WingdingCheckbox").Indices="133";
}
else
{
sender.findName("WingdingCheckbox").Indices="95";
}
}

function PathCheckBox(sender, args){
if (sender.findName("PathCheckBox").Text=="unchecked")
{
sender.findName("1Check").Stroke=sXColor;
sender.findName("2Check").Stroke=sXColor;
sender.findName("PathCheckBox").Text="checked"
}
else
{
sender.findName("1Check").Stroke="White";
sender.findName("2Check").Stroke="White";
sender.findName("PathCheckBox").Text="unchecked"
}
}

function RadioButtonGrp1(sender, args){
// get canvas name for which button
var sRB = sender.Name.toString();

var nIndex;
var sName;
for (nIndex=0; nIndex < 3; nIndex++)
{
sName = "ctlRB" + nIndex;
if (sName == sRB)
{
// The selection
sender.findName(sName + "Glyph").Indices = "126";

sender.findName("CheckBoxUsingwingdings").Visibility="Collapsed";
sender.findName("CheckBoxUsingPath").Visibility="Collapsed";

switch(sender.findName(sName + "Text").Text){
case "Use wingdings":
sender.findName("CheckBoxUsingwingdings").Visibility="Visible";
break;

case "Use Path":
sender.findName("CheckBoxUsingPath").Visibility="Visible";
break;

case "Use Neither":
break;

}
}
else
{
// unselect everyone else
sender.findName(sName + "Glyph").Indices = "124";
}
}


}

function RadioButtonGrp2(sender, args){
// get canvas name for which button
var sRB = sender.Name.toString();

var nIndex;
var sName;
for (nIndex=0; nIndex < 4; nIndex++)
{
sName = "ctlRB2" + nIndex;
if (sName == sRB)
{
// The selection
sender.findName(sName + "Center").Fill = "Red";

switch(sender.findName(sName + "Text").Text){
case "Red Check":
sXColor="Red";
break;

case "Green Check":
sXColor="Green";
break;

case "Blue Check":
sXColor="Blue";
break;

case "Black Check":
sXColor="Black";
break;

}
}
else
{
// unselect everyone else
sender.findName(sName + "Center").Fill = "White";
}
}
}



</script>


XAML for producing this page:

<Canvas 
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">


<!-- Checkbox Style Group -->
<Canvas Canvas.Top="20" Canvas.Left="20">

<!-- chiseled rectangle for group box -->
<Rectangle Width="150" Height="80" Stroke="White" Canvas.Top="1" Canvas.Left="1"/>
<Rectangle Width="150" Height="80" Stroke="#A0A0A0"/>

<!-- Wingdings Radio Button -->
<Canvas x:Name="ctlRB0" Canvas.Top="10" Canvas.Left="10" Cursor="Hand"
MouseLeftButtonDown="RadioButtonGrp1" >
<Glyphs x:Name="ctlRB0Glyph" Canvas.Left="0" Canvas.Top="2"
Fill="Black" FontUri="wingding.ttf" FontRenderingEmSize="16" Indices="124" />
<TextBlock x:Name="ctlRB0Text" FontSize="14" Canvas.Left="17" Foreground="Black" Text="Use wingdings" />
</Canvas>

<!-- Path Radio Button -->
<Canvas x:Name="ctlRB1" Canvas.Top="30" Canvas.Left="10" Cursor="Hand"
MouseLeftButtonDown="RadioButtonGrp1" >
<Glyphs x:Name="ctlRB1Glyph" Canvas.Left="0" Canvas.Top="2"
Fill="Black" FontUri="wingding.ttf" FontRenderingEmSize="16" Indices="124" />
<TextBlock x:Name="ctlRB1Text" FontSize="14" Canvas.Left="17" Foreground="Black" Text="Use Path" />
</Canvas>

<!-- Don't show checkbox -->
<Canvas x:Name="ctlRB2" Canvas.Top="50" Canvas.Left="10" Cursor="Hand"
MouseLeftButtonDown="RadioButtonGrp1" >
<Glyphs x:Name="ctlRB2Glyph" Canvas.Left="0" Canvas.Top="2"
Fill="Black" FontUri="wingding.ttf" FontRenderingEmSize="16" Indices="126" />
<TextBlock x:Name="ctlRB2Text" FontSize="14" Canvas.Left="17" Foreground="Black" Text="Use Neither" />
</Canvas>
</Canvas>

<!-- blank and text for group box -->
<Rectangle Width="77" Height="15" Fill="White" Canvas.Top="13" Canvas.Left="25"/>
<TextBlock FontSize="10" Canvas.Left="27" Canvas.Top="13" Foreground="Black" Text="Checkbox Style" />


<!-- Path Check Color Group -->
<Canvas Canvas.Top="20" Canvas.Left="180">

<!-- chiseled rectangle for group box -->
<Rectangle Width="150" Height="100" Stroke="White" Canvas.Top="1" Canvas.Left="1"/>
<Rectangle Width="150" Height="100" Stroke="#A0A0A0"/>

<!-- Red Radio Button using Ellipse -->
<Canvas x:Name="ctlRB20" Canvas.Top="10" Canvas.Left="10" Cursor="Hand"
MouseLeftButtonDown="RadioButtonGrp2" >
<Canvas Canvas.Top="4">
<Ellipse Stroke="Black" Fill="White" StrokeThickness="2" Canvas.Top="1" Width="12" Height="12" />
<Ellipse x:Name="ctlRB20Center" Fill="White" Canvas.Top="5" Canvas.Left="4" Width="4" Height="4" />
</Canvas>
<TextBlock x:Name="ctlRB20Text" FontSize="14" Canvas.Left="17" Foreground="Black" Text="Red Check" />
</Canvas>

<!-- Green Radio Button using Ellipse -->
<Canvas x:Name="ctlRB21" Canvas.Top="30" Canvas.Left="10" Cursor="Hand"
MouseLeftButtonDown="RadioButtonGrp2" >
<Canvas Canvas.Top="4">
<Ellipse Stroke="Black" Fill="White" StrokeThickness="2" Canvas.Top="1" Width="12" Height="12" />
<Ellipse x:Name="ctlRB21Center" Fill="White" Canvas.Top="5" Canvas.Left="4" Width="4" Height="4" />
</Canvas>
<TextBlock x:Name="ctlRB21Text" FontSize="14" Canvas.Left="17" Foreground="Black" Text="Green Check" />
</Canvas>

<!-- Blue Radio Button using Ellipse -->
<Canvas x:Name="ctlRB22" Canvas.Top="50" Canvas.Left="10" Cursor="Hand"
MouseLeftButtonDown="RadioButtonGrp2" >
<Canvas Canvas.Top="4">
<Ellipse Stroke="Black" Fill="White" StrokeThickness="2" Canvas.Top="1" Width="12" Height="12" />
<Ellipse x:Name="ctlRB22Center" Fill="White" Canvas.Top="5" Canvas.Left="4" Width="4" Height="4" />
</Canvas>
<TextBlock x:Name="ctlRB22Text" FontSize="14" Canvas.Left="17" Foreground="Black" Text="Blue Check" />
</Canvas>

<!-- Black Radio Button using Ellipse -->
<Canvas x:Name="ctlRB23" Canvas.Top="70" Canvas.Left="10" Cursor="Hand"
MouseLeftButtonDown="RadioButtonGrp2" >
<Canvas Canvas.Top="4">
<Ellipse Stroke="Black" Fill="White" StrokeThickness="2" Canvas.Top="1" Width="12" Height="12" />
<Ellipse x:Name="ctlRB23Center" Fill="White" Canvas.Top="5" Canvas.Left="4" Width="4" Height="4" />
</Canvas>
<TextBlock x:Name="ctlRB23Text" FontSize="14" Canvas.Left="17" Foreground="Black" Text="Black Check" />
</Canvas>

</Canvas>

<!-- blank and text for group box -->
<Rectangle Width="88" Height="15" Fill="White" Canvas.Top="13" Canvas.Left="185"/>
<TextBlock FontSize="10" Canvas.Left="187" Canvas.Top="13" Foreground="Black" Text="Path Check Color" />

<!-- Checkbox using wingding -->
<!-- 133 unchecked box, 95 checked box -->
<Canvas x:Name="CheckBoxUsingwingdings" Canvas.Top="120" Canvas.Left="20" Cursor="Hand" Visibility="Collapsed"
MouseLeftButtonDown="WingdingCheckBox" >
<Glyphs x:Name="WingdingCheckbox" Canvas.Left="0" Canvas.Top="2"
Fill="Black" FontUri="wingding.ttf" FontRenderingEmSize="16" Indices="133" />
<TextBlock FontSize="14" Canvas.Left="17" Foreground="Black" Text="wingding Checkbox" />
</Canvas>


<!-- Checkbox using Path -->
<Canvas x:Name="CheckBoxUsingPath" Canvas.Top="120" Canvas.Left="20" Cursor="Hand" Visibility="Collapsed"
MouseLeftButtonDown="PathCheckBox" >
<Canvas Canvas.Top="4">
<Path Stroke="Black" Fill="White" StrokeThickness="2"
Data="M0,0 L10,0 L10,10 L0,10z"/>

<Path Name="1Check" Stroke="White" StrokeThickness="2"
Data="M2,2 L8,8"/>
<Path Name="2Check" Stroke="White" StrokeThickness="2"
Data="M2,8 L8,2"/>

</Canvas>
<TextBlock x:Name="PathCheckBoxText" FontSize="14" Canvas.Left="17" Foreground="Black" Text="Path Checkbox" />
<TextBlock x:Name="PathCheckBox" FontSize="14" Canvas.Left="17" Foreground="Black" Text="unchecked" Visibility="Collapsed"/>
</Canvas>

</Canvas>

Copyright © 2006-2017, WynApse