Category Archives: .NET

Developing for Windows Mobile – Guru Meditation

I’ve been working away for a few nights now trying to put together a simple framework for building user interfaces on a Windows Mobile device. It’s only taken a few nights to build something that I’m pretty happy with… and I was thinking of maybe even posting some source code.


It was at this moment of course that I had a visit from my Inner Guru. You know the one… that little voice in your head that sniggers impolitely whenever you struggle to convert a loop into a LINQ expression. Or when you’re hacking out some prototype code and you need to new up an instance. You know that really its going to need an IOC container, you look around, no-ones watching… in goes the explicit “new Foo()”. Immediately your Inner Guru can be heard muttering to themselves, “tut… tut.. will he never learn…”.


Anyhow, my Inner Guru popped in for a visit just the other day and we had a quick chat about the work I’d been doing on my mobile framework. The conversation went something like this:



Me: Hey – check out this framework I’ve been building for Windows Mobile – pretty cool huh?


Guru: Hmm… yes it appears you’ve made quite some progress.


Me: Yeah – look it can do animations.


Guru: Very impressive. Did you have trouble using the DirectX libraries?


Me: Ah well, err no it’s just using GDI.


Guru: Ah, I see. Does that give you full hardware acceleration on the device?


Me: Um… no I don’t think so.


Guru: Ah, I see. Commendable that you have support for an opacity on each element.


Me: Yeah, well I mean no. It seemed like a good idea at the time but I haven’t done that yet.


Guru: Ah, I see. It appears all objects support using a RotateTransform?


Me: Yeah, well I mean no. I couldn’t figure out how to rotate images an arbitrary amount with decent performance.


Guru: Ah, I see. I notice that your transforms all inherit from a base class which of course must perform the Matrix calculations.


Me: Yeah, well actually no. I mean there is a base class but I haven’t bothered implementing the transforms using Matrix math – they’re just, you-know, hard coded.


Guru: Ah, I see. It seems you’ve done some work building the framework for a layout engine that can be plugged into any container control. Seems a bit WinForms’ish to me, not very WPF like.


Me: Well I didn’t think it was so bad, although I haven’t actually written that bit yet.


Guru: Ah, I see. So no actual layout panels yet, not even the most simple stack panel?


Me: Err, well no – but it wouldn’t be hard to add.


Guru: But you haven’t done it – even though it wouldn’t be hard.


Me: Well no.


Guru: Hmm.


Me: I was thinking of posting the source code.


Guru: I see. So despite the obvious architectural flaws, the missing classes, the lacklustre performance, the questionable code formatting you feel it adequate for public viewing, or perhaps that may be ridicule? I see you’re still using foreach loops – can’t quite seem to wrap your head around LINQ can you dear boy?



Me: Umm…


Fortunately it was at this point that my Inner Guru hit an untrapped exception deep in his runtime. The following image began blinking away in my head.


I suppressed an evil chuckle and posted the code: http://mobileui.codeplex.com

Tech-Ed Australia 2009 – Day Two

First – here’s a few blog posts which cover some of the sessions I went to yesterday – but in much more detail. I’d recommend both blogs if you’re not already subscribed.

Windows Mobile Marketplace – http://www.techau.tv/blog/?p=2106

Starting a Small Software Enterprise – http://richardsbraindump.blogspot.com/2009/09/how-to-build-small-software-enterprise.html

Everyone that attended yesterday’s session on the Windows Mobile Marketplace was also sent an e-mail this afternoon to let us know the information we were given regarding the regional pricing policy was incorrect. The price is actually an additional $10 per region, not $99 which I think it quite acceptable. See Jame’s blog post for details.

DEV310 Make Some Magic! Shake, Flip and Flick Your Application for Windows Mobile 6.5!

This talk began with a brief introduction of marketplace and the Race to Market Challenge. This was then followed by a good discussion around new and emerging phone capabilities which included an interesting video of some folk who have developed a multi-touch resistive screen technology. This means you get multi-touch, pressure sensitivity and fine grain accuracy.

Unfortunately for me a large part of the talk was based around how you can use the great open source sensor API to access hardware specific phone features such as accelerometers and light sensors.Would have been interesting for those that hadn’t seen it before – but otherwise just a run through of the provided demos apps.

There was also a quick demonstration of how easy it is to write your own gesture recognition engine for pre 6.5 phones. Simple but very effective.

DEV350 What is new in VS2010 & .NET FX 4.0… and what should you be using in your next project?

The session speaker was Adam Cogan. I tried to listen to him… I really did. But he’s just so annoying!

He spends all his time going off on irrelevant tangents or trying to amuse the audience. Then creeps through the content at a snails pace [hmm… can snails creep?]. His endless audience questions quickly become tiresome too. What makes it even more annoying is that he’s always getting/picking great topics for Tech-Ed sessions. Its just that the delivery is so poor. But then its probably just me. I I always give him a 1 on the review and if everybody else did the same he wouldn’t get the gigs right? Guess I’ll just notch it down to a personality clash – just hoping next year that he decides to do a talk on something less interesting.

I didn’t manage to sit through this talk to the end. A good coffee was much more enjoyable.

DEV320 Visual Studio 2008 IDE Tips

I thought this session would be entertaining though I consider myself fairly familiar with Visual Studio’s IDE (I should be after 7 years) and wasn’t expecting too many surprises. Having said that I came away with at least 5 tips that I certainly intend to apply to my everyday workflow. We didn’t even have to take notes because Sara had posted them just prior to her talk. My favourites were 5, 15 (esp. when used to execute from find combo) and 22. Another great session by Sara.

SQL209 Project Gemini: Self-Service Business Intelligence

This was all new for me. Essentially it seems to be providing business analysis functionality using Excel as the design tool – very much end-user oriented. Support for Excel Services (via SharePoint), using Analysis Services transparently with scheduled updating of data sources. The demo was very well delivered I was impressed in how the convergence of Excel, SharePoint, Silverlight, Reporting Services and Analysis Services worked seamlessly to produce the output.

To top it off the presenter showed how the project Gemini Excel add-in could sort and filter 101 million rows in real time (sub-second) even when running on a HP Mini netbook. All via an in-memory data engine and clever use of compression.

Its being delivered as part of SQL 2008 R2 together with Office 2010.

Tech-Ed Australia 2009

IMAG0042 I’m at Tech-Ed again this year (that’s three in a row!). Unfortunately this year I had to pay for the privilege since neither the company I’m currently working for nor Microsoft came to the party. Being an independent contractor I hardly expected my client to foot the bill – but I did try and get a ticket off of Microsoft – after all they footed the bill last year.

Day One of the main event has just finished and I was generally very impressed with the sessions I attended. I don’t really expect to learn a great deal at Tech-Ed. I figure its geared mainly towards corporate developers/IT pros who don’t necessarily have the passion/inclination to keep right up with emerging technologies and processes outside of company time. So if I don’t come to Tech-Ed to learn about the future of WPF, MVVM trends, ORMS and MEF then what am I doing here?

Well – to answer that he’s a quick recount of the sessions I attended today.

Keynote

Pretty much on target this year. Some opening spiel about how now is a good time to be innovating which was further enforced by a HP representative. Then into some demos – Office 2010, a glimpse at VS 2010 CodePlex and Blend 3 and some Windows 7.

SOA303 A Lap around Microsoft Code Name "Oslo"

This Oslo thing has got to go somewhere… eventually… right? The presenter certainly did the best job I’ve heard yet of describing Oslo with demos of M, Quadrant and Intellipad. The talk was done well, the demos flawless but i still came away wondering whether this is really going to mature into a product that will be accepted in the real world.

DEV230 A Tour of CodePlex

I was one of the many that joined the petition to get Sara Ford to come down to Oz. I’m a relatively new subscriber to Sara’s blog – having caught the end of her VS 2008 tips and then her musings and tips for her new role as Codeplex PM.

She seemed a little nervous in her part of the Keynote (looking up at 2500+ strangers) but in this session she was on fire. Its always a little awkward watching how the US speakers react to the subdued Australian audiences – but Sara didn’t miss a beat – she just steam-rolled ahead with a level of enthusiasm that was truly contagious.

SaraFord.FanClub.Membership++;

In fact – so inspired I’m going to post my latest project (Windows Mobile stuff) on Codeplex.

ARC203 How to build a small software enterprise from zero

I picked this session at the very last minute and as it turns out that was a choice very well made.

The speaker was a Perth based book author ( {yawn} – so who isn’t) by the name of Joseph Albahari. But then I discover he also happens to be the author of Linqpad (automatically elevating him to Legend status)! Just last week I was considering upgrading his most excellent utility to the premium version that includes intellisense auto-completion.

This talk was full of practical advice on how to make your own business out of developing software, with plenty of good examples from Joseph’s own journey with Linqpad. The slides, delivery and content in this talk were all first class.

WEB303 Free up the UX Bottleneck

This session was an overview of Sketchflow (within Expression Blend 3) by Shane Morris. Of all the sessions I attended today this one was the least rewarding. That was through no fault of Shane’s who covered the topic well – simply that I was already to familiar with the content. Particularly considering I’d seen Matt Morphet’s similar (dare I say superior) presentation at Remix and since then had a chance to play quite a bit with Sketchflow myself. Bad choice on my behalf – but then there wasn’t any other compelling content in this timeslot.

DEV260 Distributing and Monetizing Windows Mobile Applications through the Windows Marketplace for Mobile

I’ve been messing around building a few simple apps for my new HTC Touch Diamond 2 device and have considered launching an app or two on Microsoft’s new Windows Mobile Marketplace. I’d even gone so far as to entering a couple of very simple entries into the Codemason’s competition.

This talk became a very frank discussion about the good and bad points of the new Marketplace. It was definitely worth going to and the speaker was very open about the shortfalls in the scheme. For instance, although the marketplace will allow apps to be delivered to any of 29 countries you have to target each country individually – effectively taking a US$99 hit for registering each application instance in each country. Seems to make sense to initially target any application for the US only – I can’t see Australia or New Zealand having the volume of Windows Mobile users to support anything but a very locale specific application.

I got the general impression that most people leaving this talk would be less inclined to launch applications via Windows Mobile Marketplace. Seems a shame – like Microsoft almost got it right but then the marketing team came along at the last moment and crippled their solution.

Some random negatives:

  • Seriously – invest in a schedule builder that works. Please! How hard can this really be? Every year they insist on having some terrible web interface that has an awful user experience. It takes forever to get things into your schedule. This year is the worst yet. Its truly appalling – it doesn’t seem to work at all. Doesn’t matter how many times you click add/remove the schedule just won’t update. Most annoying!
  • With so many delegates with mobile devices Telstra’s NextG network seems a little saturated. It’s been a bit hit and miss and early in the evening I’ve been getting some really poor throughput.

And the flip side:

  • All delegates at Tech-Ed Australia 2009 receive a HP Mini 2140.
  • Mine was scheduled to be given to my mother-in-law as a lame-ass cheapo computer that will let her surf the net. The more time I spend with it though the more I’m starting to like it. The build finish is really very nice, performance seems not as bad as I expected and it seems to run Windows 7 Ultimate very nicely. The only thing about the device that is anything other than sweet is that it seems very loud. In a quiet hotel room my Fujitsu tablet PC can’t be heard at all over the HP Mini’s constant whirring even though its not in use.
  • Wireless connectivity at the event has been very good so far. After a few initial attempts at getting a connection the HP Mini worked flawlessly with the wireless. Resuming from sleep it connects back to the network in a matter of seconds. Good job!
  • Weather is awesome.
  • Got a good room at Jupiter’s Casino which is connected to the venue by a walkway.

Phew – that post was a little longer than I had originally intended. Anyone who has read this far is probably a work colleague – and yes I’m about to order room service then connect via VPN and start working on those bugs.

Developing for Windows Mobile – Composing User Controls

Tonight I finished refactoring the mobile UI framework I’ve been putting together so that it can correctly handle composite elements. Previously I’d been able to handle a collection of polygons (Rectangles, Stars etc.). I’ve now introduced the concept of DrawingContainers that themselves have a collection of elements, any of which may be another DrawingContainer.

The idea is that I can now construct UI controls that themselves are composed of simple graphic primitives. Just like WPF right? Each graphic element can have its own animations and hit test capabilities and controls can be composed within each other to form richer user controls. All this is rendered to the hosting Windows.Forms.Control in a single double-buffered render.

The class diagram below gives an indication of where I’m currently at. Everything in the diagram has been implemented.

 

Spencen.Mobile.UI

As one example of compositing controls I used a multi-part windmill.

Windows Mobile Spinning Wheel Thing_Thumb

Defined in code as:

var center = new Point( hostCanvas.Width / 2, hostCanvas.Height / 2 );
var yellowBrush = new SolidBrush( Color.Yellow );
var panel = new Panel( hostCanvas ) { Size = hostCanvas.Size, Center = center };
var bar1 = new Panel( hostCanvas ) { Size = new Size( 200, 20 ), Center = new Point( center.X, center.Y - 190 ) };
var bar2 = new Panel( hostCanvas ) { Size = new Size( 200, 20 ), Center = new Point( center.X, center.Y + 190 ) };
panel.Children.Add( new Rectangle() { Size = new Size( 50, 400 ), Center = center } );
bar1.Children.Add( new Rectangle() { Size = bar1.Size, Position = new Point( 0, 0 ) } );
bar2.Children.Add( new Rectangle() { Size = bar1.Size, Position = new Point( 0, 0 ) } );
bar1.Children.Add( new Star() { Size = new Size( 75, 75 ), 
Center = new Point( bar1.Size.Width / 2 - 90, bar1.Size.Height / 2 ),
Background = yellowBrush } ); bar1.Children.Add( new Star() { Size = new Size( 75, 75 ),
Center = new Point( bar1.Size.Width / 2 + 90, bar1.Size.Height / 2 ),
Background = yellowBrush } ); bar2.Children.Add( new Star() { Size = new Size( 75, 75 ),
Center = new Point( bar2.Size.Width / 2 - 90, bar2.Size.Height / 2 ),
Background = yellowBrush } ); bar2.Children.Add( new Star() { Size = new Size( 75, 75 ),
Center = new Point( bar2.Size.Width / 2 + 90, bar2.Size.Height / 2 ),
Background = yellowBrush } ); panel.Children.Add( bar1 ); panel.Children.Add( bar2 ); panel.Transforms.Add( _rotateTransform ); _rotateTransform.RenderCenter = new Point( hostCanvas.Width / 2, hostCanvas.Height / 2 ); panel.Host.AnimationManager.AddAnimation(
new FloatAnimation( _rotateTransform, "Angle", new TimeSpan( 0, 0, 50 ) ) { FinalValue = 3600 } ); var barRotation = new RotateTransform(); bar1.Transforms.Add( barRotation ); bar2.Transforms.Add( barRotation ); panel.Host.AnimationManager.AddAnimation(
new FloatAnimation( barRotation, "Angle", new TimeSpan( 0, 0, 50 ) ) { FinalValue = -7200 } ); var starRotation = new RotateTransform(); bar1.Children[ 1 ].Transforms.Add( starRotation ); bar1.Children[ 2 ].Transforms.Add( starRotation ); bar2.Children[ 1 ].Transforms.Add( starRotation ); bar2.Children[ 2 ].Transforms.Add( starRotation ); panel.Host.AnimationManager.AddAnimation(
new FloatAnimation( starRotation, "Angle", new TimeSpan( 0, 0, 50 ) ) { FinalValue = 18000 } ); hostCanvas.View.Children.Add( panel );

Other features so that I’ve got so far:

  • Support for Behaviours. So far the only implementation is a DragBehavior that allows dragging any attached element along one or both axis. Even supports a “flick” by determining the angle and velocity on mouse up and applying an animation with a cubic easing function to simulate velocity decay.
  • Scrolling between views/pages using an easing function (and BitBlt).
  • Simple image support.

Other ideas:

  • Button and ItemsList controls.
  • Stack and custom (e.g. radial) layout panels.
  • Integration with platform APIs to allow drawing of rounded rectangles, gradient fills and to support alphas.
  • A transform for flipping vertically or horizontally.
  • Behaviour to support an ICommand style interface to allowing hooking UI interactions with a view model.

Developing for Windows Mobile – Animation Basics

This post is a follow on from my most recent efforts creating some screens for a Windows Mobile application. I had decided to write a simple graphics library to help me do some nice transition effects. So over the last two nights I ported (actually rewrote) my original WinForms Transition demo to Windows Compact Framework.

So far I have support only for polygons, but that includes hit testing, transforms (rotate, translate, scale), animation (floats, points, colours, brushes) and easing functions (currently sine in/out and elastic out).

Hopefully I’ll post more about this (with source code) soon – but here is a quick demo video that I captured using Expression 3’s new screen capture utility (very neat!).

Windows Mobile Animations_Thumb

So far I’ve been really happy with the performance. Will be interesting to see how much it degrades once I start adding gradients, transparency and more complex shapes. [Note that the video doesn’t really reflect the performance too well.]

Developing for Windows Mobile – Getting Started

Now I have my new Windows Mobile 6.1 device I’ve decided to delve once more into the mysterious realm of developing for mobile devices. My previous forays have both been very lightweight. The most recent was simply displaying bus timetable information within a ListView control. Despite its simplicity its actually something I find very useful on my daily commute – rather than digging around in my bag for the paper version and then tuning in to the times and stops that I’m interested in.

Here’s a screenshot of my original Bus Timetable applet (its just too trivial to be awarded the title “application”):

BusTimetable - PocketPC 2003 SE

Now here’s a screenshot of the same application running on my new HTC device:

2009 07 06_21 15 12_0015_111g

Hmm.. some things scaled and some didn’t But overall when compared to the other default applications (particularly those written by HTC) it looks pretty lame.

So, I decided to get to work and create a user interface that:

  1. Scales well across the more common Windows Mobile devices resolutions (at least 240×320, 480×640 and 480×800).
  2. Fits with the “look and feel” of the pre-installed HTC applications.
  3. Works with touch only – this type of application needs to work using just my thumb since common scenarios for its use are when I’m walking through a crowd and carrying a bag.

With the help of the UIFramework from MSDN I managed to get some screens that I was pretty happy with. The icons and selection had gradient fills and the icons were superimposed on their corresponding “frames” with a transparent background.

2009 07 06_21 27 31_0016_111g  2009 07 06_21 28 35_0018_111g 

However, I soon found that things weren’t quite a rosy as I was hoping. To start with the UIFramework library sample seems to be a “work in progress”. That is to say it has a lot of bugs or parts that simply don’t work – its obviously intended as a starting reference for someone intending to owner draw their own controls/graphic elements.

Also, I originally created each ButtonBar as a user control. As with WinForms this meant that when it came to scrolling the buttons it looked terrible. Really slow – and each button is its own Window hence there is no capability of double-buffering. Man – I have been so spoiled by WPF – I had long forgotten all this pain! This trick then seemed to be to ditch using controls and just render the entire UI on a single user control. That way the main user control can double buffer all the rendering and there is only one render pass. The downside of course is that you then have to take care of everything – drawing all your own controls, hit testing, anchoring, dpi scaling etc.

Well – I’m not sure where I’m going with all this. But I did consider porting my WinForms Transitions code to the Windows CF. Even this was a no-go though – because although it contains plenty of base classes and helper methods for transforming and hit testing objects it relies heavily on using GraphicsContainer to do the actual transforms. These aren’t supported by the Compact Framework. So, I started from scratch, building a simple graphics library that will let me scale, rotate and translate graphic primitives. So far I have a spinning/zoomable rectangle – guess you gotta start somewhere.

MobileTransitions

NHibernate – a Quality ORM?

[This is a flame. If you are an NHibernate fan, please stop reading now, you’ll only upset yourself otherwise.]

Like many others I subscribe to the codebetter.com RSS feed. One of the members feels that its their personal responsibility to enlighten subscribers with endless NDepend analysis results for various frameworks. I almost always skip those posts.

However, this latest post regarding the NHibernate 2.1 release I found most amusing.

I’ve been subjected to NHibernate. I don’t enjoy the experience. Some of the pain that I’ve felt begins to make sense. 58,000 lines of spaghetti code to do some pretty simple ORM mapping – woot! {snigger}

Windows Mobile SDK disables Sierra 880U NextG Wireless Card

On my 50 minute bus trip home I often get out my laptop – whether its to finishing checking-in my days work via VPN, getting a headstart with projects that I’m working on at home, of even just catching up with blogs/mail etc.

Tonight I fired up the laptop, inserted my Telstra Wireless NextG card and… nothing. Just the message “Card not detected”. Tried both other USB ports no luck. Opened up device manager and there it was – exclamation marks against all the Network Adapters and Ports associated with my Sierra Aircard 880U. Not good!

I tried all the usual, time honoured, general purposes fix measures:

  • Reboot the machine
  • Disable and re-enable the devices
  • Un-install the devices and do a hardware scan to re-install them

No luck. When I got home I removed the drivers and tried to re-install from the original installation disk that came with the device. The installer failed right after selecting the modem device. So I re-installed the driver manually from the CD. The installation worked but still the device wasn’t detected.

Time to backtrack – it was working flawlessly last week. Once I’d got to this point the culprit became obvious. I had installed Windows Mobile 6.0 and 6.5 Developer Tools on the weekend so I could start doing development for my new phone on my laptop. It made a quirky kind of sense that this installation could have somehow installed some virtual drivers that were interfering with the real HDSPA modem.

Sure enough. After uninstalling Windows Mobile 6.0 Developer Tools and Windows Mobile 6.5 Emulators then re-inserting the modem it worked immediately. Great! But how do I get to have a working NextG Wireless Card and developer for a Windows Mobile device!? Is this just some quirky hardware issue on my laptop/install?

Continuous Tile Panel

A couple of weeks ago someone suggested to me an idea for a particular type of layout panel. The idea was to be able to display a fixed set of tiles which are “wrapped” horizontally. So as you scroll horizontally the tiles will move off one edge of the panel and eventually re-appear on the other side. Think of how we commonly see the earth projected onto a rectangle – scrolling left or right to bring the particular geography into the centre of the screen.

I jumped into this without giving too much thought about how I would want to interact with the panel from an API perspective. For that reason its probably I’ve taken altogether the wrong approach but I thought I would post it up here anyway, ‘cause its unlikely I’ll take it any further than this proof of concept.

Usage

Define some XAML like so:

<panels:TilePanel x:Name="tilePanel" Height="170"
Rows="3" Background="LightYellow" ClipToBounds="True"
XOffset="{Binding ElementName=xOffsetSlider,Path=Value,Mode=OneWay}"
YOffset="{Binding ElementName=yOffsetSlider,Path=Value,Mode=OneWay}"
Scale="{Binding ElementName=scaleSlider,Path=Value,Mode=OneWay}">
<panels:TilePanel.Resources>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="32pt"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Padding" Value="3"/>
<Setter Property="TextAlignment" Value="Center"/>
<Setter Property="Background" Value="LightBlue"/>
</Style>
</panels:TilePanel.Resources>
<TextBlock>A</TextBlock>
<TextBlock>B</TextBlock>
<TextBlock>C</TextBlock>
<TextBlock>D</TextBlock>
<TextBlock>E</TextBlock>
<TextBlock>F</TextBlock>
<TextBlock>G</TextBlock>
<TextBlock>H</TextBlock>
<TextBlock>I</TextBlock>
<TextBlock>J</TextBlock>
<TextBlock>K</TextBlock>
<TextBlock>L</TextBlock>
<TextBlock>M</TextBlock>
<TextBlock>N</TextBlock>
<TextBlock>O</TextBlock>
<TextBlock>P</TextBlock>
<TextBlock>Q</TextBlock>
<TextBlock>R</TextBlock>
<TextBlock>S</TextBlock>
<TextBlock>T</TextBlock>
<TextBlock>U</TextBlock>
<TextBlock>V</TextBlock>
<TextBlock>W</TextBlock>
<TextBlock>X</TextBlock>
<TextBlock>Y</TextBlock>
<TextBlock>Z</TextBlock>
<TextBlock>1</TextBlock>
<TextBlock>2</TextBlock>
<TextBlock>3</TextBlock>
<TextBlock>4</TextBlock>
<TextBlock>5</TextBlock>
<TextBlock>6</TextBlock>
<TextBlock>7</TextBlock>
<TextBlock>8</TextBlock>
<TextBlock>9</TextBlock>
<TextBlock>0</TextBlock>
</panels:TilePanel>

This generates the following layout where each of the items is laid out in three rows.

Continuous Tile Panel - Letters at Start

Items that are beyond the right edge are actually wrapped back to the left hand side (by subtracting the total width of all columns). So that when we supply a horizontal offset we get the desired effect.

Continuous Tile Panel - Letters Shifted

Note that in the example each column width is automatically calculated based on the widest element. Likewise row heights are calculated based on the tallest elements. Although this allows for different widths/heights per column/row its works well when all items are the same width and height.

One example usage of this control would be as an ItemsPanel for an ItemsControl that displays tiled images that form a single scene. It so happens that ICE generates these types of tiles (at various zoom levels) for publishing its panoramas.

<ItemsControl ItemsSource="{Binding TileSet}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="LightGray">
<Grid>
<Image Source="{Binding ImagePath}" Stretch="Uniform" Height="Auto"/>
                    <TextBlock Margin="4" TextAlignment="Center" FontSize="6pt" Foreground="White" Opacity="0.5" 
VerticalAlignment="Center" HorizontalAlignment
="Center"> <TextBlock.Text> <MultiBinding StringFormat="{}{0},{1}" > <Binding Path="ColumnIndex"/> <Binding Path="RowIndex"/> </MultiBinding> </TextBlock.Text> </TextBlock> </Grid> </Border> </DataTemplate> </ItemsControl.ItemTemplate> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <panels:TilePanel Margin="10" Background="LightYellow" ClipToBounds="True" Rows="{Binding TileSet.RowCount}" XOffset="{Binding ElementName=xOffsetSlider,Path=Value,Mode=OneWay}" YOffset="{Binding ElementName=yOffsetSlider,Path=Value,Mode=OneWay}" Scale="{Binding ElementName=scaleSlider,Path=Value,Mode=OneWay}"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl>

Continuous Tile Panel - ICE

 

Code

To load the ICE images into a collection of “Tiles” I wrote the following.

    public static class TileLoader
{
public static TileSet LoadFromFolder( string path, int zoomLevel )
{
var result = new TileSet(path, zoomLevel);
if ( !Directory.Exists( path ) )
throw new ArgumentException( "The specified tile folder does not exist.", "path" );
if ( zoomLevel < 0 )
throw new ArgumentException( "The zoom level must be >= 0.", "zoomLevel" );
DirectoryInfo tileLevelFolder;
try
{
var rootFolder = new DirectoryInfo( path );
var tileFolder = new DirectoryInfo( Path.Combine( path, "tiles" ) );
tileLevelFolder = new DirectoryInfo( Path.Combine( tileFolder.FullName, "l_" + zoomLevel ) );
}
catch ( System.IO.IOException ex )
{
throw new ArgumentException( 
string.Format( "The tile set specified by the path {0} is corrupt.", path ), "path", ex ); } var column = 0;
// Order the directories by numerical ascending, e.g. c_3 before c_21 foreach ( var columnFolder in tileLevelFolder.GetDirectories( "c_*" )
.OrderBy( d => int.Parse( d.Name.Substring( 2 ) ) ) ) { var row = 0; foreach ( var imageFile in columnFolder.GetFiles( "tile_*.wdp" )
.OrderBy( i => int.Parse( i.Name.Substring( 5, i.Name.IndexOf( '.' ) - 5 ) ) ) ) { var tile = new Tile() { ColumnIndex = column, RowIndex = row, ImagePath = imageFile.FullName }; result.Add( tile ); row++; if ( result.RowCount < row ) result.RowCount = row; } column++; } return result; } } [DebuggerDisplay("Column: {ColumnIndex}, Row: {RowIndex}, {ImagePath}")] public class
Tile { public string ImagePath { get; set; } public int ColumnIndex { get; set; } public int RowIndex { get; set; } } public class TileSet : List<Tile> { public TileSet( string path, int zoomLevel ) { Path = path; ZoomLevel = zoomLevel; } public string Path { get; protected set; } public int ZoomLevel { get; protected set; } public int RowCount { get; set; } }

The panel’s arrange override code is as follows:

protected override Size ArrangeOverride(Size finalSize)
{
int row = 0;
int column = 0;
double fullWidth = _columnWidths.Sum();
double fullHeight = _rowHeights.Sum();
int maxColumns = (int) Math.Ceiling( (double) finalSize.Width / (double) _maxChildWidth);
double x = -( XOffset * _maxChildWidth );
double y = - YOffset;
foreach (UIElement child in Children)
{
x = x % fullWidth;
if (x >= Math.Min(_maxChildWidth * maxColumns, fullWidth - _maxChildWidth + 1))
x -= fullWidth;
else if (x < - _maxChildWidth)
x += fullWidth;
if ( x > -_maxChildWidth && x <= _maxChildWidth * maxColumns &&
y > -_maxChildHeight && y <= fullHeight )
{
child.Arrange( 
new Rect( new Point( x * Scale, y * Scale ),
new Size( child.DesiredSize.Width * Scale, child.DesiredSize.Height * Scale ) ) ); child.Visibility = Visibility.Visible; }
else { child.Visibility = Visibility.Hidden; child.Arrange( new Rect( new Point( 0, 0 ), new Size( child.DesiredSize.Width * Scale, child.DesiredSize.Height * Scale ) ) ); } y += _rowHeights[ row ]; row = ( row + 1 ) % Rows; if ( row == 0 ) { x += _columnWidths[ column ]; //column * _childWidth ; y = -YOffset ; column++; } } //RenderTransform = new ScaleTransform(Scale, Scale, 0.0, YOffset); return finalSize; }

This is far from complete – sample project can be found here. [It’s a VS2010 project but should be easy enough to re-assemble for VS2008.]