March 08
Rob Relyea asks for feedback on WPF. In response, I've put together some of my top 10 pet grievances. I have to highlight that this list is relatively minor. The structure and modularity of WPF stands out over and above other frameworks... there is a lot of potential here.
- DataTrigger versus Trigger - I've never really understood why these two needed to be modeled differently. A DataTrigger can be used against non DependencyProperties, and a Trigger can be used between different parts of the Visual Tree (usually with DPs). But does that distinction really need to be made to the developer? Why not just call it a Trigger and let the Framework work out the details. What's more annoying is that the properties on the two elements are different. This inconsistency is evident in a few areas of WPF.
- Expressing Inter-object References - the DataTrigger, Trigger, Storyboard, Timeline elements and others all suffer from inconsistent ways of referencing other objects. In WPF you often need to relate one object to another. It could be for Binding, or for animating a property or triggering an action based on a value being set. The problem is that there are different ways to express these relationships in WPF.
Storyboard and DataTriggers use TargetName - the name of the element being manipulated. Binding uses various ways : - including matching on type, name, relative path etc.. The DataContext is a pure and simple reference, through which you can use a resource look-up or set it in code directly. My point is that there should be one way of expressing inter-object references and that's it. Having to name elements is not good, the PropertyPath object is useful and the expressiveness of the Binding element is very good. We need one solution that's the best of all worlds used consistently everywhere.
- Inconsistently Behaved Events - some of the events in WPF do not act in accordance with the CLR guidelines. For example, the LayoutChanged event is fired when any element changes its position in the window. Even if you only hook a textbox 5 levels down the visual tree - where it is never moved - you still receive a LayoutChanged event every time some other element is moved, resized etc. What's worse is that the 'sender' parameter for LayoutChanged is always null. This makes the event next to useless... which leads nicely on to the next problem.
- Storyboard and Timeline completed events - these are hard to manage in some circumstances. The problem with these is that there is no way to link the event invocation back to the object being animated or to the animation object itself. WPF actually clones the Timeline or Storyboard before the animation is started - and there are no properties (that I can see) that will give you access to the object being animated. This makes ad-hoc triggered animations on collections of objects difficult to manage. The solution that I use is to set a generated 'name' on the Timeline and use a Dictionary to look it up in the event handler.
- Panels - I think one thing that would make WPF easier to learn would be to simplify the role of each element. I wish all Panels were called XXXXPanel. I also wish that their role was restricted to laying out elements - and not part of the visual tree. Setting the background color of a Panel just doesn't make sense and blurs its real purpose. I think it's little things like this that make it harder for new users to adopt the technology.
- Custom animations - this is still an area that I haven't spent that much time digging around in - I've only reused other people's hard work. Every time I see somebody hook into the render override to calculate the new animation position (and not use the Dispatcher) it just feels so Win32. Is it not possible to write your own Timeline derived class that would perform custom animation based on the scene contents?
- More transparency - I'm talking about tracing what WPF and MILCore are doing. When a texture needs reloading then it would be nice to see it logged somewhere - with the reason why. Why was a re-render necessary etc... The solution here may be ETW - but I'm not sure we have the tools and a supporting MSDN article.
- Deployment - the story is better now that IE7 is being rolled out. The install still takes too long and is painful for the average XP user. I'm hoping Microsoft will start using their own technology and we will see a wider install base (something more than the now defunct Microsoft Max). What's concerning is what's coming next. With WPF 1.5 being talked about, how much is this going to hurt...? Please no more reboots.
- Mid-life crisis - another concern is memory bloat. The nature of WPF app's makes them prime candidates for mid-life crisis - meaning objects are held long enough to survive past a generation 1 collection, but cleared down and recreated frequently enough for this to become a real problem. Generation 2 collections are bad for some kinds of applications, they are also bad when users check out their process list to see which applications are being greedy with their memory. DataBinding and the way ItemsControls work help this to a certain extent, but would it be better to use a memory pool for all objects rather than newing them straight out of the heap?
- GPU versus CPU - one big plus point with WPF is the utilization of the GPU. This is a big win over the competition. One thing that I don't understand is the lack of GPU acceleration for certain operations. Bitmap effects is one that springs to mind - why isn't a pixel shader used here for hardware that supports it? Is it concern over the driver quality? I would like to see more use of the shader model in the future - particle effects and other GPU features. It makes great eye candy for demos.
- + 1 more - Guidance Needed - what was great about MFC and VB was that there was a set way of doing things. Basically everybody wanted to be like Office or Explorer. It was actually quite hard to be anything else - if you wanted to change the behavior of one of the common controls it could take weeks of effort. We now have the tools to give us much more freedom, but there are only a handful of real-life applications and no new established look and feel. The Web (in some ways) suffered from the same problem - standards were gradually established over time. We need the next 'Microsoft Office' or 'Amazon' or 'CNET' for WPF applications. You can just mimic Win32 - but then why not just use Win32?
Lastly, please fix the MSDN feedback site. It looks like the WPF team have stopped reviewing the feedback. The versions of WPF include the July CTP and Beta 2 - but nothing later! The list of operating systems doesn't even include Vista. Would be nice to submit feedback - especially now that this technology is getting in more developers' hands.
September 03
Here's a few lessons learnt whilst developing WPF usercontrols, custom controls and custom ItemsControls.
Failed to recognize Dependency Property or Attached Property.
Make sure that the static property is defined for on the class it is being used. For a dependency property called 'Custom' with a default value of 1.0:
public static DependencyProperty CustomProperty = DependencyProperty.Register("Custom", typeof(int),
typeof(MyClass), new PropertyMetadata( 0, new PropertyChangedCallback(Callback)));
Also make sure that the class level accessors have been added:
public int Custom
{
get { return (int)GetValue(CustomProperty); }
set { SetValue(CustomProperty,value); }
}
For Attached Properties use RegisterAttached:
public static DependencyProperty CustomProperty = DependencyProperty.RegisterAttached("Custom", typeof(int),
typeof(MyClass), new PropertyMetadata( 0, new PropertyChangedCallback(Callback)));
The public methods :
public static void SetCustom(UIElement element, int value)
{
element.SetValue(CustomProperty, value);
}
public static int GetCustom(UIElement element)
{
return (int)element.GetValue(CustomProperty);
}
Error Loading XAML after adding a Dependency/Attached Property
Check that datatype of the default value. Make sure that it matches the type of the property (1.0 for a double versus 1 - which is an integer).
Implicit Styles not being picked up for the custom control:
When defining a style with a key of the data type of the custom control all the settings are ignored.
First, check that the default resource key has been defined in the custom control. Add the following public static constructor, this indicates that the default style for this control should use the Type object of MyClass :
static MyClass()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyClass),
new FrameworkPropertyMetadata(typeof(MyClass)));
}
Also, do not set the Style property of the custom control in the XAML definition. To apply a default style use a local style definition with a key of the type object.
Your Custom Control is not being created as the item in the ItemsControl
To instruct an ItemsControl derived class to create a specific custom control for databound items you need to override two virtuals:
protected override DependencyObject GetContainerForItemOverride()
{
return new MyClass();
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return (item is MyClass);
}