Tuesday, July 28, 2009

Adventures while building a Silverlight Enterprise application part #17

Today we are looking into databinding to the ComboBox.SelectedItem property trough a custom dependency property in a UserControl.

Post 42
But before all that I want to let you all know, this is post #42 on Developers 42. For obvious reasons this is a special post on my blog. As I started out last year, I didn't have any visitors, but now I average about 1700 visits a month. A large part of these visits come trough Google, but a special thanks goes out to Dave Campbell for publishing a lot of my articles on SilverlightCream.com. Trough his great efforts of bringing us the latest and greatest on Silverlight, his website is the second greatest referrer, only topped by Google. I won't elaborate any more on this. Stats, highs and lows will all be published in October when the blog celebrates it's first year of existence.

Binding to ComboBox.SelectedItem trough a custom dependency property in a UserControl.
I ran into this building a user control based on the requirement that we need a combo box that includes an edit button next to it when needed and also provides a label when needed. Simplest way to do this (at least as I see it), is trough building two UserControls. The first combines the ComboBox with a Button and the second combines the result with a TextBlock. Today we want to focus on the first one, which I dubbed ExtendedComboBox. I wrote the following XAML as a start:

<UserControl xmlns:input="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input"
xmlns:inputToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"
x:Class="ExtendedComboBox.ExtendedComboBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows"
x:Name="extendedComboBoxControl"
>
<StackPanel x:Name="stackPanel" Orientation="Horizontal" HorizontalAlignment="Stretch">
<ComboBox x:Name="comboBox"
HorizontalAlignment="Stretch"
SelectionChanged="comboBox_SelectionChanged"
>
</ComboBox>
<Button x:Name="editButton" Content="..." Padding="5,0,5,0" LayoutUpdated="editButton_LayoutUpdated"
Click="editButton_Click"/>
</StackPanel>
</UserControl>


Simple enough. All I had to do now was add some dependency properties to control some functionality and Bob's your uncle, wright? Wrong! I will spare you the details on sizing specifics and events, as this is not the focus of this article.

For databinding I figured I would need to bind to the ItemsSource and the SelectedItem properties of the ComboBox. Here is the code I initially came up with:

publicIEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
comboBox.ItemsSource = value;
}
}

// Using a DependencyProperty as the backing store for ItemsSource. This enables animation, styling, binding, etc...
publicstaticreadonlyDependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(ExtendedComboBox), newPropertyMetadata(null));

publicobject SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set
{
SetValue(SelectedItemProperty, value);
comboBox.SelectedItem = SelectedItem;
}
}

// Using a DependencyProperty as the backing store for SelectedItem. This enables animation, styling, binding, etc...
publicstaticreadonlyDependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object), typeof(ExtendedComboBox), newPropertyMetadata(null));


As you can see these are standard dependency properties, only I've added a line to assign their values trough to the ComboBox. For the ItemsSource property this works like a charm, however, for the SelectedItem property it doesn't.

After struggling with this, building a complete test rig and reading trough books worth of blog posts, I finally came up with the following solution. I removed the passing trough of the value in the properties setter method and added manual binding for the property in the constructor of the ExtendedCombobox. Here is my new constructor:

public ExtendedComboBox()
{
InitializeComponent();
Binding selectedItemBinding = newBinding("SelectedItem");
selectedItemBinding.Source = this;
selectedItemBinding.Mode = BindingMode.TwoWay;
comboBox.SetBinding(ComboBox.SelectedItemProperty, selectedItemBinding);
}

This way the ExtendedComboBox becomes the source of the binding for the ComboBox.SelectedItem property. After adding this (and obviously also implementing the Equals and GetHashCode methods on the business objects involved) it now works like a charm, without having to write any extra code in the modules that use this control.

Please leave me a comment if you have any questions, remarks or if you just want to say hi.

Monday, July 20, 2009

Adventures while building a Silverlight Enterprise application part #16

So I've seen the release of Silverlight 3 coming for a while now and we've had some discussion about upgrading or not. In the end we concluded that the only reason not to upgrade would be a big impact on our existing application. We decided we would have to wait for the final release before testing it with our current code.

I've heard a lot about backwards compatibility, but I've heard that before with other upgrades and I had a lot of disappointment when actually trying that out. When it comes to backwards compatibility I guess seeing is believing. So last week I took some time to check out the upgrade to Silverlight 3.

To make sure I wouldn't do anything to my own development environment I decided to take a virtual machine and test it on that.
Here is what steps I planned to test our application with Silverlight 3:
  1. Install the Silverlight 3 Runtime
  2. Test our application with the Silverlight 3 Runtime
  3. Install a Silverlight 3 development environment
  4. Change the .aspx page to use the object tag instead of the asp:Silverlight control
  5. Get the complete solution to compile
  6. Get the application to run
  7. Test for behavior changes
The first two steps were a breeze and everything worked as expected. This was great, but I had somewhat expected this as the Silverlight 3 Runtime was still handling my application as if it was a Silverlight 2 application. Test passed.

Because all I wanted to do with the development environment was test the Silverlight 3 migration of our client software, I decided to use the new Microsoft Web Platform Installer to setup the tools needed. I haven't tried it before, so I didn't know what to expect. Actually I had only one surprise during setup, which was with the installation of IIS. It requested me to insert the disks for, in this case, Windows XP SP2, so it could copy the files for IIS from that disk.

Other than that, which is still a logical choice as IIS is obviously part of the Windows license you have, everything was downloaded and installed automatically and I was done installing everything in two hours, while reading up on breaking changes between Silverlight 2 and 3 (weird for a backwards compatible release, right :-p). All in all I was pleasently surprised by this great new solution from Microsoft and I hope they soon allow us to install your licensed version of Visual Studio trough the WPI.

Now that I was ready to test the actual upgrading of my application to Silverlight 3, I copied the sources to my virtual machine and opened the solution with Visual Web Developer. Apart from some mistakes where I forgot to copy some linked files, it opened and converted my solution without any hickup.
After putting in the missing files, it compiled without problems. I pressed F5 and waited with anticipation...
...it worked on the first try! However, I was going a little to fast as I didn't replace the asp:Silverlight tag with the object tag and it was still running with the famous quirks mode enabled (as the minimal version still pointed to Silverlight 2). I replaced the asp:Silverlight tag with the object tag as it looks below:

<div id="silverlightControlHost">
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="ClientBin/someapp.xap"/>
<param name="onerror" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="3.0.40624.0" />
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40624.0" style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
</a>
</object>
<iframe id="_sl_historyFrame" style='visibility:hidden;height:0;width:0;border:0px'></iframe>
</div>


I ran the application again...
...and it still worked as expected! After some more testing, the only change in behavior that I could find in our application was with the ListBox.ScrollIntoView method. In Silverlight 2, if you would call this with the last item in the listbox, it would scroll it into view, but it would still be at the bottom of the screen. In Silverlight 3, if you call this with the last item, it will actually scroll the item to the top of the listbox, showing empty space below it. As this is the preferred behavior in our case, I haven't done any research to see if I could change it.

All in all, this has been one of the most painless migrations I have experienced ever. Microsoft, my compliments on a job well done.

Wednesday, July 15, 2009

CodeEmbed4Web Beta 1 Release

Today it is my pleasure to announce to you the release of CodeEmbed4Web Beta 1. This public beta release of my new tool is available for download below.

As written in earlier posts, this tool allows you to copy code from Microsoft Visual Studio or another program that copies it's code in Rich Text Format, convert that code to other formats using predefined templates and then paste that converted code into any other program. The purpose of this tool is to quickly convert source code into publishable formats, like for example HTML, with a minimal effort and without limitation as to where it's going to be used.

With Beta 1, two templates are included:

  • CodeEmbed4WebXml.xslt allows you to get an exact copy of the XML generated by the tool. This enables you to build your own .xslt templates based on example XML files you can generate yourself.
  • ToHtml.xslt allows you to directly convert any code to html, so you can copy it into an html compatible program.
Feel free to add your own templates in the templates folder you find in the installation folder. New templates are automatically added to the tool as it starts up. If the tool is already started, please click the Refresh button that is below the list of templates.
The template you had selected last, will be selected when the tool starts.

Now without further delay, I present you with the download link:

CodeEmbed4Web Beta 1 (.msi)

If you need any support, found a bug, ran into an error, have any questions, suggestions or remarks, or you just want to let me know you are using CodeEmbed4Web Beta 1, please send an email to codeembed4web@gmail.com.

Update: Unfortunately I have recieved some reports of CodeEmbed4Web not being able to start. For some reason it throws an exception. I have been able to reproduce this behavior and I am looking into it. As soon as I figure it out, I will let you know. If you have this problem and if you are willing to provide me with some information on this, please send an email to codeembed4web@gmail.com.

Update: I've recently fixed the above issue and reposted the setup at the above link. I'll also release a simple patch soon.

I hope you all enjoy this tool and please provide me with feedback.

Friday, July 10, 2009

Adventures while building a Silverlight Enterprise application part #15

This was one of these weeks. You know, a week that gets hectic unexpectedly? Last Tuesday-night we had a company meeting as we have every three months. Some of the major topics inside the company are presented to the entire staff. This varies from finances to important projects and new customers. One of the topics was the new version of our system on which I was to be giving a short demo.

Not so much of a problem until I decided to publish the latest standing of the Silverlight client to my local IIS on Tuesday-afternoon, with only about 30 minutes to go until the start of the meeting.
I know, I shouldn't be doing that so short before a demo, but I spend the days before that drastically improving the layout of the application, together with one of our product-experts and we decided, this being an internal presentation and all, that it was important to give a positive impression to the staff with this new and improved interface. I got a 'Publish succeeded' from Visual Studio so I fired up Internet Explorer and surfed to my local site, hosting the Silverlight client. I saw the first peaces of the application come up and then, all of a sudden, it threw an exception...

As I now had only 25 minutes left, I was in a tight spot. I decided to use my time to go over the demo from Visual Studio, to make sure everything worked nicely in there. After that, with only 10 minutes left, I decided I would demo from Visual Studio, as there was no time to actually troubleshoot the IIS deployment.

I don't think anyone noticed, or even cared for that matter, but I personally hate doing demos from Visual Studio. You always run the risk of running into some forgotten break point or that exception that you did catch still stops in the IDE. You could run in all sorts of problems.

After that I was busy for the past days, rebuilding some of the code generation we use for our business objects, so they would now use CodeDom, instead of a StringBuilder, so I had no time to troubleshoot the IIS deployment process untill today, when I had too, because this afternoon we want to update our test environment.

I tried attaching Visual Studio to iexplore.exe to see if I could debug my code this way, but none of my breakpoints would trip (altough Visual Studio did catch the JavaScript exception that is thrown when something isn't catched in Silverlight). This made it a lot more difficult to find out where things went wrong. Fortunately we load several .xap files on the fly, so I opened up HttpWatch and recorded the traffic while reloading the application. I did several runs and found out that the problem was always with loading one particular .xap file.
At first I thought it may be because an older version would be loaded from cache, as loading the .xap file would trigger a HTTP 304, meaning a version was loaded from cache. Clearing out the cache, however, didn't resolve the problem.
I was on to something however. I republished my solution to IIS, cleared the cache and tried again. This time I did get a HTTP 200, meaning that the .xap file was loaded OK, but I still got an exception. I opened up the ClientBin folder containing the .xap files for my IIS deployment and looked at the filedates.
It turned out that some of my .xap files were actually not updated recently! As I did make changes to assemblies that these .xap files use, surely they crashed. I went into Visual Studio again and published once again, this time specifying that any files should be deleted from the folder first.
I refreshed the application in Internet Explorer and suddenly it all workes nicely.

So some lessons learned:
  • Take more time before a presentation to make sure everything works
  • Don't trust Visual Studio to know when files need updating
  • Completely redeploy your applications every now and then
I hope you may prevent these pitfalls because you read them here first.

P.S.: For everyone wondering about the CodeEmbed4Web tool, the code is pretty much done, just some organizational stuff to be taken care off.

Friday, July 3, 2009

The birth of CodeEmbed4Web part #2

As it's Friday today, I figured I give an update on the CodeEmbed4Web project. I've been working on this on and off for the past week and a half and got some stuff done. As you may still remember from the previous post I sad I would test the mechanism I came up with to make sure it works with XAML as well. I'm happy to let you know it works exactly like expected.

I haven't got around to building a template for C# yet, let alone for XAML, but I have been putting a lot of thought into how the user interface for this tool should look. Some considerations:
  • The tool shouldn't be invasive. This means that it should take the smallest space possible without disturbing the functionality.
  • As I'm using WPF, I figured it should look good, but as I'm not much of a designer I figured I would use one of the themes from the WPF Toolkit.
  • It should be flexible in allowing to add new templates.

After playing around with Microsoft Expression Blend 3 Preview I came up with what you can see in the screenshot below.




No, it's not integrated with Visual Studio. That's just to show you how small the user interface is. You can go trough the buttons from top to button, to use the tool. The top tool expands a list of templates, so you can select your template. The middle button converts whatever code is on the clipboard and puts it back on the clipboard. The bottom button expands a menu which, at the moment, only allows you to close the tool.

At the top of the user interface, above the first button, is a handle you can use to drag the tool anywhere.

So, next steps:

  1. Finish up the user interface in terms of behaviour (not showing it in the task bar and staying on top of other windows, just to name a few).
  2. Build a template for C#
  3. Build a setup
  4. Release Beta 1

I would love to know what you think about the user interface and if you have any ideas to further improve on it. Please let me know what you think, by leaving me a comment.