Showing posts with label XAML. Show all posts
Showing posts with label XAML. Show all posts

Tuesday, August 27, 2019

Loading an image into an ImageButton from an EmbeddedResource

Sad, but this took me awhile to figure out.  A lot of the examples on the web are incorrect so it took quite a bit of thrashing to figure this simple thing out.

The way to load an image into an ImageButton from an EmbeddedResource is to of course add an image to your project and mark it as EmbeddedResource. 

The next step is to determine the “path” to this resource.  If the project name is “Project” and the folder you added your image to is named “Folder” and the image is named “Image.png” then the “path” to this image is "Project.Folder.Image.png”

Then it is a simple process to use the static class ImageSource, like this:

ImageSource.FromResource("Project.Folder.Image.png")

Tuesday, August 30, 2016

Changing the ZIndex of a XAML Element using a Storyboard


One of my current projects has two XAML elements moving in 3D and as the  second element eclipsed the first element the ZIndex had to be changed so the second element would now appear in front of the first. 

Lots of searching later (and quite a few articles saying that it was not possible) I came up with a XAML based Storyboard that worked, but since I needed to build the Storyboard programmatically, I needed to convert it to C# code.

This is what I came up with:

Code Snippet – CreateZIndexStoryboard
  1. private Storyboard CreateZIndexStoryboard(FrameworkElement fromElement, int newZIndex)
  2. {
  3.     var myZIndexStoryboard = new Storyboard();
  4.     var myZIndexAnimation = new ObjectAnimationUsingKeyFrames();       
  5.     var myZIndexKeyFrame = new DiscreteObjectKeyFrame
  6.     {
  7.         Value = newZIndex,
  8.         KeyTime = TimeSpan.FromMilliseconds(AnimationLength/2)
  9.     };
  10.  
  11.     myZIndexAnimation.KeyFrames.Add(myZIndexKeyFrame);
  12.  
  13.     myZIndexStoryboard.Children.Add(myZIndexAnimation);
  14.  
  15.     Storyboard.SetTarget(myZIndexAnimation, fromElement);
  16.     Storyboard.SetTargetProperty(myZIndexAnimation, "(Canvas.ZIndex)");
  17.  
  18.     return myZIndexStoryboard;
  19. }

One of the main points of difference between Silverlight and Windows Universal XAML is that setting the target property on the storyboard, ie. Storyboard.SetTargetProperty is that in silverlight you would set the path to the property by creating a new PropertyPath object.  With Windows Universal XAML you using a binding to a property using a string with binding syntax.

Sunday, August 21, 2016

It’s been a while, but I’m back.

When I started this blog, way back in 2008, my main goal was to record and share my experiences as I grew as a programmer.  I didn’t want to rehash the same information that you got from a hundred other sources.  Instead I wanted to show the unique parts of my eternal journey to be a better programmer.

During my three year hiatus I grew a lot, but I would put quite a bit of it under the heading of “Everyone else has been there, done that” and I could not really justify wasting your time reading such drivel.  Plus, lots of personal “stuff” happened, such as the death of my Mother-in-law and last years diagnosis of my wife’s cancer.

So, I expect to start adding new content soon.  Prepare yourself.  You have been warned.

Friday, November 15, 2013

Creating XAML hexagons without using a PATH element

I was recently working on a small Windows Phone 8 app that needed some tessellated (tiled) hexagons and after searching the web for a simple solution, I did not find what I wanted. 

All of the solutions involved drawing the hexagon using drawing primitives such as the PATH element.  I wanted a “simpler” solution.  I wanted a Grid based solution, and here it is.

To start with I needed to know two semi-basic points about hexagons: what is the ratio of height to width, and (with the hex “standing” on one of its flat sides) what is the the ratio between the horizontal length of the flat and the horizontal distance from the end of the flat side to the edge of the hexagon.  (Boy that is harder to write than it is to just see it)

I found both pieces of information at: Hexnet

Hexnet shows that if the length of one side of a hex has a length of 1, then the overall width is 2 and the height of the hexagon is √3 (approx. 1.73).  So, if we were to build this in a grid, we would have a single hexagon take up 6 cells (2 rows and 3 columns) and our two critical semi-basic points are: √3 to 2 and 1 to .5.

If we wanted a hexagon with an overall width of 200px (200 times our example above), our grid would be defined as:

   1:  <Grid x:Name="LayoutRoot" Background="White" Width="200" Height="173">
   2:      <Grid.ColumnDefinitions>
   3:          <ColumnDefinition Width="*"></ColumnDefinition>
   4:          <ColumnDefinition Width="2*"></ColumnDefinition>
   5:          <ColumnDefinition Width="*"></ColumnDefinition>
   6:      </Grid.ColumnDefinitions>
   7:      <Grid.RowDefinitions>
   8:          <RowDefinition></RowDefinition>
   9:          <RowDefinition></RowDefinition>
  10:      </Grid.RowDefinitions>
  11:  </Grid>



if you look at this grid with gridlines on, you get:


image



Now from here we can either create a outline of a hexagon using 6 line objects, create a solid hexagon using 3 rectangle objects or combine both for an outlined solid color hexagon.


“Wait!”, you say.  “I can see the six lines making up the outline of a hexagon, but how could you do a solid color hexagon with three squares?”


Well, I’m glad you asked.  If you fill the center column with a rectangle, that’s one.  If you make a copy but rotate it 60 degrees using the center as the pivot point and make a third and rotate it –60 degrees then you have your solid color hexagon.


And, if you just start repeating the second and third columns when you add columns, you can start to create a grid full of tessellated (tiled) hexagons, just like I did in this image.


image


And here is the complete xaml I used to create the above image (From this code it was simple to extract rules that I used to create large fields of tessellated (tiled) hexagons in code):


   1:  <UserControl x:Class="Hexagon.MainPage"
   2:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   5:      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   6:      mc:Ignorable="d"
   7:      d:DesignHeight="346" d:DesignWidth="500">
   8:      <Viewbox Stretch="Uniform">
   9:          <Grid x:Name="LayoutRoot" Background="White" Width="500" Height="346" Margin="50">
  10:              <Grid.ColumnDefinitions>
  11:                  <ColumnDefinition Width="*"></ColumnDefinition>
  12:                  <ColumnDefinition Width="2*"></ColumnDefinition>
  13:                  <ColumnDefinition Width="*"></ColumnDefinition>
  14:                  <ColumnDefinition Width="2*"></ColumnDefinition>
  15:                  <ColumnDefinition Width="*"></ColumnDefinition>
  16:                  <ColumnDefinition Width="2*"></ColumnDefinition>
  17:                  <ColumnDefinition Width="*"></ColumnDefinition>
  18:              </Grid.ColumnDefinitions>
  19:              <Grid.RowDefinitions>
  20:                  <RowDefinition></RowDefinition>
  21:                  <RowDefinition></RowDefinition>
  22:                  <RowDefinition></RowDefinition>
  23:                  <RowDefinition></RowDefinition>
  24:              </Grid.RowDefinitions>
  25:              <Rectangle Fill="Pink" RenderTransformOrigin="0.5, 0.5" Grid.Column="1" Grid.RowSpan="2"></Rectangle>
  26:              <Rectangle Fill="Pink" RenderTransformOrigin="0.5, 0.5" Grid.Column="1" Grid.RowSpan="2">
  27:                  <Rectangle.RenderTransform>
  28:                      <RotateTransform Angle="-60" />
  29:                  </Rectangle.RenderTransform>
  30:              </Rectangle>
  31:              <Rectangle Fill="Pink" RenderTransformOrigin="0.5, 0.5" Grid.Column="1" Grid.RowSpan="2">
  32:                  <Rectangle.RenderTransform>
  33:                      <RotateTransform Angle="60" />
  34:                  </Rectangle.RenderTransform>
  35:              </Rectangle>
  36:              <Rectangle Fill="Aquamarine" RenderTransformOrigin="0.5, 0.5" Grid.Column="3" Grid.Row="1" Grid.RowSpan="2"></Rectangle>
  37:              <Rectangle Fill="Aquamarine" RenderTransformOrigin="0.5, 0.5" Grid.Column="3" Grid.Row="1" Grid.RowSpan="2">
  38:                  <Rectangle.RenderTransform>
  39:                      <RotateTransform Angle="-60" />
  40:                  </Rectangle.RenderTransform>
  41:              </Rectangle>
  42:              <Rectangle Fill="Aquamarine" RenderTransformOrigin="0.5, 0.5" Grid.Column="3" Grid.Row="1" Grid.RowSpan="2">
  43:                  <Rectangle.RenderTransform>
  44:                      <RotateTransform Angle="60" />
  45:                  </Rectangle.RenderTransform>
  46:              </Rectangle>
  47:              <Rectangle Fill="LightBlue" RenderTransformOrigin="0.5, 0.5" Grid.Column="5" Grid.Row="2" Grid.RowSpan="2"></Rectangle>
  48:              <Rectangle Fill="LightBlue" RenderTransformOrigin="0.5, 0.5" Grid.Column="5" Grid.Row="2" Grid.RowSpan="2">
  49:                  <Rectangle.RenderTransform>
  50:                      <RotateTransform Angle="-60" />
  51:                  </Rectangle.RenderTransform>
  52:              </Rectangle>
  53:              <Rectangle Fill="LightBlue" RenderTransformOrigin="0.5, 0.5" Grid.Column="5" Grid.Row="2" Grid.RowSpan="2">
  54:                  <Rectangle.RenderTransform>
  55:                      <RotateTransform Angle="60" />
  56:                  </Rectangle.RenderTransform>
  57:              </Rectangle>
  58:              <Rectangle Fill="LemonChiffon" RenderTransformOrigin="0.5, 0.5" Grid.Column="1" Grid.Row="2" Grid.RowSpan="2"></Rectangle>
  59:              <Rectangle Fill="LemonChiffon" RenderTransformOrigin="0.5, 0.5" Grid.Column="1" Grid.Row="2" Grid.RowSpan="2">
  60:                  <Rectangle.RenderTransform>
  61:                      <RotateTransform Angle="-60" />
  62:                  </Rectangle.RenderTransform>
  63:              </Rectangle>
  64:              <Rectangle Fill="LemonChiffon" RenderTransformOrigin="0.5, 0.5" Grid.Column="1" Grid.Row="2" Grid.RowSpan="2">
  65:                  <Rectangle.RenderTransform>
  66:                      <RotateTransform Angle="60" />
  67:                  </Rectangle.RenderTransform>
  68:              </Rectangle>
  69:              <Rectangle Fill="Thistle" RenderTransformOrigin="0.5, 0.5" Grid.Column="5" Grid.Row="0" Grid.RowSpan="2"></Rectangle>
  70:              <Rectangle Fill="Thistle" RenderTransformOrigin="0.5, 0.5" Grid.Column="5" Grid.Row="0" Grid.RowSpan="2">
  71:                  <Rectangle.RenderTransform>
  72:                      <RotateTransform Angle="-60" />
  73:                  </Rectangle.RenderTransform>
  74:              </Rectangle>
  75:              <Rectangle Fill="Thistle" RenderTransformOrigin="0.5, 0.5" Grid.Column="5" Grid.Row="0" Grid.RowSpan="2">
  76:                  <Rectangle.RenderTransform>
  77:                      <RotateTransform Angle="60" />
  78:                  </Rectangle.RenderTransform>
  79:              </Rectangle>
  80:              <Line Grid.Column="0" Grid.Row="0" X1="1" Y1="0" X2="0" Y2="1" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  81:              <Line Grid.Column="1" Grid.Row="0" X1="1" Y1="0" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" VerticalAlignment="Top" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  82:              <Line Grid.Column="2" Grid.Row="0" X1="1" Y1="1" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  83:              <Line Grid.Column="0" Grid.Row="1" X1="1" Y1="1" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  84:              <Line Grid.Column="1" Grid.Row="1" X1="1" Y1="0" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" VerticalAlignment="Bottom" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  85:              <Line Grid.Column="2" Grid.Row="1" X1="1" Y1="0" X2="0" Y2="1" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  86:              <Line Grid.Column="3" Grid.Row="1" X1="1" Y1="0" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" VerticalAlignment="Top" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  87:              <Line Grid.Column="4" Grid.Row="0" X1="1" Y1="0" X2="0" Y2="1" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  88:              <Line Grid.Column="5" Grid.Row="0" X1="1" Y1="0" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" VerticalAlignment="Top" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  89:              <Line Grid.Column="6" Grid.Row="0" X1="1" Y1="1" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  90:              <Line Grid.Column="4" Grid.Row="1" X1="1" Y1="1" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  91:              <Line Grid.Column="5" Grid.Row="1" X1="1" Y1="0" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" VerticalAlignment="Bottom" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  92:              <Line Grid.Column="6" Grid.Row="1" X1="1" Y1="0" X2="0" Y2="1" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  93:              <Line Grid.Column="0" Grid.Row="2" X1="1" Y1="0" X2="0" Y2="1" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  94:              <Line Grid.Column="2" Grid.Row="2" X1="1" Y1="1" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  95:              <Line Grid.Column="0" Grid.Row="3" X1="1" Y1="1" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  96:              <Line Grid.Column="1" Grid.Row="3" X1="1" Y1="0" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" VerticalAlignment="Bottom" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  97:              <Line Grid.Column="2" Grid.Row="3" X1="1" Y1="0" X2="0" Y2="1" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  98:              <Line Grid.Column="3" Grid.Row="3" X1="1" Y1="0" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" VerticalAlignment="Top" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
  99:              <Line Grid.Column="4" Grid.Row="2" X1="1" Y1="0" X2="0" Y2="1" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
 100:              <Line Grid.Column="6" Grid.Row="2" X1="1" Y1="1" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
 101:              <Line Grid.Column="4" Grid.Row="3" X1="1" Y1="1" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
 102:              <Line Grid.Column="5" Grid.Row="3" X1="1" Y1="0" X2="0" Y2="0" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" VerticalAlignment="Bottom" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
 103:              <Line Grid.Column="6" Grid.Row="3" X1="1" Y1="0" X2="0" Y2="1" Margin="-5 -5" StrokeThickness="10" Stretch="Fill" Stroke="Black" StrokeEndLineCap="Round" StrokeStartLineCap="Round"></Line>
 104:          </Grid>
 105:      </Viewbox>
 106:  </UserControl>

Tuesday, November 12, 2013

My adventures in Windows Phone 8 development

A couple of months ago, I attended VSLive in Redmond.  While I was there I sat in on a session on Windows Phone 8 Development given by Nick Landry ( @ActiveNick ). 

Since then I’ve signed up for a Windows Phones Developers Account ( Beer & Pretzel Games ), a DVLUP.com account ( My saunderl account ) and have published 3 apps (Tic Tac Toe, Sudoku Challenge and Simple Lap Counter).  None of these apps are going to set the world on fire, but it is a start and I’ve got a list of about twenty other apps and games I want to write.

So, for at least the next few posts, I will be writing about my adventures in Windows Phone 8 development.

Monday, November 30, 2009

How to create your own Silverlight Cube Control similar to Telerik's Cube

Well, as part of our lastest project, I needed to figure a way how to spin a widget.

So, how do you rotate widgets in an Asp.Net application? Well that question is fairly simple to answer - Silverlight!

The next question is much harder: Buy or Build?

After some searches I found two controls for sale: The Telerik Cube control and the ComponentOne C1Cube control.

So, first stop, download each and put them through the paces. I found a deal breaker for each control.

We need to be able to minimize our widgets but both controls had problems with that:
- The Telerik control would resize but would apply a transform to 'Squash' the widget and according to the Telerik website FAQ, this behaviour can not be overridden.
- The Component one control 'Must' be in the shape of a cube. Ok, I know that sounds like a 'duh' point, but like I said, we need to minimize our widgets. But when I altered the height of the control to just the height of the header, the cubes' width was also adjusted.

So, that left build - but there did not seem to be any examples of how to rotate a cube from side to side, on demand. I did find an example of a continuously spinning cube. With this example to decompose, I slowly taught myself the parameters and transformations that were needed to create the appearance of a cube spinning from one face to another.

So, here is my demo of a rotating six sided cube. If you do not need to rotate to the top and the bottom, you can have sides of any height, as long as all the sides are of the same height. Plus, my example is not limited to four or six sides. This example allows for an unlimited number of sides!

Now, there a couple of things that the professional controls do that my demo cannot. My code cannot free rotate and it also does not twist as it rotates to properly show a side. If you need these properties, you may want to go with the professional controls.

Here is the Visual Studio 2008/Silverlight 3 project.

Wednesday, August 19, 2009

The easiest way to convert vector graphics to XAML

Wow, this is sooooo simple. I've been converting WMF, EMF, CDX, CDR, AI, EPS, PDF and SVG to XAML all day. This is actually fun!

First get a vector graphic and a program that can open it. I've used Adobe Illustrator, CorelDraw, Inkscape and even Windows Picture and Fax Viewer.

Next get a vector graphic that your program can open.

Finally get the Microsoft XPS printer driver if it is not already installed.

Now open the file in your program of choice and print it to the XPS printer driver.

Now rename the resultant XPS file to ZIP.

Open the ZIP file and inside the Documents/1/Pages folder is a file named 1.fpage.

Extract the file and rename it to .XAML.

Now you have a XAML file that will open in Internet Explorer, but if you want to have a XAML file that will open kaxaml or for use in a WPF or a Silverlight application, open the file in notepad and replace the FixedPage tag with the Canvas tag.

Here is a XAML graphic I converted from my Corel Gallery. (Either open link in IE7/IE8 or download the XAML file and open it in your XAML viewer of choice)

Older posts from other blogs tell you to use Inkscape and print to PDF and then open the PDF in Adobe PDF Viewer. Fron the Adobe PDF Viewer you can then print to the XPS printer driver. The reason was that Inkscape converted the file to a raster image. Then and only then could you retrieve the 1.fpage file. This was because Inkscape sent the graphic to the printer as a raster image, not a vector image.

Well, since those blog posts were written, there have been updates to Inkscape, and now Inkscape prints a vector image as a vector, so there is now no need for converting it to an intermediate format (PDF).

Sunday, February 8, 2009

Fancy fonts in XAML (Silverlight and WPF)

Outline, Shadow, Embossed and Engraved text in XAML.

Here are a few quick and easy ways to spice of your text in XAML.

To use these tricks, you need to have the ability to exactly place the text. For that you need to use a Canvas Layout control.


<UserControl x:Class="SilverlightApplication2.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="320" Height="200">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions >
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Margin="3">
<Canvas Width="800" Height="60">
<TextBlock FontSize="36"
Canvas.Top="2" Canvas.Left="10">Outline</TextBlock>
<TextBlock FontSize="36"
Canvas.Top="2" Canvas.Left="12">Outline</TextBlock>
<TextBlock FontSize="36"
Canvas.Top="4" Canvas.Left="10">Outline</TextBlock>
<TextBlock FontSize="36"
Canvas.Top="4" Canvas.Left="12">Outline</TextBlock>
<TextBlock FontSize="36"
Canvas.Top="3" Canvas.Left="11"
Foreground="White">Outline</TextBlock>
</Canvas>
</Button>
<Button Grid.Column="0" Grid.Row="1" Margin="3">
<Canvas Width="800" Height="60">
<TextBlock FontSize="36"
Canvas.Top="5" Canvas.Left="4"
Foreground="Black">Shadow</TextBlock>
<TextBlock FontSize="36"
Canvas.Top="3" Canvas.Left="2"
Foreground="Gray">Shadow</TextBlock>
</Canvas>
</Button>
<Button Grid.Column="1" Grid.Row="0" Margin="3">
<Canvas Width="800" Height="60">
<TextBlock FontSize="36"
Canvas.Top="3" Canvas.Left="0"
Foreground="Gray">Engrave</TextBlock>
<TextBlock FontSize="36"
Canvas.Top="5" Canvas.Left="2"
Foreground="White">Engrave</TextBlock>
<TextBlock FontSize="36"
Canvas.Top="4" Canvas.Left="1"
Foreground="Black">Engrave</TextBlock>
</Canvas>
</Button>
<Button Grid.Column="1" Grid.Row="1" Margin="3">
<Canvas Width="800" Height="60">
<TextBlock FontSize="36"
Canvas.Top="5" Canvas.Left="3"
Foreground="Gray">Emboss</TextBlock>
<TextBlock FontSize="36"
Canvas.Top="2" Canvas.Left="2"
Foreground="White">Emboss</TextBlock>
<TextBlock FontSize="36"
Canvas.Top="4" Canvas.Left="4"
Foreground="Black">Emboss</TextBlock>
</Canvas>
</Button>
</Grid>
</UserControl>

Tuesday, November 11, 2008

Dynamically adding XAML strings from C#

In designing the screen for my silverlight game Switcheroo, I wanted to be able to dynamically add XAML chunks that represent the pieces (Ellipse). True, I could have just created the graphic elements property by property, but since the only difference between all the game pieces is if they are black or red, I thought that if it only took one or two lines of code, it would be a more elegant solution.

I wanted to separate the internal representation of the gameboard in the gaming object from the XAML front end. Then I could just clear the gameboard and recreate all the pieces after the gameboard object was updated. The question was, how?

Well I googled high and low but though I found many "solutions" to my problem, none of them worked. After trying different combinations of the aforementioned solutions, I got closer. This is my first try that made any headway:

const string red =
"<Ellipse Stroke='Black' Fill='Red' Height='30' Width='30' Margin='10,10,10,10' />";

LayoutRoot.Children.Add((Ellipse)XamlReader.Load(red));


But the error I got back was:

AG_E_PARSER_MISSING_DEFAULT_NAMESPACE [Line: 0 Position: 0]

Not a very helpful error message! Well, googling this error I found others that were getting the same error and a simple answer - the element must contain the same namespace. The only namespace is the one at the beginning of the XAML document thought. Well, I thought, it's worth a shot. So I added the namespace lines from the beginning of the element. Our code now looked like this:

const string red =
"<Ellipse xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' Stroke='Black' Fill='Red' Height='30' Width='30' Margin='10,10,10,10' />";

LayoutRoot.Children.Add((Ellipse)XamlReader.Load(red));


And low and behold! It worked!

So when you have lots of repetitious XAML or elements like named colors that cannot be easily replicated in code, just use the XAML string!