In the Last Post
Previously, I’ve spoken about about Visual Studio and Expression Blend, styles and templates, and some of the important foundations of XAML-based databinding. In this post, learn about customizing your applications by writing reusable code components that can be linked in declaratively.
Making It Do Your Bidding
To really make your Silverlight application look good, you’re going to need to resort to custom code sometimes. The instinctive thing to do is to wire up event handlers to run at various times to create objects, adjust bounded values, or to start animations. As much as possible though, you should try to avoid this. There is a great setup for creating the necessary components that can then be referenced declaratively.
For example, suppose you want to bind to a Boolean value, but you don’t want to show true/false – instead you want to show on/off. You might be tempted to forgo binding to do this manually, but this would be a mistake. The IValueConverter interface makes it trivial to accept a value and convert it to something else. You can even implement a conversion in the other direction if you need it to work in two-way databinding. Once you create the class, you will actually use it completely declaratively, and hopefully, in a completely reusable way.
As another example, suppose you want to show a message box at some point in your application. You’d probably be tempted to use the Clicked event of the button to show the message in an event handler. Instead, create an instance of the Action class. An Action object just exposes an atomic action that doesn’t need to return anything – in this case, it just shows the message box when invoked. Great for simple actions that are reusable. Once created, you can drag them onto elements in your application, then choose the trigger that should start them (click, close, etc)
Speaking of triggers, if you want to trigger based on something not defined in Silverlight, you can do that too by creating your own Trigger class. You can monitor anything – events on elements, messaging queues, system activity – whatever you need. When you detect your event, you do whatever you want to do (log it maybe?) and invoke any bound activities/actions.
Finally, there will be times that you want to create actions that affect elements, such as cool bouncing effects, or a realistic drifting motion. Such actions are called Behaviors. Wire up what should happen when an object is attached or detached to your behavior, then what to do when you are triggered. It all happens declaratively and encourages maximum reuse.
Summing it Up
The world of XAML is a great place to be right now. Much of this post applies to both WPF and Silverlight. For games, utilities, or line of business applications, you can do a lot with much less code possible than Windows Forms. The graphic effects are amazing and so simple to take advantage of. Don’t avoid it because you heard it was just like Flash except by Microsoft. It’s much more, and being able to work completely from managed code is definitely the icing on the cake!
Resource: Get started by taking advantage of the tutorial videos available by Microsoft.
In Case You’ve Just Tuned In…
In my previous post, I talked about Visual Studio vs. Expression Blend, styles, and templates. In this post I’ll talk about databinding.
The Ties That Bind
As with WPF, databinding is an incredibly powerful feature of Silverlight. The ability to declare a relationship between properties of an element and the properties of an object is amazing. You can bind the properties of Silverlight controls to any CLR object’s public properties, but it will be a one-time binding only. Ideally, you’d probably like it if a Label would update when its associated property changes. In order to get dynamic binding, you need to be able to alert the controls when the value changes. Fortunately, you can do this without even tying your object to Silverlight itself.
Enter the System.ComponentModel.INotifyPropertyChanged interface. This interface signals to consumers that this object raises the NotifyPropertyChanged event whenever a public property’s value changes. This event simply references the sender (the object itself) and a strong representation of the property name. In every property’s setter method you can raise the event. WPF will automatically subscribe to any objects that implement this interface. It will bind to an object without the interface – it will just be one-time.
If you have a collection of objects, you may want elements like ListBoxes or ComboBoxes to reflect changes to the collection’s elements. For this purpose, use the ObservableCollection class as the base. This is like using the List class, but it automatically raises events for added and removed elements. Coupled with INotifyPropertyChanged, your UI can be completely responsive to object changes.
You will also hear about Dependency Properties. These are a special type of property that are used for UI elements. In this case, properties are accompanied by DependencyProperty objects that can be passed around to refer to a property without using reflection. These property values are potentially dependent on the values of other objects, such as size which can be affected by scaling, rotation, and layout. This is a somewhat more advanced topic to understand, although implementing them is pretty straight-forward.
Taking it in Context
Once you have an object or collection for binding, you don’t actually need to explicitly bind that object to every field. For example, if you have fields for name, address, and city, you’ll need to set a binding for each to the Name property, Address property, and City property, but the question of the source object is settled by using the DataContext property of a parent. Data context works as a hierarchy. When an element is bound to a field name, like Address, it has no idea of where it will find that data except to check its DataContext. If no object is set there, it will check the context of its containing object, and so on up the chain. This makes for a very powerful arrangement that makes it easy to move UI elements around or even pull them out to a new user control with minimal rework.
To Be Continued
In my next post, I’ll talk about how you can write code to perform special tasks, while keeping your code-behind work to a minimum…
I recently gave a talk for the Corvallis .NET User’s Group (CDNUG) about using Silverlight as a developer. Silverlight is pitched as a Flash-replacer, a video streaming enabler, and a designer’s dream, but it doesn’t get much love for business applications or more general use. This isn’t actually fair, as Silverlight has amazing databinding and custom presentation features just like it’s older brother WPF.
Tooling Around
The first challenge to developers with Silverlight is the tooling. We devs are used to our environment being a certain way. Visual Studio, SQL Server Management Studio, and other similar applications use an MDI layout that makes sense to us. Expression Blend (the tool of choice for Silverlight/WPF design) is almost totally alien!
Comparison of Blend and Visual Studio
It’s not just the dominant darkness of the theme either! The control toolbox, properties, resources, and other features are just not intuitive to someone with several years of Visual Studio experience.
I Do Declare!
Another big difference to understand isn’t unique to Silverlight, but rather is an attribute of XAML-based declarative programming in Silverlight and WPF. While all UI elements are based on classes, just like in Windows Form applications, the declarative model opens up a whole different way to modify controls. You can set properties of a control, and you can sub-class a control, but the preferred method is to use styles and templates.
Styles are an interesting way of setting properties of objects independent of the objects themselves. You could think of it as a collection of property names and values, and then applying that collection to an object using reflection. It’s more slick than that of course though! Once a template is created, you can apply it to any instance of a given type of control, similar to theming.
Templates refer to the actual composition of a control. From Windows Form programming, we think of a TextBox as a root-level element. In XAML though, everything is a composite control. A TextBox is a collection of rectangles and a content presenter. Some elements are shown or hidden based on focus, disabling, or other states. Modifying the template means declaratively adding or removing elements. This could be to add a magnifying glass to a search text box or to change a button from rectangular to circular.
Default Silverlight Button template
To Be Continued…
In my next post, I’ll talk about data binding in Silverlight…
I’m in the middle of a fairly large sized project right now and as a team we’ve elected to use LINQ to SQL across the board. LINQ to SQL (L2S) is great to work with. The class generation using the DBML file is easy to use and creates objects that are pretty much identical to what I’d create myself for business objects. I can change properties of an object, or create a new object attached to a table collection, and then when I submit the changes it magically gets sent to the database. It’s really great to work with. At least when you can use ad-hoc queries…
The problem is that in this situation, we aren’t able to send *any* queries to the database. Permissions for reading and writing data are denied – all we can do is call stored procedures. Of course we can do anything that we need with these stored procedures, but this causes headaches with the L2S objects.
If you do some reading, you’ll learn that L2S fully supports stored procedures. It’s not all that uncommon for table writes to be restricted, so you can set Create, Update, and Delete stored procedures for every table. You can also associate arbitrary stored procedures that look become methods on the DataContext.
All of this allows you to use standard L2S syntax for modifying object properties and submitting the changes, or calling Remove() on an object in a collection to delete the underlying row. Unfortunately, all Select operations still result in queries being generated. Even things as simple as getting a count send a “Select count(*)…” query to the server. As I said, we can’t send queries of any type, so this has become a real challenge.
There are so many places where queries get sent. Even if you use a stored procedure to get an object (i.e. a manager), it will issue a select query to get associated objects (i.e. manager’s direct reports). The query itself is great! Really, it does a wonderful job of this, but I have to wonder why this is the only way it can work.
There is no concept of a default Select operation. In my mind, if I could specify a get-by-id stored procedure for every table, much of the problem would be gone. Whether I need a single record myself, or associated queries for foreign key relationships, if L2S knew how to get a record by its ID using a stored procedure we’d be in great shape.
Unfortunately, this isn’t possible right now. I don’t know if it’s even on the horizon, but for now it’s a very tedious procedure to make sure that you don’t use LINQ much at all, except on cached query executions from the stored procedures (using ToList() on the results). This takes out much of the benefit of L2S since you are forced to think it through so much.
To make it worse, sometimes you can’t even tell that it’s using queries unless you log all queries or use SQL Profiler. What would be great is if you could tell it to use no dynamic queries (EnableDynamicQueries = false). Then if the query generator senses a need to do so to satisfy an expression tree it could throw an exception. Clearly, complex searches are more complicated and possibly couldn’t be done by dynamically determining the stored procedure to use, but as it is now you are forced to use the stored procedure methods explicitly. To make all of this worse, using these methods causes you to lose the benefits of object tracking. This means that subsequent queries from the same DataContext result in cached objects. Clearly not ideal!
I’ll be at the MVP Summit in February and I’m hoping to meet up with some of the LINQ people. Nothing new to them I’m sure, but worth bringing up anyway!
Please read my recent post about creating successful sample/demonstration code at: http://aeshen.com/wordpress/?p=261
Please read my recent post about building communities around products and technologies at: http://aeshen.com/wordpress/?p=246
Please read my recent second blog post about LINQ to SQL at: http://aeshen.com/wordpress/?p=245
Please read my recent blog post about using LINQ to SQL at: http://aeshen.com/wordpress/?p=237