|
First, I just want to say that when I first encountered WPF and saw the data binding syntax, I was thrilled beyond belief. Anybody who has ever done data binding in VB6, Delphi, or half a dozen other languages knows that while it typically makes for a pretty fantastic "hello world" demo, it doesn't work at all in a practical, real-world scenario under real-world load and stress from real users. Many data binding implementations don't scale, many violate separation of concerns, and many just plain suck.
The meat of it is that in WPF, I can use powerful binding expressions to tell UI elements (represented by XAML elements) that I want them bound, how I want them bound, and to what I want them bound. For example, to set the text of a text block to a property on an object instance named 'myData', I might write:
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" x:Name="_userNameBlock"
Text="{Binding Path=UserName, Source={StaticResource ModelRoot}}"
VerticalAlignment="Center"/>
Couple of really cool things going on here. The bulk of the coolness is the fact that I am binding to a model object, not to something in my controller or to something somewhere else that makes my design suck. Secondly, this binding is two-way. Assuming the UserName property is defined as shown below, the GUI will be notified anytime it changes:
public string UserName { get { return _userName; } set {
if (_userName != value)
{
_userName = value;
NotifyChanged("UserName");
}
}Basically what this is doing is calling a private helper method that fires off the PropertyChanged event handler (required by classes that implement INotifyPropertyChanged, which is how the WPF GUI is informed of value changes). If I want to customize the way the bound value appears, I can create a type of class called a "Value Converter". This lets me do things like render an image on screen when the data is an integer index into a list of images, etc.
Now for Cocoa!
I was actually pretty shocked by what felt like similar power levels in the binding capabilities of both systems. Both WPF and Cocoa let you bind to model objects in two-way fashion. One difference I found is that you (can) do the binding for Cocoa within Interface Builder - which means you don't see any of the code or XAML or anything else - you just set the bindings directly in IB. Of course, you can use VS 2005's designer to create bindings, but its often slower than just typing the binding syntax in manually.
Another thing I liked is that support for value transformations is built directly into the system. Also, one thing that I freaking loved was the fact that I could bind to the sum of all prices in an array of ledger rows, or the count of rows, or the average price - all directly within IB without having to create a container class in my model that has calculated dynamic properties. In order to get this kind of functionality in WPF, that's what I typically do - create a container that has properties that do the simple calculations (sum, avg, min, max, count, etc) on the contained array/collection/etc.
With Cocoa, I can bind a text field to an array controller called Ledger, set the controller key to arrangedObjects (this is essentially the list of items contained in the array controller, which is similar to WPF/WinForms controls that maintain currency within a collection..though WPF often keeps the existence of such constructs hidden from you) and then I set the model key path to @count. This is where it gets even cooler, I can set the display pattern to "You have %{value1}@ transactions in the ledger." How cool is that?? The binding itself also has placeholders for when no value exists, for when nothing is selected, or even for when the value is not applicable or null. And finally, if I really need to I can write a method that transforms the value from its raw form to some other form.
Oh! This one fact made me giggle with glee: I don't need to manually fire events to notify the GUI of changes made to my model!!! With Cocoa, when you set up a binding, it automatically rigs up a key-value observer that then automatically takes care of GUI updates when the underlying values change. This way, I can remove the "clutter" in the property definition (see the UserName property above) and just include model data! This behavior is configurable, and even works with Obj-C 2.0's new property syntax, but by default you get a lot of functionality for free.
I can easily create parent/child views by mixing array controllers by binding one to arrangedObjects and one to selection (controller keys). Obviously I'm not an expert on this yet, but suffice it to say I was extremely pleased with Cocoa bindings.
So - which one is better? I can't say. Cocoa bindings are as powerful as they are through the miracle of Key-value-Coding and Key-Value-Observing while WPF's data bindings are as powerful as they are through the power of the XAML object instantiation language. They both do their jobs extremely well. If I was writing an application for Vista/XP, I would do it in WPF using WPF bindings. If I am writing an app in Cocoa, I'll use Cocoa bindings. I am pleased to find out that binding is one area in which Cocoa does not fall short like so many languages/environments have before it.
Interesting. I guess we are seeing some of the trade-off decisions made by
the Cocoa team and the WPF team. It seems that the WPF team's implmentation
allows the engineer to have ultimate control (good or bad). Whereas the
Cocoa team chose robust simplicity.
You can create your own custom view objects, etc. and have those added to
the object pallet in Interface Builder. This includes exposing bindings.
Interface Builder 3.0 which will come out with Mac OS X 10.5 takes this
capability even farther.
You can kind of customize Cocoa bindings as shown here
http://ltconsult.com.au/blog/?p=10
Todd - my colleagues and I have had this discussion multiple times. It
seems as though Microsoft's goal when implementing a framework is to
provide you with a ridiculous amount of control, power, and flexibility.
That amount of power often results in a lot of complexity, and the need to
write abstraction layers to simplify the most commonly performed tasks.
Well, you can design your own custom Cocoa controls. Just have a look at
iLifeControls or mmalc's CocoaExamples.
Kevin - Well said. As a framework designer myself, this is the type of
thing I struggle with most often. As I step back and look at my own past
decisions, I more often then not choose the Apple approach. In addition,
your comments can also be elevated and made analogous to the entire Apple
vs PC approach to computes. PC's are an open and infinitely configurable
machine, where as Apple's Macs are mostly closed and one can only configure
a handful of piece-parts. Interesting.