Monday, October 29, 2007
Disclosure
and
what I do mean,
more or less,
when working with big silverlight projects,
that at times,
it fills like 'hacking' some of the things we have todo to get things working.
So I don't mean to sanction anything illicite. and 'HackingSilverlight' just sounds cool.
I have this sample on my blog about wiring Silverlight into the browser history. This is an old flash trick and it works pretty good. But from my perspective as a dicplined programmer it is totally a hack. Not that it should not be done or anything its just as a professional we try so hard to do things the right way or the fastest way in the best way possible and are so proud of our cool algorythm or application and take pride in the attention to detail that we tend to be abit agast at solutions like this.
so thats why I say 'HackingSilverlight'.
JavaScript type casting
var SomeValue = "100";
var SomeNumber = 3;
// alert 1: "1003"
alert( SomeValue + SomeNumber);
// alert 2: "103"
alert( Number(SomeValue) + SomeNumber);
So this is where we can get a way with telling people 1 * 1 may not always equal 2... in this sample the first alert is going to make everything a string where as in the next one we cast the questionable value to a Number and now the math works right...
hmmm... whats the point of a varient if it can't figure out its a number.
Anyway so there is type casting in JavaScript
Friday, October 26, 2007
Silverlight Key Events In full screen mode...
Embedding Popfly Silverlight Mashups in Community Server
http://simonguest.com/blogs/smguest/archive/2007/05/23/Embedding-Silverlight-Videos-in-Community-Server.aspx
Creating a 'Path' Object in Silverlight
<Path Name=”MyPath” Stroke=”…” Fill=”…” Data=”…” …/>
At the very least, you may also use Canvas.Left and Canvas.Top or just place it in a canvas etc as well. A designer normally would be abstracted from actually building a path by hand but in cases such as building a pie chart one might want to write code to dynamically build slices of the pie chart programmatically and so therefore would want to know the syntax of the ‘data’ property on a path so they could compute it in their code.
How do I define a Path myself? To start with you must define a start point which is designated by ‘m’ (not case sensitive) and a point such as ‘M 10, 10’. You also need to define an end point which could be the same point so something like ‘L 10, 10’. So lets check out the types of things I can pass in.
If our start point is say ‘M 10, 10’ and we want to draw a horizontal line we can then do use the horizontal line command like this: ‘H x’ which might look like this then: ‘M 10, 10 H 150’. Next we can draw a line down using the vertical line command like this: ‘M 10, 10 H 150 V 150’ and if you use the L point from earlier we get a horizontal line and then a vertical line and a line from that point back to where we started which creates a triangle. (see the Path Sample Part 1).
So to get creative we can then use the Cubic Bezier Curve Command designated by ‘C’ so from the end point of our vertical line command we can then draw a Curve using 2 control points like this: ‘C 100, 100 200, 200 50, 50’. This shape would then give us this funky triangle shape with a weird ‘foot’ at the bottom.
We can also use the Quadratic Bezier Curve Command which would be ‘Q point1 end point’ where point 1 is our control point we could use the ‘Smooth Cubic Bezier Curve Command that is ‘S point1 end point where point1 is the control point for a regular curve or use ‘T’ to make the curve quadratic.
My favorite command is the Elliptical Arc Command which can be used to create a slice curve such as the curve of a pie slice. The syntax is ‘A size rotationAngle isLargeArcAngle sweepDirectionFlag endpoint’. These are the following:
· Size: this is the radius of the arch in pixels
· Rotation Angle: is the angle of rotation of the curve in degrees
· ‘Is Large Arc Angle’: is a flag that sets the render of the arch to be 180 degrees or greater if set to 1 where the default is 0
· ‘Sweep Direction Flag’: is a flag determining if the arc is to be drawn from a positive angle or not from the point if set to 1 but default is 0
· ‘End Point’ is just that the X,Y end point of our Arc
So if we use an arc definition like this: A 50, 50 200 1 0 100, 100 added to our sample (see Path Sample 3) we get a crazy but cool shape. That you really have to see to understand… note how the fill is applied effectively making 2 ‘shapes’. The entire definition would look like this:
<Path Name="PathElement" Data="M 10, 10 H 150 V 150
C 155,155 160,160 140,165
A 50, 50 200 1 0 100,100
L 10, 10"
Stroke="#3c5f0c" StrokeThickness="3"
Fill="#728f4a"
/>
Check out the SDK for more detailed on Path definition syntax or paths in general.
Silverlight 1.0, JSON and (gasp) PHP
JavaScript Class Structures
So it turns out that if I declare my class with its properties and then declare using prototype my methods then all instances of the class use the same method. this is also how to extend core classes as well. (dah, as I have seen that before) So then the new rule is that proper javascript class declarations should look like this:
function myclass()
{
this.WhateverProperty = "";
}
myclass.prototype =
{
Method1: function( param1, param2 )
{
// some code
},
method2: function( param1, param2 )
{
//some more code
}
}
Yes I know my curly braces are matching and not the OLD school javascript standard but will all the other languages it just seems to be that JavaScript should follow suit, anyway this is how a javascript class should look like until I am proved otherwise... (hmm. setting my self up again). :)
Silverlight Host Loosing Mouse Capture...
So now we have framed the problem here is how we solved it. So even though the media player visually one size when we first catch the mouse down on the drag corner we actually change the size of the underlying aghost for silverlight to be an extra buffer of so many pixels. So now the aghost makes it much harder for the user to get the mouse off of the silverlight surface so we basically run around the screen and chase after the mouse. On drop then we resize the aghost to match the current drag corner position. On IE this works really well, on firefox it is more problematic but does work well if done correctly. On Safari on the Mac the drag works well but Safari is generally more touchy around the html dom.
Another point or rather surprise for me was making this same player work on Safari on the Mac... lets not get confused with Safari on windows which as of this post blows up on contact with silverlight. But anyway. on the Mac, Silverlight runs as smoothly as in IE especially with this particular mouse capture issue. Hmm... makes me wonder if it is just Firefox...
Path Performance Issues in Silverlight
Parsing XML in Silverlight 1.0 - Cross Browser
So the XML Mini me is a simple XML parseing engine written in Javascript. It only supports a limited subset of something like the real xml parser in .NET like XMLReader or even XMLDocument but it does so a few simple things including some simple xPath like behavior. I hestiate to say a subset of xpath as the mini me is so extremely limited. I also suspect that the silverlight team at some point will have a good XML parser built in to silverlight at some point but we will see. there is of course Silverlight 1.1 but if you can't do the .NET part it doesn't do much goo.
In Silverlight, you have the downloader object so its really reasonable get XML easily no matter what. So then using the XML mini me looks something like this:
var MyDom = new XMLDocument();
MyDom.LoadXML( SomeXML);
I tried to keep the syntax as famliar as possible. So now we have our XMLDOM called 'MyDom' and then to get data out we can do this:
var ArrayOfVAlues = MyDom.SelectNodes("//items");
In this case the mini me will return all the text values of all the items nodes in the dom in the form of an array. Underneath the covers the parser is just doing some 'string' manipulation but for small groups or data or simple RSS feeds or config files it seems to work well. large XML parseing would scary me preformance wise as would writing a more full featured parser that is entirely written in JavaScript.
Some things to note on the class is that it has an XML property like the XML parser we used to use in classic ASP but otherwise it only has two methods currently as those are the ones I need to get it working for my particular project. lets look at the XML it can deal with for starters, here is a sample:
So in this sample using some simple xml our parse deals with it easily. In this case when we make a call to SelectNodes("//url") we will get an array of all the urls values with all the < ! [ CDATA stuff stripped off into an array. simple, easy and fast but easly breakable if you muck up the xml to much. So for the time being its a great stop gap and if JavaScript works then this works at it uses only intrinsic language features.
So the little XML mini me is great for simple stuff but when you really need to do real work with XML you really need a more robust solution that includes a real XML parser. Now that can prove problematic especially when it has to work in lots of browsers. To address this problem with my own work I wrote another class that wraps the cross browser functionality and wraps some key elements that I use. Typically I need things like all of properties of a given node in a list in the form of an array. Plus things like xPath and the like for Silverlight.
So the attached javascript class wraps the core functionality. It includes the HTTP request functionality and XML parsing with the other bits I 'might' need. Basically the class works like this:
var NewDOM = new XML();
NewDOM.Load("Sample.xml");
This code fires when the html page script code behind fires. When you call 'Load' and pass a url to an xml file it then depending on the browser it uses the appropriate HTTP request object to load the file and assign the onload event. On the XML files load the call back is called and the object does the appropriate processing. Once this does its thing we now can use it to parse our XML.
On the onload event for the page in my little test I make two calls to different methods. The same methods are supported on this class as the XML mini me but additional ones are included like 'SelectNodesAttributes'. Also I noticed in firefox by 'onload event gets called twice so I put a flag on it so it only fires once. So in this sample I call the two methods that return arrays but you can have direct access to the DOM and use xPath etc using NewDOM.XmlDocument.
Building a TextBox in Silverlight 1.0...
In building a text block there are a number of key bits of functionality we need todo: making the control look like a text box, making the text box behave with focus like a text box (have a cursor) and getting key board events into the text box. If you can address these then things like wrap, overflow and size ratio's etc are pretty straight forward.
Actually making a control to look like a text box is not too hard. Basically we have a canvas with a nice boarder in XAML and you can make something that looks like a text box. In this case something like this:
Nice and simple. Now that it 'looks' like a text box we need to have a cursor when it gets focus... For the cursor you can do a number of other things but lets start with a little line rectangle. We set the size and starting position in our XAML and then make it invisable. In our code behind we wire up an event on the box so that on 'MouseLeftButtonDown' we get the event and set the 'textbox' into a focus state. Basically these means we set a flag, changed opacity and started an animation on the cursor to make it blink.
Now our text block looks like a text block when we click on it and the cursor shows up... Now we need to actually make it work. Todo this we can add a text block element and wire an additional event to the document object of the page to capture keyboard events. In our keyboard event handler we need to check the key codes against our look up table so we know what they mean and add the character to our text box. If we run our text block now we notice that this appears to work but the cursor doesn't move. So then we make our event handler move the cusor as well.
So in less then a few hundred lines of code we have a working text box. From here we now need to be able to deal with text overflow moving the cursor back and forth and sizes and ratios. When the control is wrapped nicely in a class and xaml file we can use it in our projects by just creating the class and passing in a destination or target and 'poof' instance text box. Almost like its built in.
Now to see if anyone is actually reading the blog... If any one is interested in the code let me know. :)
Ok Ok, so it seems some one actually does really read my blog. :) I feel much better so I'm going to post more on the text box.
Lets start by updating our xaml a bit.
now we have added the cursor and textblock we talked about earlier. In our code behind we have our event handler called:
TextBox_OnKeyPress and an initialization routine called InitTextBox. In the onload event we then call our iniatilizer and wire up the key press event handler. Now the trick here is that we are not wiring anything to 'silverlight' persay but in IE we wire it up to the document object like this:
function onload(sender, args)
{ InitTextBox(sender); document.onkeyup = TextBox_OnKeyPress; }
Ideally this all is wrapped in a consumable control which I'm will finish when I finish this cool char size algorythm so everything isn't hard coded but in the mean time this example uses a number of present values in the xaml and things like font size and base increment in the code. Also there is a GetWidth function with hard coded values that is used for moving the cursor on the text box surface.
So back to our function InitTextBox(sender). In the sample I did initially this function basically saves some references to different parts of the control such as the cursor and text box for manipulation and then it adds an event listener to the text box canvas. This function is around actually giving the control 'focus' effectiving. There are a few other things you might want todo that is not in the sample like code for getting the control out of focus etc. So our add event in the initializer looks like this:
TextBox.addEventListener("MouseLeftButtonDown",
function( sender, args )
{
IsTextBoxMouseCaptured = true;
TextBoxCursor.Opacity = "1";
CursorAnimation.begin();
} );
So when some one actually clicks on to the control we set our flocus flag to true and turn the cursor on by setting the opacity and turning on the blink animation.
Back to our key press event. This guy remember we wired up to the document object but we only want to get events when the control has focus. That means in the event handler we need to test for the flag and if true then we can do something. Here is a sample:
function TextBox_OnKeyPress()
{
if( IsTextBoxMouseCaptured )
{
var EventCode = Number(event.keyCode);
switch(EventCode)
{
case 48: SetCharacter( "0", ")", event.shiftKey );
break;
case 37:
TextBoxCursor["Canvas.Left"] = LastPosition();
break;
}
So in this case we see the flag test and then we grab our 'EventCode' from the keyboard and we use a case statement to determine what character this is and what todo. To make the example easier I removed all but two character examples. The first case we are dealing with the zero/close paren key. Note we call a function called SetCharacter and pass in three events. The SetCharacter function gets the current shown text, determines which charater we want based on shift condition adds the charater to the real text value we keep in a variable and then determines what text is to be shown places the text and calculates the cursor position based on another function called GetWidth which determines all the offsets from the base character size (this is the one that needs the cool algorythm so all the values are not hard coded...).
The last case is a move back button which calls the 'LastPosition' function and moves the cursor based on the character behind it. So that is basically all the key aspects of doing a text box in Silverlight 1.0.
}}
ASP.NET Server Controls in VS 2008 and .NET 3.5 and Sharepoint
Today is going to be a bit of a rant. Background on the issue is that in VS 2005 I have written server controls for ASP.NET and Web Parts for Share Point. Typically for building Share Point web parts I like to developement them as server controls to so I have this nice easy structure to work with until I have something that does basically what I want. The trick with a server control is basically basic C# stuff. First you make a class and inherit from your base control and then you overwrite a method and add some declaritive stuff and then you can use it on your page by using a register in the ASPX. Then you can use your tag to create an instance of your control. Also this can then be put into its own dll and added to VS's toolbar and you can pass the dll around to friends etc and everyone can have this cool dll. Now to turn the control into a web part basically you change the base class, add a few using statements and change the output method name, make sure its all in a dll and your good. So far so good right?
For a server control, the class basically looks like this:
[ToolboxData("<{0}:SomeName id=\"\" runat=\"server\" />")]
public class SomeName: System.Web.UI.WebControls.WebControl
{ protected override void Render(HtmlTextWriter writer)
{
writer.Write(PresentHTML()); // some method we make...
}
}
We also add a few bindable properties like id or width or title or something that might look like this:
private string _Id = string.Empty;
[Bindable(true), Category("Appearance"), DefaultValue("")]
public string id
{
get
{ return _Id;
}
set
{ _Id = value;
}
}
Again straight forward stuff. right? We also might add other functionality of course and we have it in a name space but this is the key bits above. Now to turn this into a 'WebPart' we make it look something like this:
[DefaultProperty("Text"),
ToolboxData("<{0}:MyWebPart runat=server>{0}:MyWebPart>"), XmlRoot(Namespace = "MyWebPart")]
public class MyWebPart : WebPart
{
private string _Id = string.Empty;
[Bindable(true), Category("Appearance"), DefaultValue("")]
public string id
{
get
{ return _Id;
}
set
{ _Id = value;
}
}
protected override void RenderWebPart(HtmlTextWriter writer)
{
writer.Write(PresentHTML()); // our private method that does the real work...
}
}
not a big change and again pretty straight forward. I dont' show all the properties and methods like the one reference to 'PresentHTML' which is just a private method that returns a string. This is the basic stuff needed for sharepoint. The one other thing is to make sure you have the using statements that reference all our Sharepoint bits:
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.WebControls;
and of course the sharepoint dll that your building to needs to be referenced. So to use the server control version you have to create a Register tag in your ASP.NET that looks like this:
<%@ Register TagPrefix="prefix" Namespace="ControlNameSpace" %>
then in the ASPX page we can add the tag for our control to test it without all the jumping around you need todo with Share Point. In this case it might look like this:
This is 'All Good' in VS 2005 but the other day (earlier this morning) I had to make it work in VS 2008 for embededing a webpart 'Silverlight' control into Sharepoint. So I got to the test page of the silverlight project and do basically the above and make a web part that writes out all my Silverlight stuff (actually it was Devin's Silverlight app). This way we care wire up bits that the web part needs to pass into the Silverlight class todo its thing for when it actually has to live in Sharepoint. I would have thought this easy enough...
So I add the class and set it up as a server control. I add the references, and the register for the tag prefix and namespace reference and then add a tag to the control that should create the silverlight app. I compile it and try to run it and it blows up entirely. After fighting with this for some time it turns out that you need to have an 'Assembly' reference in the register tag in VS 2008/.NET 3.5 for a server control to be able to run in ASP.NET 3.5. So then it looks something more like this:
<%@ Register TagPrefix="prefix" Namespace="ServiceNamespace" Assembly="SilverlightApp" %>
The part that bothered me is that if the class is in the same assembly as the rest of the site and we call out the name space and class specifically it should be able to find the default assembly since its run in that assembly... but alas I was wrong. Not that, that is a surprise but it always seems to surprise me when I am. :)
Silverlight 1.1 As A Sharepoint Web Part
Silverlight Site Configuration
1. Copy the Silverlight Website folder to Server Location.
2. Open IIS Manager (Start-> All Programs -> Administrative Tools -> Internet Information Services (IIS) Manager)
3. Open Server Node (local Computer)
4. Open ‘Web Sites’ node.
5. Open Default running web site node
6. Right Click web site node and select New -> Virtual Directory
7. When the Virtual Directory Creation Wizard comes up click next
8. Enter the correct Alias ‘[some name]’
9. Click ‘Next’
10. Click ‘Browse’ and find the physical location of the site directory by drilling down in the ‘Browse For Folder’ and then select ‘OK’
11. Click ‘Next’
12. Select ‘Run Scripts’ check box
13. Click ‘Next’
14. Click ‘Finish’
Web Part Configuration
1. Make sure the wep part project is compiled.
2. Copy the project to the Sharepoint server.
3. Copy the WebPart.dll to the bin directory under the wwwroot.
4. From the VS command prompt navigate to the bin directory under wwwroot.
5. gacutil the dll which should look something like this: gacutil –i WebPart.dll
6. from this same location in the VS command prompt use the command: sn –T WebPart.dll to find the strong name key. For example: 7dd6db7c5d0189b7
7. Find the Sharepoint Web.config by opening up the IIS Manager and selecting the core site and then right click on the web.config and file the file location.
8. Add a ‘safecontrol’ node to the safecontrols section like this:
PublicKeyToken=7dd6db7c2d0088b7"
Namespace="[some name space]"
TypeName="*"
Safe="True"
/>
9. Make sure the dwp file has a valid public token.
10. Go to the Sharepoint home page.
11. Click Site Actions and select ‘Show Page Editing Toolbar’
12. Click Page button in the toolbar.
13. Select ‘Add Web Parts’ -> Import
14. Click Browse and find the dwp file in the project.
15. Click ‘Upload’
16. Select ‘Add to: Top Zone’
17. Click ‘Import’
18. Close the import right hand bar
19. Select publish from the toolbar
So I'm not saying this is the right method or the best way todo it but it worked for me in my case... abit of a hack but well its Sharepoint :)
Wiring Silverlight Into the Browser History/Back Button
So lets look at that in more detail. Starting from the page that hosts our Silverlight application we can see that there is a script include. That script file includes our class and at the bottom of the page is our initialization code.
In the block of script at the bottom we have two lines of code. The first creates a global reference and instance of our class and the second line calls the Init method. If we go to our class source and go to the Init method and all it does is do a document.write and inserts an iframe that our class will use to create history paging entries.
In the paging prototype we also see two other methods. The method 'AddPage' loads page proxies into our iframe to create entries using our key value.
SilverlightPager.AddPage( "somevalue that indicates state");
in my sample project we just use an indexer in our Scene object on on mouse click on the button this happens:
// Put clicked logic here
this.indexer++;
SilverlightPager.AddPage(this.indexer);
Our next method is called 'OnReturnPage' which is actually called by our proxy pages. So in our Silverlight application we call 'AddPage' and pass in a key value each time we change state in and what that to be a history point. In our sliverlight load we also need to associate a delegate to the 'PagingDelegate' member of our class like this:
SilverlightPager.PagingDelegate = MyAppChangeStateHandler;
This will then be called each time our application calls 'AddPage' or clicks the browsers history button. In both cases the page proxies are going to call OnReturnPage and pass in our path which will have the key as a querystring value that we then strip off and pass into the PagingDelegate to change the application state. So then we get a little Flash Magic Mojo for our Silverlight app.
Popfly goes Beta
http://www.popfly.com
Silverlight - Associating Files in Visual Studio
So here is a Visual Studio trick I picked up from Josh in WPF land that applies to Silverlight. One issue we found in Silverlight was when we were building big Silverlight applications and custom user controls that the XAML and .js files were not associated to each other. But in Visual Studio if you know what todo its pretty straight forward. Then yoru 'XAML files can have JavaScript code files even if created seperating with different names.
Here is how you do it. When you silverlight solution and project is open in Visual Studio Right click on the project in the visual studio solution explorer. Click 'Unload Project'. If the solution is tied to Source control you will get a dialog 'Attempt to unload projects with shared checkouts' and you can select the option you want. So assuming you select 'continue' then the project is unloaded. Right click on the project and select Edit [project filename].csproj. You will see the project file open up in a raw xml edit mode. Fine the 'itemgroup' collection that has the file you want to make dependent on another file. Add a 'DependentUpon' node to the node that is your file and put the name of the file you want your file to be under. Save and close the project file. Then you right click the project and click 'reload' the project.
Its a cool trick and sure helped me clean up a few huge messy projects.
Silverlight, JSON and Automatic Design Asset Zip and index generation...
From an architectural stand point this is a much cleaner method of keeping additional assets packaged especially when there is a lot of xaml and images etc and keep it as small as possible over the wire. Silverlight allows us to address all that by being able to download zip files. On the downside there is not dynamic way to know what is in the zip file and plus it is a pain to have to do it on your own. So this is how I addressed it.
First I built a windows application project in Visual Studio without any windows. I added directories with all my design assets and set them to be content and show up in the output directory. When you compile the project it builds out the executable and copies all the folders and assets added to the project to the output directory. From here Visual Studio starts the application. Although it doesn't have a UI persay it starts by looking for any zips that might be in the directory and deletes them.
Now the cool part happens... it looks at all the diretories and creates an index JSON file for each folder. It saves these all in the root of each directory and then proceeds to create zip files for each directory automatically. All I need todo is then have this projects zip files that are generated in the output folder be copied to my Silverlight project directory structure as a pre or post build event and I'm good. All these additional assets are kept nicely packaged and out of the main project. And I didn't have to mess with it on my own.
Also note that the attached project doesn't have the zip.exe that builds the zip via console commands passed to it. You can use the command line version of any thing like pkzip etc but you will have to edit the source of the main application to make it work. I have my own licensed copy of this command line tool that (pkzipc.exe) which is what the argument structure is designed for.