Pixel perfect positioning of list elements in WPF

21. January 2010

This is something I had to look up several times myself, so I thought I should write it down for later reference.

I was building a simple level editor for SilverTile (more about that in another post later) and wanted to place the map tiles in a grid-like fashion. This could be done using my dynamic Grid control, but I wanted pixel perfect control of where the tiles were placed on screen. Note the gaps between the grid rows in the following screen shot.

Fail!

Fail! Note the gaps between the tiles!

To do this I would need to use a Canvas control and place each tile using the Canvas.Left and Canvas.Top properties to set the position.

Win! This is what we want. Pixel perfect placement of our images!

The challenge is that the Canvas control doesn’t support list binding directly, so you must use some other control to accomplish this. Luckily there is a solution available by using the ItemsControl class. The ItemsControl is a list control that lets you specify which control should be the root element. In our case we will use a Canvas control as the root and then use data binding to specify the values for the Canvas.Left and Canvas.Top properties.

Using the ItemsControl

To exemplify the usage of the ItemsControl I first created a simple view model for the application. This was simply a list of TileData objects where each describes one tile. Each TileData object has an image source and Left and Top properties. The Left and Top properties tell where the tile should be placed on screen. In a real application your view model would probably be more complex and possibly calculate the positions based on some other data.

// The TileData class describes a tile
public class TileData
{
    public Uri Image { get; set; }
    public double Left { get; set; }
    public double Top { get; set; }
}

Now, with the view model in place we can setup our application.

<Grid Name="Root" Loaded="Root_Loaded">
    <Grid.Resources>
        <Style x:Key="ContainerStyle">
            <Setter Property="Canvas.Left" Value="{Binding Left}" />
            <Setter Property="Canvas.Top" Value="{Binding Top}" />
        </Style>
    </Grid.Resources>
    <ItemsControl Name="map" ItemsSource="{Binding}" ItemContainerStyle="{StaticResource ContainerStyle}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Width="{Binding Path=Root.ActualWidth}" Height="{Binding Path=Root.ActualHeight}" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Image Source="{Binding Image}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

Here we have a Grid as the root element of the application. I’ve used a grid since it will be sized dynamically when the window is resized, something the Canvas control doesn’t. We then have the ItemsControl that has its ItemsSource bound to our data context. The ItemsSource is the list of TileData objects that is used to describe the map.

And now we get to the interesting part: The ItemsControl.ItemsPanel property. This property defines which control should be the container into which all our list items are placed. By setting this to a Canvas control we end up with a layout where you can set your child controls position as you want.

Further we have the ItemsControl.ItemsTemplate that tells how you want each object in your ItemsSource to be rendered. In our case we render it as an Image control with its source bound to the Image property of your TileData object.

The final missing part is how we place our controls. The obvious way to do this would be to set the Canvas.Left and Canvas.Top properties of our Image control by binding them to the Left and Top properties of our TileData object. One would expect this to work but if you try it you will see that all our controls are placed at the top left corner of the canvas, with Canvas.Left = 0 and Canvas.Top = 0. The solution is to create a style that sets the Canvas.Left and Canvas.Top properties and to assign that to the ItemContainerStyle property of the ItemsContainer. By doing this you will see that our Image controls are placed correctly where we want them.

Using Snoop to find out what really happened here

To understand what really happened here we need to examine the control hierarchy our Xaml code generates. A good tool to do this is Snoop. It lets you attach to a running Wpf application to examine all properties of all generated controls.

Using Snoop to look at our applications control hierarchy

Look at the above screen shot. Here you can see the control hierarchy of the GridWin application. If you look down the tree you will find an ItemsControl control with a child Border control. The Border contains an ItemsPresenter Control that contains a Canvas. This Canvas control is the one we assigned to our ItemsControl.ItemsPanel property.

The Canvas contains a bunch of ContentPresenter controls that each contains one Image control. And this is the reason why we cannot set the Canvas.Left and Canvas.Top properties of our Image controls directly. Since the images are contained in the ContentPresenter controls we need to set the properties here instead. And this is what we do when we set the ItemContainerStyle property. The style is applied to the ContentPresenter which is placed at the correct position.

Using the code

I am using this approach in a level editor application for SilverTile that I will be writing about soon. The application stores the map as a list of Tile objects where each Tile knows which row and column they should be placed in. The Canvas.Left and Top properties are then bound to the X and Y properties that are caluclated by multiplying the row or column number with the tiles width or height in pixels. The tile list is used as the ItemsSource for an ItemsControl that renders the tiles at the wanted position.

The ItemsControl is available in Silverlight as well as in WPF, so this approach works just as well there. The only challenge is that the binding of the Canvas' size to the size of the Root grid cannot be done in Silverlight 3 since it doesn't support element to element binding. This is fixed in Silverlight 4 though, so there you should be able to use the exact same approach.

kick it on DotNetKicks.com

.NET, Silverlight, WPF , ,

SilverTile: Another progress report

17. December 2009

It's time I posted another progress report.

Since my last progress report I have implemented most of the features from my feature list. I'm not entirely happy about the Xaml support for level design, and I am still missing the support for per-pixel collision detection, but the game engine works well enough that I have implemented a VERY simple game using it. 

The game, available here, lets you control your character on a field throwing swords at some monsters. You get points for how many monsters you kill and if you are touched by a monster you die. 

Hunting monsters

Hunting monsters

As simple as it is the game demonstrates the features needed for a proper game:

  • We have collision detection - both between moving sprites (character, monster, sword) and between sprites and background (you cannot walk across mountains). 
  • We have animation support and an animated sprite can have many animations that we can choose.
  • The game area and all game assets are defined in Xaml. 
  • Graphics are reused between sprites. This means that two identical monsters share the same bitmaps in memory.

The engine is still missing some features. The most obvious one is the pixel perfect collision detection. This is a simple feature to add, but I fear that it will be a real performance killer so I postpone it until I really need it. Apart from that I feel that the framework surrounding game setup needs some work.

The current implementation lets you define one or many GameAreaGrid objects. The GameAreaGrid lets you place one rectangular sprite in each cell. You then tell the Viewport to load the grid and it will be setup as the background area of your game. To change maps you tell the viewport to load another GameAreaGrid object.

While this works well enough I would like it to be even simpler to use.

The idea is to add support for area transitions to cells in the GameAreaGrid so that when the player enters one of these we automatically loads the new grid and places the player at the new location. This should allow us to setup an entire game world using only Xaml. I'm not entirely sure what would be the best way to define an area transition but I think it would be nice to add an AreaTransitions collection property to the GameAreaGrid where each object in the collection described a transition that would be performed when the player enters a given cell. A transition would be from a cell (grid row and column) to a new cell in another GameAreaGrid. The reference to the GameAreaGrid would be a regular object reference that could be modeled as a binding to a StaticResource in Xaml. This still gives us the option of designing the GameAreaGrid in Xaml or in code if we prefer. 

I would also like to allow random placement of enemies in a GameAreaGrid. Either completely random or by identifying cells where mosnters can spawn. The types of monsters, the number of monsters and how often they spawn would also have to be specified.

So that will be my plan for the week until christmas. Implementing more support for game mechanics, paving the way for a complete game engine :-)

kick it on DotNetKicks.com

.NET, Silverlight , ,

SilverTile: Old-school gaming on a modern platform - progress report

8. December 2009

It's time for a progress report.

The last week I have been adding basic features to SilverTile. The first feature was to add basic rendering support. My first attempt used Array-copy functions to copy pixel data from the sprite to the viewport. This worked well, but it did not support alpha blending (transparency) of pixel data. To improve this I added some code from the Silverlight Games 101 blog that allowed rendering of bitmap data from one WriteableBitmap to another. I modified the code somewhat to support rendering of data from any IRenderable and then I had the rendering support I needed.

The intial architecture of SilverTile defined each sprite object as having its own pixel data. This is fine as long as you have only a few sprites or if each sprite have an unique appearance, but in most cases you will have many sprites using the same image. One example is the walls of a game area. I model each wall segment as an unique sprite, but each is built up of the same image. So instead of having each sprite have its own pixel data I refactored out the pixel data into a Frame object that could be reused between sprites. This also lay the ground for animation support later.

Zelda walking

Link walking!

To set up a game area I want to support two modes. One mode should be building game areas in code by using the AddBackgroundSprite() method of the Viewport class. This lets you add one sprite at a time at the desired location. While building the game area in code works well, I wanted to support using Xaml to describe the game area and the graphical resources used by a game. Since Silverlight only allows classes that inherit from UIElement to be named (given the x:Name and x:key attributes) in Xaml I had a choice of either letting the Sprite classes derive from UIElement or using a separate set of classes to describe the game area. I cholse the latter option and built a set of classes that can be instansiated in Xaml and that describes a game area, a game tile and a frame. I then added a SetGameArea helper method to the viewport that reads the GameArea data and performs the setup.

Finally I added support for animated sprites. An animation is a list of IFrame objects in combination with a frame rate. Each time the Update method of the animated sprite is called, we check if the elapsed time is greater than the time a frame should last and if it is we switch frames to the next frame. When we reach the last frame in the animation we go back to the first frame again. Although I will need for sprites to support multiple animations (like walk left and walk right), this is a good starting point.

On top of all this I have written tests for everything. This really helped me when refactoring the code to use IFrame and the bitmap blitting.

If you have the Silverlight 4 beta installed you can watch a live demo here: http://rag.no/st/silvertile.html. (Try clicking on the game area!) Or you can download the source code here: http://silvertile.codeplex.com/

 

kick it on DotNetKicks.com

.NET, Silverlight , ,

SilverTile: Old-school gaming on a modern platform (part 2)

3. December 2009

I will try to keep SilverTile simple with just the features needed to get my game running.

At the very least SilverTile will support the following:

  • Rendering to a surface (WriteableBitmap)
    • I think this is the fastest way to render pixel graphics in Silverlight (done)
  • Support both tiles for background / terrain, and moveable sprites
    • Sprites should support animation (done)
    • Sprites should support transparent pixels (done)
  • XAML for game level setup
    • Support using XAML to setup the game levels/maps (done)
    • SUpport using XAML to define sprites and animated sprites (done)
  • Collision detection
    • Tiles should support bounding-box collision detection (done)
    • Sprites should support bounding-box collision detection (done) and possibly per-pixel collision detection (not yet)
  • Input control
    • Keyboard input should be handled in a structured way
  • Game infrastructure support
    • Support for transitions between levels/maps defined in XAML (done)

In addition I think SilverTile needs a way to handle the game and a game session as an entity, but that can wait until later. This is implemented in the SilverTileGameWorld class.

Any comments? Did I forget anything essential? I will update this page with any new features and with some progress information as soon as I have anything to report.

.NET, Silverlight , ,

SilverTile: Old-school gaming on a modern platform (part 1 of many)

30. November 2009

This is the start of my developer diary for SilverTile. The diary is mainly for my own use both as a reference and as a way to document my progress. Hopefully I will end up with a useable solution one day.

Silvertile? What is it?

The last few months I've been experimenting with Silverlight programming. I've written all kinds of database-driven applications and have experimented with various different programming models. While this has been rewarding and I've learned much, it hasn't excactly been coding for fun.

For a while I participated in the development of Smeedee, a project monitor for agile projects, and that was fun - but lately I've been playing with my own project again. As all good nerds know, writing a game is the most entertaining way you can learn a new programming language or platform. So that is what I've been doing. Being a fan of old-school games I decided to write a remake of a real classic – the original Zelda for the NES-platform. The game itself is simple, but it is fun to play and writing a remake should be a fun challenge.

Zelda

Good old Zelda - coming to Silverlight?


Writing games is a fun excercise itself, but it gets even more fun if you end up with something that can be reused later. That is the reason I am writing about SilverTile and not SilverlightZelda - I am writing a reuseable library for old-school games. :-) The library itself will be quite simple, but I plan to include XAML support for graphics and level design.

Can I use it? Does it work?

I have created a project for SilverTile on Codeplex, but the source code there is more or less unusable. I have been using it as a test bench for the architecture and design of the library and I don't think anyone will be able to use it. As soon as I have some usable code I will upload it to the project.

So then. I'll get back to the coding. Hopefully I will have more to show soon. :-)

kick it on DotNetKicks.com

Silverlight , ,

A simpler (and dynamic) Grid control for WPF

6. November 2009

The last days I have been playing with WPF trying to get an understanding of how it works ”under the hood”. So I have written a bunch of tiny applications where I prototype a function. When building these applications I don’t care much about its user interface, but I still like to have my controls lined up neatly. To do this I usually use a grid control with some rows and columns. This usually works well, but the grids syntax gets tiresome to write and rewrite all the time.

Yesterday this annoyed me so much that I decided to fix it! The reason was not only the syntax, but also that I needed a grid that let me set the number of rows and columns dynamically using data binding. The result is the DynamicGrid control. It allows you to replace this code:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
</Grid>

With this code:

<grid:DynamicGrid NumColumns="8" NumRows="8">       
</grid:DynamicGrid>

Nice! And it also allows you to use data binding to setup the number of rows or columns. Like this:

<grid:DynamicGrid NumColumns="{Binding ColumnCount}" NumRows="{Binding RowCount}">       
</grid:DynamicGrid>

So your grid can adapt to your data source. On top of all that, it even plays nice with the old grid-markup. So if you need a header row with a fixed size then you can insert it using a RowDefinition and let the DynamicGrid add the rest of the rows and columns for you automatically.

How does it work?

It turned out that implementing the grid was really easy. All I needed to do was to subclass the Grid class, add two new dependency properties and add the code that added the columns and rows automatically.

I created two new dependency properties named NumColumns and NumRows. They are both identical except for the naming:

public static readonly DependencyProperty NumColumnsProperty =
    DependencyProperty.Register("NumColumns", typeof(Int32), typeof(DynamicGrid));

public Int32 NumColumns
{
    get { return (Int32)GetValue(NumColumnsProperty); }
    set { SetValue(NumColumnsProperty, value); }
}

There is not much to note about them – we default to one column and one row.

I then wrote an override for the OnInitialized method:

protected override void OnInitialized(EventArgs e)
{
    base.OnInitialized(e);

    RecreateGridCells();
}

This will call the RecreateGridCells method that does the actual setup of the dynamic grid. Since it is called after the base grid is initialized we support its functionality.

The RecreateGridCells method does the custom setup:

private void RecreateGridCells()
{
    int numRows = NumRows;
    int currentNumRows = RowDefinitions.Count;

    while (numRows > currentNumRows)
    {
        RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
        currentNumRows++;
    }

    while (numRows < currentNumRows)
    {
        currentNumRows--;
        RowDefinitions.RemoveAt(currentNumRows);
    }

    int numCols = NumColumns;
    int currentNumCols = ColumnDefinitions.Count;

    while (numCols > currentNumCols)
    {
        ColumnDefinitions.Add(new ColumnDefinition{ Width = new GridLength(1, GridUnitType.Star) });
        currentNumCols++;
    }

    while (numCols < currentNumCols)
    {
        currentNumCols--;
        ColumnDefinitions.RemoveAt(currentNumCols);
    }

}

Here we read out the number of rows we want and the number of rows we have. If we need more rows we add them to the RowDefinitions collection and set their heights to *. The * means that they should scale automatically. If we have too many rows we remove them starting with the last one.

After setting up the rows we setup the columns the same way.

That is all there is to it!

So this code:

<Window x:Class="DynamicGridDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:grid="clr-namespace:DynamicGridDemo"
        Title="MainWindow" Height="350" Width="525">
    <grid:DynamicGrid NumColumns="2" NumRows="2">
        <Button Grid.Column="0" Grid.Row="0" Content="At 0,0" />
        <Button Grid.Column="0" Grid.Row="1" Content="At 0,1" />
        <Button Grid.Column="1" Grid.Row="0" Content="At 1,0" />
        <Button Grid.Column="1" Grid.Row="1" Content="At 1,1" />
    </grid:DynamicGrid>
</Window>

Gives you this result:

Let’s add a header row:

<Window x:Class="DynamicGridDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:grid="clr-namespace:DynamicGridDemo"
        Title="MainWindow" Height="350" Width="525">
    <grid:DynamicGrid NumColumns="2" NumRows="3">
        <Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Content="Header label here at 0,0 and 1,0" FontSize="20" Background="Yellow" />
        <Button Grid.Column="0" Grid.Row="1" Content="At 0,1" />
        <Button Grid.Column="0" Grid.Row="2" Content="At 0,2" />
        <Button Grid.Column="1" Grid.Row="1" Content="At 1,1" />
        <Button Grid.Column="1" Grid.Row="2" Content="At 1,2" />
    </grid:DynamicGrid>
</Window>

Gives this result:

And it even plays nice together with the old syntax. This is useful if you need a header row with a fixed size for example:

<Window x:Class="DynamicGridDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:grid="clr-namespace:DynamicGridDemo"
        Title="MainWindow" Height="350" Width="525">
    <grid:DynamicGrid NumColumns="2" NumRows="3">
        <Grid.RowDefinitions>
            <RowDefinition Height="40" />
        </Grid.RowDefinitions>
        <Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3" Content="Header label here at 0,0 and 1,0" FontSize="20" Background="Yellow" />
        <Button Grid.Column="0" Grid.Row="1" Content="At 0,1" />
        <Button Grid.Column="0" Grid.Row="2" Content="At 0,2" />
        <Button Grid.Column="1" Grid.Row="1" Content="At 1,1" />
        <Button Grid.Column="1" Grid.Row="2" Content="At 1,2" />
    </grid:DynamicGrid>
</Window>

This gives the following output (note the size of the first row):

I haven't done much testing of the code, so it may include some nasty bugs, but I think it may be useful. Either if you are prototyping an application or if you need a grid that sizes to your content.

Download the source code here: DynamicGridDemo.zip (77.44 kb) (Visual Studio 2010 b2, WPF4 required)

kick it on DotNetKicks.com

.NET, WPF ,

Playing with the Amazon Relational Database Service

4. November 2009

In this post I will look at the new Relational Database Service (RDS) from Amazon Web Services (AWS).

This was supposed to be a short post, but ended up being huge! So good luck to anyone who wants to read it...

AWS offers a bunch of services ranging from simple data storage to full virtual servers. The common factor for all of them is that they are controlled using standard web services. This means that you can easily manage them programmatically if you want to. In this article I won’t focus on the management bit, but rather on how and why to use the service.

In all simplicity RDS is MySQL running on a virtual server somewhere in Amazons server farm. The service is a port of MySQL so if you can connect to a regular MySQL database you can connect to RDS as well. You also manage RDS the same way you would manage a regular MySQL server, you can connect to it using the standard tools and create databases and tables as you want.

In my opinion there are two scenarios where you would use RDS: Either you have an application using MySQL already running on a virtual server on Amazon EC2 or you have an application that needs to reach a MySQL database from anywhere on the internet. In the first case you can now host the database on a dedicated system instead of a custom virtual server. This allows you to easily scale the performance of your application by scaling up your database. In the second case you have a desktop application that needs to connect to a database while being connected to the internet. In that case you could host the database on your own server, but hosting it at AWS is guaranteed to offer better availability and much better bandwidth.

There are at least four obvious advantages to using RDS as compared to running your own server with MySQL:

  • High availability – AWS guarantees an uptime of at least 99.95%. Since it is hosted in Amazons server farm it will probably be much more available than most services.
  • Easy to upgrade – Using the management web services you can easily scale your RDS server using a single api call. This is much easier than even upgrading a virtual server.
  • Automatic backups – RDS will automatically backup your database and in addition you can set up your own backups if you need to.
  • Available anywhere – It is easy to configure the RDS firewall so you can make the database available in any way you need to.

But there are also some disadvantages to RDS:

  • You trust AWS with your data – Since AWS are hosting your database you also trust them with your data. In some scenarios this may be a problem.
  • You pay per hour – When using RDS you have to pay per hour your database is running. While the prices are quite reasonable they still accumulate over time. It will be cheaper to run your database on an existing server if you have one.
  • Limited bandwidth – Depending on your use this may not be a problem, but running your database on a remote server means that you connection will be limited to the capacity of your internet line.

Getting started with RDS

The first thing you need to get started with RDS is an account with AWS. It is free to sign up for AWS, but you must pay to use their services. Signing up is simple, especially if you have shopped at Amazon.com before. Sign up here: https://aws-portal.amazon.com/gp/aws/developer/registration/index.html

After you have signed up for AWS you need to create a digital certificate that identifies you. This is done in the Your Account -> Security Credentials page. To access AWS you need two keys – an Access Key ID and a Secret Access Key.

With your keys in place you are ready to connect to AWS and the RDS service. I’ll show you an example .NET application that manages your database instances later, but first we will use the management tools supplied by AWS. These tools are a bunch of Java command line applications, so you need the Java runtime installed to use them. The tools can be downloaded here: http://developer.amazonwebservices.com/connect/entry.jspa?externalID=2928&categoryID=294

Setting up the command line tools is relatively easy – just unzip the file and follow the instructions in README.txt. You should setup a text file containing your Access Key ID and Secret Access Key based on the template found in the zip file.

Now we are ready to create a server! First you should make sure everything works properly. Try to run the rds-describe-db-instances command. If the tools are properly set up it should return an empty list. The next command you should try is rds-create-db-instance. This is the command that creates your server. I used the following command:

rds-create-db-instance --db-instance-identifier MyTestServer123 --allocated-storage 5 
--db-instance-class db.m1.small --engine MySQL5.1 --master-username root --master-user-password Secret123

And I got the following response:

DBINSTANCE  mytestserver123  db.m1.small  mysql5.1  5  root  creating  1
      SECGROUP  default  active
      PARAMGRP  default.mysql5.1  in-sync

This gave me a small instance of a database server with 5 Gb of disk storage. The instance is named MyTestServer123 and is running MySQL 5.1.

Now if I run the rds-describe-db-instances command again I get the following result:

DBINSTANCE  mytestserver123  db.m1.small  mysql5.1  5  root  creating  1
      SECGROUP  default  active
      PARAMGRP  default.mysql5.1  in-sync

Note that it says creating. It can take a few minutes to setup a new server and you cannot access it before it is ready. Try running the rds-describe-db-instances command after a minute until you get something like this:

DBINSTANCE  mytestserver123  2009-11-04T11:50:21.554Z  db.m1.small  mysql5.1  5  root  
available  mytestserver123.cqpn2yka5vjx.us-east-1.rds.amazonaws.com  3306  us-east-1b  1       SECGROUP  default  active       PARAMGRP  default.mysql5.1  in-sync

Now the status should be available. You should also note the text mytestserver123.cqpn2yka5vjx.us-east-1.rds.amazonaws.com. This is the name of your server and you need it when you want to connect later.
Before you can connect to your server you need to open its firewall to let you through. This is done using the command rds-authorize-db-security-group-ingress. You must run it two times. First you must set the security group for your server and then you must allow your ip-address through the firewall to servers in that security group. Use the following commands:

rds-authorize-db-security-group-ingress MyTestServer123 --ec2-security-group-name default

This will place your server in the “default” security group. The default group always exists so it is ok to use here. Then you use the following command to give your ip address access to the server:

rds-authorize-db-security-group-ingress default --cidr-ip 123.124.125.126/24

Here my public ip address is 123.124.125.126. The /24 after the ip address means that all addresses starting with 123.124.125 should be allowed to connect. Read more about the cidr format here: http://en.wikipedia.org/wiki/CIDR.

Now, finally, your server is ready to be used! Try connecting using your favorite tool. I prefer MySQL Query Browser which is part of the MySQL GUI Tools. Download it here: http://dev.mysql.com/downloads/gui-tools/5.0.html.

Trying to connect

To connect you must specify the server name you noted earlier. Run rds-describe-db-instances if you forgot it. The user name and password are the ones you specified when you created the server.

Connected!

 

Great! Now we have a database server that we can do anything with! Try creating a database and some users and some tables.

After you are done playing with your server you will probably want to remove it. If you don’t you will be billed per hour until you do, so don’t forget this! Use the following command to delete it:

rds-delete-db-instance mytestserver123 --skip-final-snapshot

The --skip-final-snapshot flag tells the program that you don’t need a backup of the server. This is ok as long as you are just experimenting. When deleting a server you get one final chance to stop the process. Answer Y at the following prompt to start the deletion:

    Once you begin deleting this database, it will no longer be able to accept connections.
    Are you sure you want to delete this database? [Ny]y
DBINSTANCE  mytestserver123  2009-11-04T11:50:21.554Z  db.m1.small mysql5.1  5
 root  deleting  us-east-1b  1
      SECGROUP  default  active
      PARAMGRP  default.mysql5.1  in-sync

Now you server will be deleted after a few minutes.

Using the web services from a .Net application

Well, all this has been nice and useful, but not very fun. So I decided to write an application that manages these servers for us. Since I’m a .Net developer that is the tool I will be using.

MySQL has a nice set of ADO.Net compatible classes for download here: http://dev.mysql.com/downloads/connector/net/6.1.html.
And AWS has a nice set of .Net classes that wrap the RDS web service for download here: http://developer.amazonwebservices.com/connect/entry.jspa?externalID=2946&categoryID=293.

I found a bug in the AmazonRDSClient class where the SkipFinalSnapshot argument was incorrectly encoded. This is easy to fix by changing line 1458 in AmazonRDSClient.cs:

// From
parameters.Add("SkipFinalSnapshot", request.SkipFinalSnapshot + "");
// To
parameters.Add("SkipFinalSnapshot", request.SkipFinalSnapshot.ToString().ToLower() + "");

Using these classes I wrote a simple WPF application that connects to RDS and downloads a list of server instances. It also lets you create new instances, delete instances and test that you can connect to an instance.


Download the source code here. The application is a WPF 4 application that needs Visual Studio 2010 to compile.

RDSApp.zip (781.82 kb)

 

kick it on DotNetKicks.com

.NET, Databases , , , ,

Accessing the local file system in Silverlight 3

2. November 2009

One of the problems with Silverlight applications as opposed to regular desktop applications is that their access to the local file system is extremely limited. In Silverlight versions 1 and 2 you could only access if via the Isolated Storage system, and that only allowed you to store up to 1 Mb of data per default. If you wanted to store more than that you had to ask the user to increase your quota.

The reason for this is of course security. If Silverlight applications were allowed access to the file system per default you could create a transparent application that searched all the files on the users computer and did whatever you wanted with it.

This limitation meant that you had to do some serious hacking if you wanted to let the user create content in a Silverlight application that he could store locally. One way is to post the data to an asp-page that will return the file for the browser to save, but that is both clumsy and inefficient.

In Silverlight 3 the situation has changed somewhat. You still cannot access the local file system directly, but you can use the OpenFileDialog to let your user browse to a file that you can then read. You also have the SaveFileDialog that lets your user select a file that you can write to. You still don’t have full access to the file system, but at least you have a way to load and save files.

The OpenFileDialog class should be well known if you have done windows programming in WinForms or WPF. It allows you to specify the file extension of the file you want to open before displaying the dialog. If the user selects a file you get a reference to the file as a FileInfo object that you can read using the OpenRead or OpenText methods.

The SaveFileDialog is similar to the OpenFileDialog in that it allows you to specify a file extension before displaying the dialog. If the user selects a file name you will get a Stream object that you can write to using the OpenFile method.

But, enough chat. Lets look at some source code! This first example opens a text file for reading:

private string OpenFileAndReturnContentAsString()
{
   OpenFileDialog openDialog = new OpenFileDialog();
   openDialog.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*";

   bool? result = openDialog.ShowDialog();

   if (result.Value)
   {
      using (StreamReader fileReader = openDialog.File.OpenText())
      {
         return fileReader.ReadToEnd();
      }
   }

   return string.Empty;
}

There are a few things to note here:

  • The format of the file extension filter should be well known to most, but it is rather clumsy to edit.
  • The ShowDialog will display the dialog as a modal window. It returns a nullable boolean that will always contain either True or False. If the user selected a file the value is True and if he cancelled the dialog or closed the window the value will be False.
  • The File-property of the OpenFileDialog object is a FileInfo that refers to the file. We can access some of its properties, but most are unavailable due to security restrictions. The only really useful property you have access to is Name. The Directory, DirectoryName and FullName properties are unavalable.
  • The FileInfo class has two methods that you can use to access the file. The OpenText method returns a StreamReader object that you can use to read the file as text. Alternatively you can use the OpenRead method to get a FileStream that you can read.

To write files you must use the SaveFileDialog:

private void SaveTextFile(string content)
{
   SaveFileDialog saveDialog = new SaveFileDialog();
   saveDialog.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*";<

   bool? result = saveDialog.ShowDialog();

   if (result.Value)
   {
      using (Stream saveStream = saveDialog.OpenFile())
      using (StreamWriter saveWriter = new StreamWriter(saveStream))
      {
         saveWriter.Write(content);
      }
   }
}

The code here is somewhat simpler than for opening files, the main reason being that you only have one way to access the file you want to write to. There are a few points to make here as well:

  • The filter is the same as the one used in the OpenFileDialog example.
  • The ShowDialog method also works the same way as for the OpenFileDialog.
  • The only way to access the file is to use the OpenFile method. This returns a Stream that we can write to.
  • When writing a text file it is easier to wrap the Stream in a StreamWriter and use that instead.
  • If you need to know the name of the file you are writing to you can use the SafeFileName property of the SaveFileDialog. This gives you the file name only, not the directory name.

I have attached a sample project. This is a simple text editor where you can load and save files locally. The solution is a Visual Studio 2010 b2 file, but the source code (xaml- and cs-files) should compile just as well in Visual Studio 2008.

Feel free to comment if you have anything to say! :-)

SLFileSystem.zip (58.00 kb)

kick it on DotNetKicks.com

Silverlight, .NET ,