Silverlight 3 Custom User Control Binding – Binding a ComboBox

October 31, 2009

So it’s late on the night before Halloween and I figured out something I wanted to share. Even with postings on forums, I did not get an answer to my problem. What problem you ask? Funny you should ask, and fortunate for you that you stumbled onto this article. Or better yet, maybe you can’t sleep either because you too have a user control you are creating in Silverlight and it wont bind correctly! Damn this thing!

The problem

I am creating a user control that contains two textblocks and a combobox. One textblock is a title, and the other a footer. The combobox sits between them. So all I wanted to do was to databind my collection to the combobox.

I have never before created a custom user control in Silverlight which is why I had to create one in the first place. I hate not having done something, don’t you? I created the xaml in blend (what a pain that was, I still just don’t get that program apparently). Then I created my code-behind for the control.

I created properties for TitleText, FooterText and ItemsSource (for the combobox). The TitleText and FooterText properties just get and set the text of the corresponding textblock controls like this:

public string FooterText
{
    get { return _lblFooter.Text; }
    set { _lblFooter.Text = value; }
}

Then I did the same for the binding of the combobox like this:

public IEnumerable ItemsSource
       {
           get { return _cboData.ItemsSource; }
           set { _cboData.ItemsSource = value; }
       }

 

After building the control, I put it in a hosting page with binding directives like so:

<sydControls:CascadingPicker x:Name=”YearPicker” Margin=”8,241,513,94″ TitleText=”Select Year” FooterText=”Hover To Change Year” ItemsSource=”{Binding Source={StaticResource YearDataSource}}” ItemTemplate=”{StaticResource YearsComboItem}” />

Looks like it should work right? WRONG!

What did I miss?

After a couple days of pulling out what little hair I had left I found something called DependencyProperty. It was the answer to my problems, except I didn’t get it at first. Apparently, you are not supposed to create properties in Silverlight controls the way I did above. The properties need to be injected (heh heh he said injected) into the Silverlight context for the page rendered. It has to do with the way things are bound and allows things like the DataContext to interact with your controls properties.

the Solution

The solution is as follows. Remove the ItemsSource property and replace it with this:

public IEnumerable ItemsSource
{
    get { return (IEnumerable)GetValue(ItemsSourceProperty); }
    set { SetValue(ItemsSourceProperty, value); }
}

Wait a sec?!? If my setter calls SetValue, then where can I put my code to pass the incomming value to my combobox.ItemsSource?? The answer is in the DependencyProperty, you also need to do this:

public static readonly DependencyProperty ItemsSourceProperty =
    DependencyProperty.Register(“ItemsSource”, typeof(IEnumerable), typeof(CascadingPicker),
new PropertyMetadata( new PropertyChangedCallback(CascadingPicker.OnItemSourcecPropertyChanged)));

WOW! What crap huh? Yup, what this is, is a DependencyProperty.Register() method call. You give it the name of the property it is going to depend on, and next you tell it what datatype is used in the property (IEnumerable in this property) then you give it the control’s datatype (mine is called CascadingPicker), then you give it a callback to a method to call when it receives a propertychanged event. I am using the Entity Framework for my object, so it has that plumbing built-in. If you are rolling your own POCO then just implement the interface INotifyPropertyChanged and call NotifyPropertyChanged(“<PropertyName>”) on your setters. You see this static thing gets the actual instance of your control passed in along with the value being set, so in your callback method you could just do something like this:

private static void OnItemSourcecPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var cascadingPicker = d as CascadingPicker;

    if (cascadingPicker != null)
    {
        cascadingPicker._cboData.ItemsSource = e.NewValue as DataTemplate;
    }

}

You take the passed in control and then you can use it to access your properties and fields to assign your values.

Another way to do it, and the way I chose to implement it was to use lambda expressions instead of a callback. You could easily combine the above two calls into one like this:

public static readonly DependencyProperty ItemsSourceProperty =
          DependencyProperty.Register(“ItemsSource”, typeof(IEnumerable), typeof(CascadingPicker),
new PropertyMetadata((o, e) =>
                                      {
                                          var cascadingPicker = o as CascadingPicker;

                                          if (cascadingPicker != null)
                                          {
                                              cascadingPicker._cboData.ItemsSource = e.NewValue as IEnumerable;
                                          }
                                      }));

This is the same call as before, but I added the lambda (o,e) => {} instead of the callback method, it just does it inline and is a bit less code.

So that was it, the xaml code remained the same, it was just that I didn’t understand the way I was supposed to create properties in Silverlight controls. Now I know and now I can create re-useable data-bindable Silverlight controls.

Ok here is your test, close your eyes and tell me the syntax of a DependencyProperty. Yeah Right! Thanks for keeping it simple Microsoft…. well at least it works!

 

-Savij


Silverlight Design

October 23, 2009

Silverlight 3

Today I want to blab about Silverlight. Microsoft, the people who brought us “Bob” are now touting Silverlight version 3. To me it should be version 2 because Silverlight 1.0 was crazy and I considered that not much more than a technology preview at best. I decided to go into this with an open mind and I’m glad I did! After a learning curve that takes at least a week or two (a lot for a seasoned developer IMHO) I found it really fun to program in. So fun in fact, that I am going to write an application in it.

As far as the iPhone game I was doing, it kind of fell apart on my end. Having never written an iPhone app, I thought writing a game would be fun, but it would have taken soooo long to complete, I may be better off getting some smaller projects out of the way. I still want to do it, but I just don’t have the time right now. So, back to Silverlight.

Silverlight is a cool tehnology that allows rich client interaction hosted in a web browser. If this sounds a lot like Flash, then you’re right as far as that goes. Silverlight is more a competitor to FlexBuilder in nature though. While you can do all the fancy animations and games like Flash does, the IDE and it’s counterpart Blend are more in tune with creating applications rather than flashy intro screens (although it does those as well).

As of Silverlight 3, there is no longer a Read Only designer in Visual Studio, in fact, they have removed the designer completely! You get XAML only now. So unless you are one o those purists who still write HTML in Notepad (sorry TextPad I meant; NotePad is much too Microsoft for the purists) you will be using Expression Blend 3. So, once you get the learning curve for Silverlight out of the way, you now have a learning curve for Blend. Thanks to a unified team at Microsoft though, Blend looks NOTHING like Visual Studio. They kind of ripped off Photoshop IMHO because they want to reel in the designers. Since I am doing this project on my own, I am the designer….. more to learn.

Think Of It This Way

So I finally got things installed and began my learning. It is important to keep in mind just what we are dealing with. Silverlight is a Client side technology. It is hosted in a browser, but is not a web page itself (although it is hosted in a web page). Because it is “living” in the plug-in (which users must install to see your creations) there are no post-backs. Think of it as a Windows program living in a browser. It’s sitting in someones home, on their computer on their network. Makes me teary to think of all my child instances all grown up and in some strangers house. I digress… The application being so far off will be unable to access your database directly and will be limited by the security of the Silverlight plug-in “SandBox”. I thought to myself, well I remember this, Web-Services!! I can do those, but then I think about the problems that Web Services brought me. They only serialize publicly exposed properties (data). I needed an object on the client, and one on the server. It was a pain in the ass honestly. Oh shit I said ass, good thing this is my blog.

Enter WCF

I had forgotten all about the headaches of manually creating a WCF service. I was not looking forward to doing it again, but on the bright side, it did solve my issues of objects on both ends, and it does serialize whole objects. Well, I’m glad I took a look at it again! Its really easy now to create WCF Services! Just right click and add one to a project (I hosted mine in a web project). It makes all of the web.config changes for you now, and it stubs out the interface and service files. Just add your interface and create your method. Works like a champ …. well until you try to hook up your Silverlight client to it. Silverllight sets up your service reference just fine, but it doesnt do crap about the client side config file. Ok, I lied, it does on one condition. The binding can not be wsHttpBinding, but needs to be basicHttpBinding (dont copy paste that, it’s from memory and could be capitalized incorrectly). Once you change the binding just set the reference and it works like a champ!

Enter Entity Framework

I really recommend checking out EF. Again there is a learning curve, but it’s so cool, I could not stop playing with it. I love the way you can access joined data and use the objects right away for your needs. I am not going to go into detail on it, but if you use this approach you can create a database to hold your data, run the EF wizard to get your business objects complete with the ability to query, insert, update and delete data. You can expose WCF services to get and return these business types and consume them in Silverlight (or whatever front end you want).

Enter Exit

To wrap this article up, I can only promise to post my discoveries as I come across them. I will be uploading sample code so you can play around with the tech as well. More to come….