I’ve been thinking a lot about Windows Mobile 6.5 and 7.0. Everyone is very focused on the user experience that Microsoft will provide. Will they show the hexes or hide the hexes… Will it have Multitouch or not? Zune integration? Will it be more stable? These are all great questions, but as a developer, none of them are the right question for me. I mean, I want the Zune Marketplace on my WM device, no doubt about it. However, there’s one thing I want more than any other as a developer.
WPF for Windows Mobile!
Yes, that’s what I want as a developer. I want my .net, but I want it pretty and usable. Is that too much to ask? Let’s face it. The .net compact framework is extremely powerful once you get past the UI. But the UI is what makes the experience, and CF is sorely lacking. WM isn’t competing against dumbphones anymore. It’s competing against the iphone and the Pre and others like it. Each of these devices does a tremendous job of making applications easy to use, and, dare I say it, fun! WM, not so much.
Why not WPF?
I can think of a few reasons why we don’t have WPF. I have no inside knowledge; these are just guesses.
Memory? Maybe WPF will take up too much memory on these devices. Newer devices come with a significant amount of memory, so don’t think this is it, at least not with devices that will officially support 6.5+.
Non-touch screens? This is a biggie. Many WM phones don’t support touch. It’s much easier to create a Winform app that can be controlled with buttons than it is to create a WPF app that is built from the ground up for touch. It can be done, but it would take more work. My response to this is that MS could just make WPF for touchscreens only. I’d rather not see this, but I’d prefer it over not having WPF at all.
No developers to get it done? Maybe Microsoft just got caught resting on their laurels when the iphone came out. Maybe they simply didn’t recognize that their UI would be mocked the minute iphone v1 was released and the first comparisons went online. It continues to amaze me how I see small companies come out with great, innovative software that is better than MS, but when MS sets out to do something, it seems to take forever. I have to believe that a WPF v1 could be released in a matter of a few months with the right resources on the job (I hate it when other people do this to me… presume to know how quickly something *should* be able to be done, so I beg forgiveness if I am way off base here).
Those are some reasons I can think of off the top of my head. I’m sure there are more reasons.
Now, there is one wildcard in all this…
Silverlight for Windows Mobile
MS has announced that Silverlight will be released for Windows Mobile. Since Silverlight (v2+, at least) is a subset of WPF, this really shows that it can be done. I don’t count SLOOB (Silverlight Out-of-Browser, in v3) as a viable alternative, since it runs in a sandbox, and therefore is too limited for many apps I, and others, would want to write for WM.
So, what to expect?
I have no expectations. I wish I had inside knowledge. I have none. I was extremely hopeful that MS would announce WPF for WM at Tech-Ed, but they didn’t. I’ll continue to hope.
[More]
I'm trying to reuse an animation that I create programmatically. The why isn't important. What is important is that the second time I try to run it with animation.Begin(), it bombs. Well, with some properties it bombs. With others, it works. Transform properties cause the error, but standard properties like opacity and canvas location work when you run the animation multiple times.
Below is a sample app. Button one and two are two instances of the same created animation. Each of them will run once, but fail the second time. This shows that it's not the object being animated, but the animation itself that is causing the error. Button three and four are opacity animations, and show that animations that change opacity never fail when run multiple times.
I'm sure one suggestion will be to recreate the animation each time. However, in my real-world app, I capture some object properties at the time the animation is created, and need to have these same values used each time the animation runs. If I were to grab the properties over each time I recreated the animation, the object might be in a different state. And I don't want to cache the initial values, because 1) it makes my animation library less flexible, and 2) I just want to do it this way, 'cause it's easier :).
I've added my code after the sample app. If anyone has any idea what I can do to prevent this while still creating the animations programmatically, please add a comment.
Here is the xaml (Page.xaml).
<UserControl x:Class="AnimationReuseTest.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid x:Name="LayoutRoot" Background="White"> <Rectangle x:Name="recMain" Height="54" Canvas.Top="225" Stroke="#FF000000" Margin="65,136,76,110" VerticalAlignment="Stretch" d:LayoutOverrides="Height" Fill="#FF941414" RenderTransformOrigin="0.5,0.5" Opacity="0.1" > <Rectangle.RenderTransform> <TransformGroup> <ScaleTransform ScaleX="0.8" ScaleY="0.8"/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </Rectangle.RenderTransform> </Rectangle> <Button Height="40" Margin="24,0,0,70" VerticalAlignment="Bottom" Content="Animate1-scalex" x:Name="btnAnimate1" Click="btnAnimate1_Click" Width="163" HorizontalAlignment="Left"/> <Button Height="40" Margin="0,0,37,70" VerticalAlignment="Bottom" Content="Animate2-scalex" x:Name="btnAnimate2" Click="btnAnimate2_Click" Width="163" HorizontalAlignment="Right"/> <Button Margin="24,0,0,26" VerticalAlignment="Bottom" Content="Animate3-opacity" x:Name="btnAnimate3" Click="btnAnimate3_Click" HorizontalAlignment="Left" Width="163" Height="40"/> <Button Height="40" Margin="0,0,37,26" VerticalAlignment="Bottom" Content="Animate4-opacity" x:Name="btnAnimate4" Click="btnAnimate4_Click" Width="163" HorizontalAlignment="Right"/> <TextBlock Height="124" Margin="8,8,8,0" VerticalAlignment="Top" TextWrapping="Wrap" x:Name="lblErrorMsg" FontSize="8" /> </Grid> </UserControl>
And here is the code (Page.xaml.vb).
Partial Public Class Page Inherits UserControl
Dim s1 As New Storyboard Dim s2 As New Storyboard Dim s3 As New Storyboard Dim s4 As New Storyboard
Public Sub New() InitializeComponent()
'add storyboards to resources - not sure why, but I'm following examples I've seen LayoutRoot.Resources.Add("S1", s1) LayoutRoot.Resources.Add("S2", s2) LayoutRoot.Resources.Add("S3", s3) LayoutRoot.Resources.Add("S4", s4) 'initialize the storyboard to animate the rectangle CreateAnimation(s1, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)") CreateAnimation(s2, "(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)") CreateAnimation(s3, "(UIElement.Opacity)") CreateAnimation(s4, "(UIElement.Opacity)") End Sub
Sub CreateAnimation(ByVal s As Storyboard, ByVal Prop As String) 'create new doubleanimation Dim d As New DoubleAnimation 'set timespan to half a second d.Duration = New Duration(TimeSpan.FromSeconds(0.5)) 'reverse animation d.AutoReverse = True 'set target to the rectangle Storyboard.SetTarget(d, recMain) 'we're animating x-axis scale - other props, like (Canvas.X) will work, though Storyboard.SetTargetProperty(d, New PropertyPath(Prop)) 'animating from start value of to 1 d.To = 1 'add doubleanimation to storyboard s.Children.Add(d) End Sub
Private Sub btnAnimate1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) 'begin animation when button is clicked - we'll get the error below the second time we click the button. 'Cannot resolve TargetProperty (UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX) on specified object. Try s1.Begin() Catch ex As Exception lblErrorMsg.text = ex.ToString End Try End Sub
Private Sub btnAnimate2_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) 'begin animation when button is clicked - we'll get the error below the second time we click the button. 'Cannot resolve TargetProperty (UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX) on specified object. Try s2.Begin() Catch ex As Exception lblErrorMsg.text = ex.ToString End Try End Sub
Private Sub btnAnimate3_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) 'begin animation when button is clicked - we won't get an error on animating s3.Begin() End Sub
Private Sub btnAnimate4_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) 'begin animation when button is clicked - we won't get an error on animating s4.Begin() End Sub End Class
Firefox and Safari seem to be destroying and recreating a Silverlight object when it's inside of a control that has its style set to "display:none". It doesn't do this when visibility is used instead of display.
Here's a working example. I fire an alert in the silverlight object's onload method. In IE, the alert doesn't pop up when you switch display back to '', but in Firefox and Safari, it does.
Example at airportwait.com (my demo site)
I'm sure the next question you're going to ask is why I don't just use visibility... Well, I'm using the ajax tabcontainer control, and it's using display to show/hide tabs. More importantly, it just doesn't seem right. It might be ok when your silverlight control is static, but I'm using javascript to initialize a photoviewer I wrote, and don't want it to have to lose the viewer's place.
Anyway, does anyone know why this is? Is it some kind of standard to destroy objects when their parent is set to display:none? Is there a workaround?
John
ps. And dang it all, I thought Silverlight was the end of browser compatibility issues ;). I could also go into why different browsers fire different silverlight events at different times (onresize, do you hear me?), but I'll leave that alone.
Everyone knows Silverlight is an object embedded in the browser. Therefore, it has the same nuances as other plugins like Flash.
What nuances? Good question.
Nuance #1 - Displaying HTML over Silverlight
I added an autocomplete extender to the airport name text box at www.airportwait.com. It worked great, except that the dropdown selections don't display over the Silverlight control on the page. This has always been an issue with plugins, and even with select controls (thankfully, the select control issue is fixed in IE7).
To fix it, I redesigned the page to hide the Silverlight control during airport name entry.
Nuance #2 - Silverlight object timing issues
I have a javascript method called ProcessResults that calls a method on my Silverlight object, which in turn displays the airport wait times. I tried this:
createSilverlight(); ProcessResults();
No good. There's a certain amount of time after createSilverlight() is called when the object isn't yet available.
So, I had to do this:
createSilverlight(); StartResultsDisplay();
function StartResultsDisplay() { setTimeout("ProcessResults()", 500); }
function ProcessResults() { ... }
This way, I wait half a second before beginning to display the data. Problem solved.
Oops. As soon as I wrote this, I remembered I could just specify an onLoad event handler for the Silverlight plugin. I thought about deleting this part, but it's still good info if someone else is dealing with the same thing.
Silverlight.createObjectEx({ ... }, events: {onLoad:ProcessResults} });
UPDATE: I changed this again. Because the Silverlight control was immediately calling the ProcessResults method after loading, the page didn't render fully until the loading was complete. This is because it takes a second or two to retrieve data for some airports, and during this time Silverlight "hangs" browser events.
Now, I still use the Silverlight onload event handler, but I wait a quarter-second to give the browser time to finish rendering.
events: {onLoad:function() {setTimeout("ProcessResults()", 250)}}
Summary
Again, these aren't uncommon issues. Still, they're the types of things that just continue to remind me that, while I love the deployment model and reach of the web, it will always be inelegant compared to smart client development!
The need So, I've been playing with Silverlight 1.1. I'm coauthoring an upcoming Silverlight 1.1 book, so it's kind of important that I know this stuff ;). I was looking for some kind of real-world app I could sink my teeth into. Genesis of an idea Around the same time, I was getting ready to fly down to Jacksonville to help out a client. I went to TSA's web site to check wait times at the security checkpoints. I got the data back, but it wasn't as useful as I thought it could be. Here's an example of the results: I looked a little further down the page, and, lo and behold, there was a link to the data in XML format. An idea was born! From concept to reality I'm not a graphics guy. However, it didn't take a rocket scientist to realize that the TSA data could be presented in such a way that a user could immediately decide the best time to go through security. I came up with a pie chart-like clock metaphor, where a glance at the chart gave you both average (outer colors) and max (inner colors) times for the entire day. Here's a screenshot: Finally, I extended the UI to display the whole week for each checkpoint on one screen. With the TSA web site, you can't get a feel for traffic patterns, or what the busiest times are. On the other hand, by using Silverlight, it becomes immediately apparent when you DON'T want to be at the airport! Architecture I wrote a web service in .NET to provide the data. The Silverlight app has three controls, the Clockgrid control, the Clock control, and the Slice control. The Clock control is made up of Slice controls, and the Clockgrid control is used to position the Clock controls on the page. The Clock and Slice controls were designed in Blend. It's all hosted on an asp.net page that's used to provide the airport selection capability. <shamelessplug> If you want to learn more, you'll have to pick up the upcoming Silverlight book I'm working on :)! </shamelessplug> What I learned Silverlight 1.1 is incredibly powerful! I've been doing ajax-like apps since Microsoft's first xmlhttp implementation. I've always thought it was incredibly fragile. On the DOM side, you have to worry about browser-specific idiosyncrasies. On the web service side, you have to worry about data formats, async callbacks, etc. Yes, I know there are libraries like ajax.net that wrap the hard work for you, but that doesn't mean the problems don't still exist. Well, with Silverlight, it's so much easier in comparison! There is one UI, the Silverlight UI. No worries about incompatibilities. On the web service side, you can add a reference to a web service just like you can within a traditional .NET app. Everything gets wired up for you. And best of all, it's all in managed code!!! Life is good! Try it for yourself Ok. I hesitate to throw a URL out there, but since this is my first blog post, and no one reads this :), why not? If you want to try the app above, go to http://www.airportwait.com. You'll need the latest Silverlight 1.1 refresh in order for it to work. I still need to clean up some things, and some airport codes don't work like they should (MSP, for example), but you should get the idea. And hey, since the data is updated as of a week ago, you might actually find it useful if you're flying somewhere! Left undone Here's what I want to do when I have more time. Make it prettier. It needs the standard web page treatment (menus, header, etc). Add a scale animation when you mouseover a clock chart. This way, the clock would zoom in and out as it was selected and unselected. Fix 0am to be 12am :). Fix the airports that don't work. I think the reason is because Silverlight limits the returned web service data size to 120,400 bytes. I know how to change this in asp.net, but I have not found a setting in Silverlight. This is one of the reasons it takes a few seconds to display an airport. Instead of making one call to the web service to get the data for an airport, I had to break it into seven calls, one for each day. While slower, this enabled larger airports to work. More data! I'd love to show flight on-time statuses and other significant airline-related data. Ah, one day... Final thoughts I've heard a lot of people wonder how useful Silverlight's going to be for anything other than playing video. Well, hopefully this example gives you a little taste of how Silverlight can make any application that has data more useful. Download the SDK and get started today!