Friday, 5 December 2008

HTML header + Silverlight plug-in scenario

Suppose you want to display a Silverlight plug-in that occupies the whole browser window. That's easy, right? You just don't specify explicitly the height and width of your UserControl in Page.xaml and give the plug-in 100% height and width in the hosting HTML page. That way when you resize the browser window, the plug-in resizes accordingly.

But what if you want to have a static HTML header - say, a div element - at the top of the page and let the Silverlight plug-in occupy the rest of the page? If you just add the header div and give it a static height of, for example, 150px, you'll get a vertical scrollbar and part of the plug-in will be off the screen, which is not what you want. To achieve the desired effect, you must subtract the height of the header div (150px in our example) from the height of the Silverlight plug-in every time you resize the browser. So here's a way to do that using JavaScript.

First, you create this function:

<script type="text/javascript">
function resizeSLHost()
{
var docHeight = document.body.offsetHeight;
var pluginHeight = docHeight - 150;
var slplugin = document.getElementById("silverlightControlHost");
slplugin.style.height = pluginHeight + "px";
}
</script>

Then, in your opening body tag, you say:

<body onload="resizeSLHost()" onresize="resizeSLHost()">

And you place your header div right before the Silverlight host div:

<div id="header" style="height:150px">
// header content goes here...
</div>
<div id="silverlightControlHost">
<object data="data:application/x-silverlight-2" type="application/x-silverlight-2" width="100%" height="100%">
// the usual stuff here...
</object>
<iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
</div>

Of course, the number you subtract from docHeight in resizeSLHost() must be equal to the height of the header div.

That worked for me in IE 7 and Firefox 3.0.4. It worked better in IE, though. In Firefox there was some latency and choppiness. So if you know a better way to do it, please drop me a line in the comments.

Regards,
Boyan

Tuesday, 18 November 2008

A thought on Microsoft and open source

I've be been browsing the Ajax Control Toolkit project on Codeplex the other day. They describe it as "a joint project between the community and Microsoft". That sounds pretty good and is in line with what we've been hearing lately about Microsoft going towards "more openness". They even have a nice-looking tool for letting people submit their patches easily, as well as some stupid calls to action - you should submit patches and "be prepared to handle the paparazzi", they say, and also it's "your chance to socialize" (... said the spider to the fly!).

OK, nothing too disturbing so far, except the aforementioned appeals, which are really awful, but let's think about something else. Let's see what happens after you download the open-source, "community-driven" (is it?) toolkit. It's not a stand-alone application, so in order to use it, you have to stick it in Visual Studio. No problem, right? You just open up the source code of Visual Studio... Stop, this will not do. You don't have the source code of Visual Studio, it's proprietary. (Or if you happen to have it - give me a call and we'll discuss the price!). So, in the end of the day, what happens is that an open-source project is used to enhance and improve a proprietary product. I don't know how you feel about that, but for me it makes the whole philosophy of open source crumble upon itself. To really prove it's taking course towards "openness", Microsoft should say "b" after they've said "a" and make Visual Studio open source as well. Then, let's see - what about the platform VS is running on? Shouldn't it also... But no, that's too scary to think about.

Anyway, if Microsoft's "openness" stops here, then I suppose what they are doing is they just got lazy one day and said, why should we fix our own bugs when we can let someone else fix them for free? We'll give'em a badge or somethin' and they're gonna be happy...

When it comes to open source, Microsoft is still a toddler. Let's hope they grow up quickly and take the right steps - and maybe tomorrow we'll see things that today we can't even contrive. To tell you the truth, I'm a bit skeptical about that - but who knows what the future holds?

Regards,
Boyan

Sunday, 16 November 2008

The Number class and the Calculator app updated

I've updated my Number class, as well as my Calculator for Silverlight that uses it.

I've made the Number class immutable and fixed some other minor issues, and I've fixed a bug in the Calculator that was causing the zeros at the end of a floating-point number to disappear if the Negate button is clicked. The current version of the Number class is 1.5.5, and of the Calculator app - 1.5.

Disclaimer. The Number class is far from finished. I intend to do some work on improving it, but first I might have to brush up on my algorithms. So it's going to be shelved for some time - but it's not going to be forgotten!

Regards,
Boyan

Calculator for Silverlight

Wanna do some math? Be my guest:



Nothing to explain here, I guess... Just your average run-of-the-mill calculator. It's implemented as a custom control, so all you have to do in order to use it is declare it in your XAML file:


<Grid x:Name="LayoutRoot" Background="YellowGreen">
<calculator:Calculator Height="200" Width="300"></calculator:Calculator>
</Grid>


If you don't want to push the buttons with your mouse, you can use the keyboard shortcuts. Of course, the Silverlight plug-in must have the focus. The shortcuts for the digits don't need elaboration, I believe. And here are all the rest:

  • A - Add

  • S - Subtract

  • M - Multiply

  • D - Divide

  • E - Equals

  • C - Clear

  • N - Negate

  • F - Floating point


To be able to work with very large numbers, the Calculator uses my Number class - more about it here.

Well, that's all for now... Happy calculating!

The source code for the Calculator is here.

Regards,
Boyan

Saturday, 15 November 2008

((int + double + decimal + ... ...) == Number), or How to not care

I'll start that off with a little dramatization.

Me: Give me a number, please.
The compiler: What kind of a number would you like, sir? We have ints, we have longs, we have de-ci-mals...
Me: Don't know. Don't care. Just a number - you know, one-two-three... A number.
The compiler: I'm afraid that won't do, sir. You'll have to be more specific.
Me (frustrated): Will you give me a ... ... ... NUMBER, you ... ... ... ... ... of a ... ... ... !!!!!!!
The compiler: Sir, you'll have to leave now.

OK, so the point is - what do I care what kind of a number? Just a number! The .Net Framework has gone to great pains in order to abstract away many of the boilerplate programming tasks, but the .Net languages still retain the numerical types system inherited from C - and even add new types! So you have to choose between ints, longs, sbytes, etc., etc. And you always stick in ints anyway, right? Granted, for some more specialized sorts of applications you still need the different numerical types. But for your everyday programming, wouldn't it be nice if we had something like a generic Number type that can hold any kind of number, be it int or float or decimal? And why should it be limited to decimal.MaxValue? What if I want decimal.MaxValue + 1?

What I have in mind is a class that represents a number as a list of digits. That way the only limitation for the size of the number is going to be your available memory. And you'll save space, because the list will contain just as much digits as you need. If you have the number 1, all the memory you need is the memory to save one digit. If you stick 1 in a decimal, it remains as obscenely big as if you put in a billion.

To try that idea in practice, I've devised a simple Number class that holds its digits in a LinkedList<int>. I've overloaded the arithmetic operators, so you can do something like that:


Number biggerThanTheDevil = decimal.MaxValue;
biggerThanTheDevil *= decimal.MaxValue;
biggerThanTheDevil *= decimal.MaxValue;
biggerThanTheDevil += 1;
// And so on, and so forth


Also, you get some additional functionality for free - like adding or removing digits from both ends of the number:


Number shrinker = new Number("1234567");
shrinker = Number.RemoveLastDigit(shrinker); // shrinker == 123456
shrinker = Number.RemoveLastDigit(shrinker); // shrinker == 12345
shrinker = Number.AppendFirstDigit(shrinker, 9); // shrinker == 912345


The Number class is immutable, so you can assign one Number to another by simply assigning the reference:


Number srcNumber = 12.345;
Number destNumber = srcNumber; // No problem - the class is immutable



There's one more difference I'd like to point out. I've overloaded the << and >> operators, but I've let them perform decimal shifts, not binary ones. That means that (10 >> 1 == 100) and (234.5 << 2 == 2.345). I think that is a better and more intuitive way for these operators to work in a high-level framework as .Net. Anyway, it's just an experiment.

The Number class is really just a simple show-case. The algorithms I've come up with for the arithmetic operations are not the most optimal as I'm not that good at maths. But if something like that gets implemented by a better developer than myself and then is included in the core .Net functionality, I think we'd all benefit.

In the end I'd like to say that I intend to re-write the Number class in C++ using direct memory management to see what performance boost will I get. When I have some results, I'll post them here.

The source code for the Number class is here.

PS: I've asked a question on StackOverflow (an excellent site, by the way!) about some aspects of the Number class and I've got some very good replies that helped me improve it. Thanks goes out to Jon Skeet and cristianlibardo.

Regards,
Boyan

Saturday, 8 November 2008

ProportionalPanel - custom control for Silverlight 2

Everybody's doing custom controls for Silverlight - so why shouldn't I?! Here's my contribution to the ever-growing army, complete with a test harness for showing-off purposes. Just add some buttons and then tweak the settings. The explanations follow.



It's a ProportionalPanel and what it does is, of course, it arranges its subelements proportionally. If you don't set the RowsCount or ColumnsCount properties (or set them to zero), the panel tries to keep the number of rows and columns as equal as possible. You can override that behavior by specifying the aforementioned properties. But if you give them invalid values, the panel reverts back to its default behavior. An example of invalid values is setting RowsCount to 3 and ColumnsCount to 4 when you have more than 12 subelements. In any case, the elements are always equally sized.

If you have an "orphan row" (a row that has less elements than the others), you can choose whether to place it as the first or the last row via the property OrphanPlacement, which takes the value "First" or "Last". The default is "First".
A typical way to declare a ProportionalPanel in XAML is:

<proppanel:ProportionalPanel x:Name="PropPanel" Background="YellowGreen"
RowsCount="3" ColumnsCount="5" OrphanPlacement="Last"
Margin="5">
<Button Content="Click me!">
<CheckBox Content="Check me!">
<!--And other controls...-->
</proppanel:ProportionalPanel>

Of course, you can also fill the panel's Children collection programmatically.

Don't forget to reference the panel's assembly and insert the proper namespace in your XAML file like this:

xmlns:proppanel="clr-namespace:ProportionalPanelProject;assembly=ProportionalPanel"

One possible usage of the ProportionalPanel is if you are doing some kind of a board game, you can use it for the board and just stick in some Rectangles, TextBlocks or full-blown custom controls for the board tiles.

Disclaimer. My oh-so-beautiful Minesweeper was a previous project, so it doesn't use the ProportionalPanel.

The source code is here. Take a look at MeasureOverride() and ArrangeOverride() to see how the logic goes. I've commented them to help you out.

Note. The download includes the test harness shown above.

Regards,
Boyan

Thursday, 6 November 2008

A Silverlight Minesweeper



Here's a simple Minesweeper-like game for Silverlight 2. It was mainly a programming exercise, so there aren't too many multimedia bells and whistles. Just a smooth transition when you open a square, and that's all. No sound. No explosions. No high score. No mines - just the letter 'M'. No automatic opening of tiles. Feel free to add the missing licks, if you like.
The board square is a Custom control with two states - "Opened" and "Closed", and two parts - a TextBlock that contains the number of adjacent mines or the letter 'M' if the square is a mine, and a Rectangle that initially covers the TextBlock. When you click a square, the state changes and the Rectangle's opacity goes to zero, thus showing the TextBlock underneath. Here's the relevant part of the ControlTemplate:
<vsm:VisualState x:Name="Closed"></vsm:VisualState>
<vsm:VisualState x:Name="Opened">
<Storyboard>
<DoubleAnimation Duration="0:0:0.3" From="1" To="0"
Storyboard.TargetName="ClosingRectangle"
Storyboard.TargetProperty="Opacity">
</DoubleAnimation>
</Storyboard>
</vsm:VisualState>
The board is a User control that uses the square's SquareClicked event to check for won/lost conditions. You win if you open all the squares that don't contain mines. If you open a mine, you lose miserably. Here's the logic:
private void Square_SquareClicked(object sender, EventArgs e)
{
if (isPlaying)
{
openedSquares++;
if (openedSquares >= BOARD_SIZE * BOARD_SIZE - NUMBER_OF_MINES)
{
isPlaying = false;
OnWonGame();
}

BoardSquare clickedSquare = sender as BoardSquare;
if (clickedSquare != null && clickedSquare.Value == "M")
{
isPlaying = false;
OnLostGame();
}
}
}
Basically, it keeps track of the number of squares opened so far. If that number reaches the total number of squares minus the number of mines, you've got yourself a winner. If the value of the opened square is 'M' for 'mine' - kaboom!!!!

You can tweak some settings by changing the values of the constants in the Page class:
private const int BOARD_SIZE = 7;
private const int NUMBER_OF_MINES = 8;
What these do is self-explanatory.

You can download the source code from here.

Regards,
Boyan