in

WPF Design and Development

IdentityMine Team Blogs

David Kelley

A day in the life of a humble software architect... doing C#, WPF, Silverlight, Legos, Fuzzy Logic AI and/or whatever is the latest and greatest or more importantly the coolest techo mumbo jumbo...

Building a TextBox in Silverlight 1.0...

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:

  <Canvas x:Name="TextBox" Canvas.Top="10" Canvas.Left="10" Height="13" Width="100" Cursor="Hand" >
   <Rectangle Name="TextBoxBackGround" Height="13" Width="100" Fill="#FFFFFF" Stroke="#999999" StrokeThickness="1" >
   </Rectangle>
   <Rectangle Name="TextBoxBackGround2" Height="13" Width="100" Stroke="#999999" StrokeThickness="1" >
    <Rectangle.Fill>
     <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
      <GradientStop Color="#00000000" Offset="0"/>
      <GradientStop Color="#33333333" Offset="1"/>
     </LinearGradientBrush>
    </Rectangle.Fill>
   </Rectangle>
  </Canvas>

 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.

  <Canvas x:Name="TextBox" Canvas.Top="10" Canvas.Left="10" Height="15" Width="150" Cursor="Hand" >
   <Canvas.Resources>
    <Storyboard x:Name="CursorAnimation" >
     <DoubleAnimation
      Storyboard.TargetName="TextBoxCursor"
      Storyboard.TargetProperty="Opacity"
      To="0"
      From="1"
      RepeatBehavior="Forever"
      Duration="0:0:.5" />       
    </Storyboard>
   </Canvas.Resources>
   <Rectangle Name="TextBoxBackGround" Height="15" Width="150" Fill="#FFFFFF" Stroke="#999999" StrokeThickness="1" >
   </Rectangle>
   <Rectangle Name="TextBoxBackGround2" Height="15" Width="150" Stroke="#999999" StrokeThickness="1" >
    <Rectangle.Fill>
     <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
      <GradientStop Color="#00000000" Offset="0"/>
      <GradientStop Color="#33333333" Offset="1"/>
     </LinearGradientBrush>
    </Rectangle.Fill>
   </Rectangle>
   <TextBlock x:Name="TextBoxText" Width="148" FontSize="12" Canvas.Left="1" FontWeight="Normal" Foreground="#000000" ></TextBlock >
     
   <Rectangle x:Name="TextBoxCursor" StrokeThickness="1" Height="12" Width="1" Fill="#999999" Canvas.Left="2" Canvas.Top="1.5" Opacity="0" ></Rectangle>
  </Canvas>

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. 


 }
}

Comments

 

david.kelley said:

I would like to use the code for creating Textbox control in silver light. 

- prashushetty

September 28, 2007 4:31 PM
 

david.kelley said:

I saw your post on how to implement an input cursor in Silverlight and I'm sure this translates to WPF too, but I'm still relatively new to WPF so I was hoping for some help. I have a FlowDocument that I will be adding text to throughout a program, kind of like a log file. At the end I want the user to be able to type a sentence, have it show up within the content of the log in bold, and then continue adding to the log from my program. So the trick is to create a cursor, like a greater than sign ">" with the blinking cursor afterwards and make input possible. Once the user hits [Enter], the text would turn into a bold paragraph block, I would add more paragraph blocks, then enable the input again.

If you could help with this, I'd be grateful.

David Cornelson

October 11, 2007 9:47 AM
 

david.kelley said:

Building a Silverlight 1.0 text box doesn't translate as well to real WPF as you might think.  First WPF has a real text box.  Inside a WPF you can create the same kind of thing but if you use a text box and just style it to look the way you want I think this would be a better model then building a text box from scratch.  You could of source build such a thing but I don't see a reason.  In the context of WPF you basically can do anything you want.

October 11, 2007 9:53 AM

About david.kelley

David for the past 10 years has focused on distributed application design and emerging Microsoft technologies on the web. Having helped design and build some of the largest systems for companies like Microsoft, Onyx Software, Saltmine, Giordanous Group and more and of course our favorite company Identitymine, he has been on the leading edge of applying the latest tech to real world business problems. David’s technology breadth includes everything from SQL Server to Windows/WCF and Silverlight. David’s accomplishments also include developing new technologies such as self editing XML files and related XML technologies to fuzzy logic systems and advanced web user interface design.
© 2007 IdentityMine, Inc.
Powered by Community Server (Commercial Edition), by Telligent Systems