One of the problems I have seen a lot of is building full blown forms in Silverlight 1.0. For the most part, Silverlight apps have placed HTML over Silverlight. This certainly works, albeit not the ideal situation and Silverlight 1.1 promises to deliver us a real text box. However, in the mean time, I decided I needed a 'Silverlight 1.0' text box. So here is how I made one work.
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.
}}