More thoughts on more thoughts on XAML, C# and WPF

Charles questions my statement about WPF data context and WPF-ignorant C# code on his blog.

I stand by my statement wholeheartedly.

Specifically, I rarely derive things from DependencyObject and as far as I've noticed, both XAML and WPF data binding works just fine without it.

XAML just relies on having public settable properties and a no-argument public constructor.  One-way data binding has the same requirements.

Two way data binding works fine if you implement the old pre-WPF INotifyPropertyChanged interface, which is pretty trivial to do.

Here's a simple C# class I just wrote to illustrate this:

public class Author : INotifyPropertyChanged {
  string name;
  bool lovesXaml;

  public
bool LovesXaml
{
    get { return lovesXaml; }
    set { lovesXaml = value; Notify("LovesXaml"); }
  }
  public string Name {
    get { return name; }
    set { name = value; Notify("Name"); }
  }

// boilerplate INotifyPropertyChanged code
  void Notify(string name) {
    if (PropertyChanged != null)
      PropertyChanged(this, new PropertyChangedEventArgs(name));
  }

  public
event PropertyChangedEventHandler PropertyChanged;

}

And here's a trivial WPF/XAML window that uses a DataTemplate to render and edit it:

<Window x:Class='Petzold.Window1'
   xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
   xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
   xmlns:local='clr-namespace:Petzold'

   Title='Petzold'
>
  <ItemsControl
>
       <local:Author Name='Charles Petzold' LovesXaml='true'
/>
       <local:Author Name='Chris Sells' LovesXaml='false'/>
       <local:Author Name='Ian Griffiths' LovesXaml='true'
/>
       <local:Author Name='Chris Anderson' LovesXaml='false'
/>
       <local:Author Name='Adam Nathan' LovesXaml='true'
/>
   </
ItemsControl>

<!-- data templates go here -->
   <
Window.Resources
>
      <
DataTemplate DataType='{x:Type local:Author}'
>
        <
StackPanel
>
          <
StackPanel Orientation='Horizontal'
>
             <
Label>Name:</Label
>
             <
TextBox Text='{Binding Path=Name}'
/>
          </
StackPanel
>
          <CheckBox IsChecked='{Binding LovesXaml}'>Loves XAML</CheckBox
>
        </StackPanel
>
      </
DataTemplate
>
    </
Grid.Resources
>
  </
Grid
>
</
Window>

I can build the Author class in a separate DLL that has ZERO dependencies on anything other than mscorlib.dll and System.dll and it works exceedingly well.

 


Posted May 10 2007, 06:46 PM by don-box

Comments

Jamie Cansdale wrote re: More thoughts on more thoughts on XAML, C# and WPF
on 05-11-2007 1:22 AM
It appears that INotifyPropertyChanged isn't in the Silverlight version of system.dll. It would be a shame if even your simple Author class example doesn't work cross platform.
Kevin wrote re: More thoughts on more thoughts on XAML, C# and WPF
on 05-11-2007 8:06 AM
Yes, I write most of my controls this way as well. It's much faster to write these data bound objects. You can do quite a bit with jujst INotifyPropertyChanged and not creating your own DependencyProperties.
Boris wrote re: More thoughts on more thoughts on XAML, C# and WPF
on 05-11-2007 11:57 AM
Implementing and using DependencyProperty of a DependencyObject instead of INotifyPropertyChanged provides much better performance, because the Databinding engine does not have to use reflection. So, Petzold is still THE KING!
Boris wrote re: More thoughts on more thoughts on XAML, C# and WPF
on 05-12-2007 12:07 AM
Not to mention that you *must* inherit from DependencyObject if you want your class to be the target of databinding
Ray Heath wrote re: More thoughts on more thoughts on XAML, C# and WPF
on 05-12-2007 1:43 PM
Hi Don -

There seem to be two different issues involved (data & presentation) that have somehow gotten blured in this discussion. Here is how they are currently separated in my head:

One may perhaps get skinny objects from somewhere across the wire [1], and wrap them with classes that support richer client-side functionality (i.e. IEditableObject, INotifyPropertyChanged, IDataErrorInfo, etc. [2]).

To make maximize the user experience, compelling presentations are sought (e.g. Petzold/Foundations, Ian Griffiths/WaveData, and Kevin's Bag-O-Tricks [3]).

Sometimes this can be accomplished in XAML (Foundations); sometimes largely by a no-developer using Blend.

Sometimes it requires no/minimal WPF-ims within the C# code (WaveData has one class that implements IValueConverter; another implements INotifyPropertyChanged).

Sometimes you have to dig down deep and get some grease under your fingernails (Kevin's Bag-O-Tricks).

The amount of work required for entry is (as you point out) quite small; but, of course, other things are clearly worth the extra effort.

Best Regards,

Ray Heath
www.rayheath.com


[1] Hopefully this will become truer as LINQ make it easier for entry-/intermediate-level developers to marginalize DataSet

[2] I generally derive these client-side wrappers from a templated class:

public class SupportAlmostEverything<T> : IEditableObject, INotifyPropertyChanged, IDataErrorInfo
{. . . T generally represents the skinny object pulled off the wire and the derived class knows how to convert between itself and the skinny . . .}

You will find these interfaces very well presented in Noyes - Databinding with Windows Forms 2.0, Addison Wesley.

[3]
Foundations - http://msdn.microsoft.com/msdnmag/issues/07/01/Foundations/default.aspx
WaveData - http://www.interact-sw.co.uk/iangblog/2006/11/19/wpfwavedata
Kevin's Bag-O-Tricks - http://wpf.netfx3.com/files/folders/controls/entry7094.aspx
Charlie Calvert's Community Blog wrote Community Convergence XXVII
on 05-14-2007 1:20 AM
Welcome to the 27th Community Convergence. I use this column to keep you informed of events in the C#
Mike Hillberg wrote re: More thoughts on more thoughts on XAML, C# and WPF
on 05-14-2007 11:08 AM
Actually INotifyPropertyChanged isn't even necessary in this example; even without it you get the two-way data binding. INotifyPropertyChanged is necessary if the properties on the Author object change for some reason, e.g. they get set from code-behind.

And Fyi, bindings in WPF can respond to other change notification mechanisms, adapting itself to what the bound source exposes: INotifyCollectionChanged for the case of a collection adding/removing items; similarly IBindingList; and if the source has a custom type descriptor the binding can listen for PropertyDescriptor changes.
dbox wrote 关于XAML,C#和WPF的更多思考的更多思考
on 05-21-2007 9:47 AM
Charles???blog?,???????WPF??????WPF????C#???????????
Anonymous Coward wrote re: More thoughts on more thoughts on XAML, C# and WPF
on 09-10-2007 3:32 PM
This would be improved if compiled...for instance, no closing <Window.Resources> tag, no opening <Grid> tag...

As a newb to C# and ASP.Net, little frictions like this make it harder to grasp the underlying message.
Daniel Cazzulino wrote re: More thoughts on more thoughts on XAML, C# and WPF
on 10-12-2007 10:33 AM
Moreover, you can use a simple custom tool to generate all the plain .NET 2.0 interfaces and events to hook nicely into databinding (Winforms or XAML, so the tool is unfortunately misnamed).

Above the manual approach you showed, the tool will generate a "strong typed" event for each property changed, as well as automatically add the code to raise the specific event. i.e.:

public EventHandler LovesXamlChanged;

bool lovesXaml;

public bool LovesXaml {
get { return lovesXaml; }
set { lovesXaml = value; RaiseLovesXamlChanged(); }
}

So that you don't forget to call the Raise, and also to allow a potential presenter for the view to react to a specific event, instead of doing a potentially big switch over the changed property name as a string. (very nice if you refactor the code)

More info at http://www.clariusconsulting.net/blogs/kzu/archive/2007/09/27/33235.aspx

Add a Comment

(required)  
(optional)
(required)  
Remember Me?