WynApse Home Page
Home    Blog    About    Contact       
Latest Article:


My Tags:
My Sponsors:






Lifetime Member:

Silverlight Glyph Explorer






The Problem

When working on the Reflection Builder, I wanted checkboxes for showing/hiding canvases and controls. Of course, WPF/E didn't have controls, and Silverlight doesn't either yet, natively, so my first thought was to use a line of text as a checkbox with the first character being a WingDing character that looks like an unchecked checkbox.

That simple statement was actually harder than it sounded because of the 'standard' fonts included in WPF/E. WingDings was not in the list. WebDings is, but WebDings doesn't have the same two boxes. On the WPF/E Forum, I was told I could put the character up as a Glyph.

Alrighty then... what's a Glyph?

According to the SDK, the Glyph Object "Represents the set of glyphs that are used for rendering fixed text." Hmmm.Looking at the SDK, I can see an indice in there, so my thought was that I could set the indice to be the keycode of the character I wanted. If I open charmap, and pick WingDings, the characters I want are 0X70 and 0x78. In decimal that would be 112 and 120. So I plugged those two values into a line that looked like this:

<Glyphs x:Name="GlyphDisplay" Fill="Black" FontUri="./wingding.ttf" fontRenderingEmSize="16" Indices="120" />


Note the local loading of the wingding font, and the Font size.

This gave me something, but not the character I wanted, and certainly confused me.

Glyph Slider

I still don't know how to map the Glyph Indice with the keycode for a font, but I figured out how to find out what the mappings are by using a slider as shown above.

The slider is the same as all the ones in the Reflection Builder and originated in the QuickStart. The differences this time out are some additions to this version:
  • MouseOver Fill effect on the thumb
  • MouseDown Fill effect on the thumb
  • Mouse clicks to the right of the thumb increment the value by 1
  • Mouse clicks to the left of the thumb decrement the value by 1
The slider works very simply in that it is set to have a scope of 0 to 300. I started it at 133, which is the indice for the unchecked box. By moving the slider, you can see that 225 is the last indice with anything of value. As the slider is moved, the indice of the glyph display is changed to show the character in the WingDing font.

Any font could be loaded up with the xaml and displayed in the manner I am doing WingDings. With the volume of Ding fonts available on the Internet, there are many line-art items available.

The Checkbox

The checkbox in the upper right is there as an example of using the WingDing characters and to make it perform a function, I chose to Scale the Glyph by a factor of two when checked.

Problems

I really wanted the Glyph part of the checkbox to take the Hand cursor, and the mouse click like a real Windows checkbox does. If you examine the xaml, you'll see that the Glyph for the checkbox is enclosed in a Canvas, and the enclosing canvas has the MouseLeftButtonDown message. Unfortunately, even with out enclosing canvas having the cursor and Mouse message, it does not happen on the Glyph itself.

Partial Solution to this problem!

I've subsequently found a partial solution for this mouse/glyph problem, but left it in here since it really is a bug.

As you'll note above, the problem still exists even though the xaml reflects the fact that I used OriginX and OriginY in place of Canvas.Left and Canvas.Top in the Glyph definition. The code for the next article uses MouseEnter and MouseLeave on glyphs without problems using OriginX and OriginY, but apparently the cursor and MouseDown messages are still an issue.

JavaScript for producing this page:

  <script type="text/javascript">
var mouseDownPosition = 0;
var mouseDownValue = -1;

function slider_Loaded(sender, args)
{
slider_SetValue(sender.findName("slider_GlyphIndice"), 133);
}

function slider_MouseLeftButtonDown(sender, args)
{
var coordinate = args.getPosition(null).x - sender["Canvas.Left"];
slider_BumpValue(sender, coordinate);
}

function slider_thumb_MouseLeftButtonDown(sender, args)
{
sender.findName("slider_thumb_GlyphIndice").Fill="Red";
var slider = sender.findName("slider_GlyphIndice");
sender.captureMouse();
mouseDownValue = slider_GetValue(slider);
mouseDownPosition = args.getPosition(null).x;
}

function slider_thumb_MouseLeftButtonUp(sender, args)
{
sender.findName("slider_thumb_GlyphIndice").Fill="SteelBlue";
sender.releaseMouseCapture();
mouseDownValue = -1;
}

function slider_thumb_MouseEnter(sender, args)
{
sender.findName("slider_thumb_GlyphIndice").Fill="Red";
}

function slider_thumb_MouseLeave(sender, args)
{
sender.findName("slider_thumb_GlyphIndice").Fill="SteelBlue";
}

function slider_thumb_MouseMove(sender, args)
{
switch (sender.name)
{
case "slider_thumb_GlyphIndice":
var slider = sender.findName("slider_GlyphIndice");
break;

}

if (mouseDownValue != -1)
{
var newValue = mouseDownValue + (args.getPosition(null).x - mouseDownPosition);
slider_SetValue(slider, newValue);

}

}

function slider_GetValue(sender)
{
switch (sender.name)
{
case "slider_GlyphIndice":
var thumb = sender.findName("slider_thumb_GlyphIndice");
break;

}
return thumb["Canvas.Left"] + .5 * thumb.width;

}

function slider_SetValue(sender, newValue)
{
if (newValue > sender.width)
{
newValue = sender.width;
}
if (newValue < 0)
{
newValue = 0;
}
switch (sender.name)
{
case "slider_GlyphIndice":
{
var thumb = sender.findName("slider_thumb_GlyphIndice");
thumb["Canvas.Left"] = newValue - .5 * thumb.width;

var Pos = thumb["Canvas.Left"] + .5*thumb.width;
sender.findName("sliderPos_GlyphIndice").Text=Pos.toString();
sender.findName("GlyphDisplay").Indices=Pos.toString();
break;

}
}
}

function slider_BumpValue(sender, newValue)
{
switch (sender.name)
{
case "slider_GlyphIndice":
{
var thumb = sender.findName("slider_thumb_GlyphIndice");
if (thumb["Canvas.Left"] > newValue)
{
if (thumb["Canvas.Left"] > 0)
{
thumb["Canvas.Left"] -= 1;
}
}
else
{
if (thumb["Canvas.Left"] < 300)
{
thumb["Canvas.Left"] += 1;
}
}
var Pos = thumb["Canvas.Left"] + .5*thumb.width;
sender.findName("sliderPos_GlyphIndice").Text=Pos.toString();
sender.findName("GlyphDisplay").Indices=Pos.toString();
break;

}
}
}
function MainCheckBox(sender, args)
{
if (sender.findName("MainCheckbox").Indices=="95")
{
sender.findName("MainCheckbox").Indices="133";
sender.findName("MainCheckBoxText").Text="Glyph size Normal";
sender.findName("GlyphScaleTransform").ScaleX=1;
sender.findName("GlyphScaleTransform").ScaleY=1;

}
else
{
sender.findName("MainCheckbox").Indices="95";
sender.findName("MainCheckBoxText").Text="Glyph size X2";
sender.findName("GlyphScaleTransform").ScaleX=2;
sender.findName("GlyphScaleTransform").ScaleY=2;
}
}
</script>


XAML for producing this page:

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


<!-- -->
<!-- -->
<!-- C H E C K B O X C O D E -->
<!-- -->
<!-- -->

<!-- Main Checkbox -->
<!-- 133 unchecked box, 95 checked box, 123 unchecked button, 126 checked button -->
<Canvas Canvas.Top="0" Canvas.Left="150" Cursor="Hand"
MouseLeftButtonDown="MainCheckBox" >
<Glyphs x:Name="MainCheckbox" OriginX="0" OriginY="15" MouseLeftButtonDown="MainCheckBox" Cursor="Hand"
Fill="Black" FontUri="wingding.ttf" FontRenderingEmSize="16" Indices="133" />
<TextBlock x:Name="MainCheckBoxText" FontSize="14" Canvas.Left="17" Foreground="Black" Text="Glyph Size normal" />
</Canvas>

<!-- -->
<!-- -->
<!-- G L Y P H C O D E -->
<!-- -->
<!-- -->

<Canvas x:Name="GlyphDisplayCanvas" Canvas.Left="0" Canvas.Top="0" >
<Glyphs x:Name="GlyphDisplay" Fill="Black" FontUri="wingding.ttf" FontRenderingEmSize="16" Indices="133" />
<Canvas.RenderTransform>
<TransformGroup>
<ScaleTransform x:Name="GlyphScaleTransform" />
</TransformGroup>
</Canvas.RenderTransform>
</Canvas>

<!-- -->
<!-- -->
<!-- S L I D E R C O D E -->
<!-- -->
<!-- -->

<!-- Glyph Indice Slider -->

<Canvas x:Name="slider_GlyphIndice" Canvas.Top="50" Canvas.Left="0" Width="300" Height="45"
Background="transparent"
MouseLeftButtonDown="slider_MouseLeftButtonDown">
<Line x:Name="slider_line_GlyphIndice" Stroke="steelblue"
StrokeThickness="1" X1="0" Y1="25" X2="300" Y2="25"/>
<Path x:Name="slider_thumb_GlyphIndice" Stroke="LightBlue" Cursor="Hand"
Fill="SteelBlue"
Data="M0,0 L6,0 6,15 3,20 0,15z"
MouseEnter="slider_thumb_MouseEnter"
MouseLeave="slider_thumb_MouseLeave"
MouseLeftButtonUp="slider_thumb_MouseLeftButtonUp"
MouseMove="slider_thumb_MouseMove"
MouseLeftButtonDown="slider_thumb_MouseLeftButtonDown" />
<TextBlock x:Name="sliderPos_GlyphIndice" FontSize="14" Canvas.Left="148" Canvas.Top="25" Foreground="Black" />
<TextBlock FontSize="12" Canvas.Left="125" Canvas.Top="40" Foreground="Black" Text="Glyph Indice"/>
</Canvas>


</Canvas>
Copyright © 2006-2017, WynApse