Showing posts with label WPF. Show all posts
Showing posts with label WPF. Show all posts

Monday, 15 October 2007

Microsoft and the Magic sweet spot

As I was coding away on the train today, for a few minutes my mind blanked while watching the landscapes Virgin offer to us regular travelers. The did an amazing job at decorating the length of the track, to the point where you'd nearly get fooled into thinking there are actually villages, cows and other things between London and Manchester. As it happens sometimes, I started thinking about my early days as a fresh and learning developer, many many years ago.

Against the normal academic training some IT people receive, I evolved as a developer from the top down. I didn't do University and got no degree in IT. I actually got as far as studying law. I learnt everything by starting to write HTML web sites back in 95, then started JavaScript in 96 and VB in 97, and discovered JScript.net and C# when I got through a friend an early preview of what was to become .net (NGWS anyone?). And I'll admit that while I understand how x86 works and how pointers work, I am absolutely unable to write a single like of C++ or any other esoteric close to the metal languages (I hope esoteric here is not taken as a challenge of C++ usefulness, as I'm sure the gurus amongst you will have understood). And it's only after all these years of coding that I start understanding calling conventions, Win32, etc.

It all got me thinking about how you understand a language and a platform. Until you reach the thorough knowledge that only years of experience will bring you, you often ignore the why question, preferring the answer to the how: you care about how you achieve a result, with the acceptance that you do not understand why it needs to be done in a specific way.

For example, in JavaScript, you'd add a method to an object type by adding it to its prototype property. You know that instance methods and type methods are two different beasts intuitively, because var $cube = new Cube(); $cube.getValue = function () { return 2; } will not work for another Cube you'd create later on. This empirical knowledge is surface magic for however long you'll take to dig deeper, learn and discover what a prototype is and how it relates to objects. At this stage, if things go wrong you'll probably have to learn more things. And it's an open ended confusing thing because both $cube.getValue and $cube.prototype.getValue can exist.

Another example comes from the WPF world.. Whenever you create a custom library of Controls for WPF, you learn about themes and how styles and templates get applied to your controls. You know that the themes being selected for a control are the end of the line customizations you provide, and you know you have to declare an attribute at the assembly level, and we're still very much in the domain of empirical knowledge. But you also know that the fallback when you don't provide themes is a file in the themes folder called general.xaml. You know the how but the why has no answer. It is a decision the framework designers took, and you have no way of changing it or influencing it in any way. This by design rule is crystal magic. The behavior cannot be changed, and once you learn how to do it, the why question is irrelevant. And if it doesn't work, there's no additional knowledge cost, because you don't need to learn anything else.

My point in all that is that these two magical elements have conflicting developer audiences. More Junior developers (and some senior developers I've worked with in the past), let's call them Mortimer, are happy with crystal magic, because it massively reduces the surface of the API you need to learn. More senior developers that have a will to understand (anyone that uses reflector as his main documentation tool would fall in this category), let's call them Einstein, tolerate surface magic because they can crack the surface, dig deeper and know all the intimate details of how the surface is achieved. They don't necessarily like crystal magic because it just works and they have no control over it, but as it's a closed ending, there's nothing that can be done about it, so they move on.

Everything would be for the best if surface magic worked for Mortimer. APIs like WCF provide a very simple surface magic, with only ServiceContract, OperationContract and DataContract concepts to learn. With the tooling support for WCF services in visual studio, the surface is small enough for most developers to start being productive very quickly. The reality strikes as soon as something unexpected happens: passing too big of an object graph, or worse, a cyclic reference within the DataContracts. Suddenly, Mortimer faces understanding notions such as bindings, behaviors, configuration files, and many other concepts that multiplies exponentially the API surface they need to understand before they can fix a problem. You just designed an API that targets Mortimer when everything works, but that requires Einstein to fix if anything goes wrong.  That said, tooling support is appropriate for being productive, which should ensure WCF adoption, so we're pretty close to the sweet point.

WPF on the other hand has a bit of both. Xaml is easy enough for Mortimer: it's understandable and can be fixed by Mortimer, because most of the bindings between DependencyObject and Xaml follows a crystal magic design. The property store will map Xaml and DependencyProperties based on the name, and nothing you want or can do will change this. You also very much pay as you go when you learn Xaml, because you can start with simple object graphs, and discover attached properties at a later time. You can use them without understanding them, and often you'll be able to fix issues by learning a bit about the Binding syntax. On the other hand, it's a very large platform and requires much more time than Mortimer would spend learning a new technology. Areas like Bindings are complex when they don't work, outputting errors to the debug window is confusing when you don't know where to look, the coexistence of logical and visual trees is difficult to grasp for winforms developers, etc.  Tooling support should help, but from what I see in beta 2, I don't believe the sweet spot will be hit with this version of Visual Studio.

And finally PowerShell is a deliciously efficient crystal magic solution. Things work as expected, pipes and formats work by magic, using a defined behavior that will not change. The framework is static enough that people are confident that the knowledge they learn using the script engine will be valid whichever Commandlet they call. The built-in variables work automatically. $_ will always have the same meaning, $$ too.

What Microsoft doesn't have anymore is a completely crystal magic solution for development. ASP was very much crystal magic, ColdFusion was too, back in the CFML days. Early days VB had few extensibility points which let developers grasp the platform more easily. PHP still has a bit of that feel, just like many other frameworks that limit choice and extensibility to increase the pace at which their developers become experts. When most of your developers know 80%+ of your API, you know you're on the right track. Anything under that and you face a problem: You're segmenting your market between Mortimer and Einstein. Your Mortimer has to get more knowledgeable to survive your technology update, your Einstein will just keep doing his expert job. The low end of the Mortimer market is gone to join the ranks of other easier and simpler technologies.

The sweet spot is not to try and provide one API for everyone, but to provide one crystal magic API for the quick and easy, and a completely different solution for Einstein and upgraded Mortimer.

Getting dynamically typed languages with the DLR is going the right direction. But now, this is a call for action to you Microsoft: Provide us with simple tools with a lot of magic to gain back the people gone to LAMP. Give us a forms design tool that maps any control on a form if the form is named after a table and a control is named after a field in that table. Give us a web tool that simply easy work with no mvc, no presenter, and a simple script language to inject a bit of server side code where it makes sense.

And remember that a crystal magic API is one that you *do not extend*. Not everyone needs a framework.

P.S.: This is just my opinion on why we're loosing so many people to php and other simpler technologies. I have a lot of designer friends that just plain refuse to touch any Microsoft technologies, because PHP is so simple. I'm probably not the target audience for any of this. Any resemblance with current or previous coworkers is purely intentional. No guarantees implied or granted. Do not use in a nuclear facility. Etc.

Technorati Tags: , ,

Sunday, 7 October 2007

WPF Tips'n'Tricks #8: Use your code-behind for binding

In the View-ViewModel-DataModel pattern that has been documented a fair bit for WPF, it is often the case that you want to have a testable class that wraps your data to expose an object model that will make binding from Xaml code easier. However, when writing prototyping or simply answering messages on the Msdn forums, as well as for the code examples on my blog, it's often the case that you want to have a sort-of ViewModel that you want to quickly hack together.

The solution is to simply leverage the code-behind of your window! Let's create a simple property on our window code-behind.

    public partial class MainWindow : Window

    {

        public MainWindow()

        {

            InitializeComponent();

        }

 

 

        public bool IsFlagSet

        {

            get { return (bool)GetValue(_isFlagSetProperty); }

            set { SetValue(_isFlagSetProperty, value); }

        }

        public static readonly DependencyProperty _isFlagSetProperty =

            DependencyProperty.Register("IsFlagSet", typeof(bool), typeof(MainWindow), new FrameworkPropertyMetadata(false));

 

    }

And now in the Xaml code you just need to bind the DataContext property to the class itself.

<Window x:Class="CaffeineIT.Blog.XamlCollections.MainWindow"

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  DataContext="{Binding RelativeSource={RelativeSource Self}}">

    <TextBlock>The flag value is:

        <TextBlock Text="{Binding Path=IsFlagSet}"/>

    </TextBlock>

</Window>

Voila! You can now bind straight to the properties defined on your Window class! But as the complexity of your project increases, you'll want to unit test the ViewModel, and for this you'll have to separate the code in a separate class. The way I choose to do it is to embed the object directly inside the Xaml code. With this approach, you'll have the a ViewModel class. Here I implement it by inheriting from DependencyObject to keep the DP we defined earlier, as it provides support for validate and coerce callbacks, but this is absolutely not necessary. You're more than welcome to implement your property through accessors and INotifyPropertyChanged.

    public class NewWindowViewModel : DependencyObject

    {

        public bool IsFlagSet

        {

            get { return (bool)GetValue(_isFlagSetProperty); }

            set { SetValue(_isFlagSetProperty, value); }

        }

        public static readonly DependencyProperty _isFlagSetProperty =

            DependencyProperty.Register("IsFlagSet", typeof(bool), typeof(NewWindowViewModel), new PropertyMetadata(false));

    }

And now I can declare this object in my Xaml.

<Window x:Class="CaffeineIT.Blog.ViewModel.NewWindow"

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  xmlns:vm="clr-namespace:CaffeineIT.Blog.ViewModel" DataContext="{DynamicResource ViewModel}">

    <Window.Resources>

        <vm:NewWindowViewModel x:Key="ViewModel" />

    </Window.Resources>

    <TextBlock>The flag value is:

        <TextBlock Text="{Binding Path=IsFlagSet}"/>

    </TextBlock>

</Window>

I find the code very tidy. Through this mechanism, you can also bind properties from your view to the ViewModel. Imagine: View updates ViewModel updates View... You can abstract all the logic of your view in your ViewModel in an oh-so-clean way it makes me salivate every time. You can then leverage commands to encapsulate actions that modifies the ViewModel which update the View. No more tier leakage!

Technorati Tags: , , ,

Tuesday, 25 September 2007

WPF Tips'n'Tricks #7: Smooth(er) scrolling

A common request with ListViews and other scrollable components is to have a smoother scrolling. By default, when a scrollable control contains items that control their own scrolling, it jumps from one item to the other, by the whole item height. It's not smooth because it's not animated, a step back in usability that I still cannot explain (lack of time maybe?)

The culprits are mainly the Panels like StackPanel and ScrollContentPresenter that don't implement smooth scrolling animations. While changing their behavior to support smooth animation is a way to solve the issue, and it may well be that I start implementing it for a future Tips'n'Tricks, but for now it's out of scope for this entry.

So how to prevent this jumpy behavior? Don't let the content decide how it's going to scroll! It's very easily accomplished, by adding the ScrollViewer.CanContentScroll attached property and setting it to false. Here's a small example:

<Window 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Smooth Scrolling Demo" Height="300" Width="300">
<Grid>
<ListBox ScrollViewer.CanContentScroll="False">

<ListBox.Items>
<TextBlock Height="40">Text1</TextBlock>
<TextBlock Height="40">Text2</TextBlock>
<TextBlock Height="40">Text3</TextBlock>
<TextBlock Height="40">Text4</TextBlock>
<TextBlock Height="40">Text5</TextBlock>
<TextBlock Height="40">Text6</TextBlock>
<TextBlock Height="40">Text7</TextBlock>
<TextBlock Height="40">Text8</TextBlock>
<TextBlock Height="40">Text9</TextBlock>
<TextBlock Height="40">Text10</TextBlock>
</ListBox.Items>
</ListBox>
</Grid>
</Window>

[Update]
Ronan is absolutely correct in pointing out in my comments:

There's a drawback when using this trick: when ScrollViewer.CanContentScroll is set you loose default scrolling behaviour of the ListBox which uses a VirtualStackPanel. On big collections you will notice a great performance degradation.

This is a complete oversight in this tips'n'tricks. Virtualization means that only visible items within a list will be created and added to the visual tree. Not an issue for a few items, but when you reach the hundreds or thousands, it becomes a necessity. When you set the CanContentScroll property, the virtualizing stack panel stops virtualizing and renders everything. Be aware of that!

And as is also pointed in that comment, making a smooth scrolling *virtualizing* panel is even harder.

Technorati Tags: , ,

Thursday, 30 August 2007

Programming WPF 2nd Edition is out

Well through Chris Sell's blog, http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=2122, the new edition is shipping. I liked the previous version, only real reference at the time I started WPF, together with the Petzold.

So I just placed an order for it, and at the same time ordered Nathan's and the other Chris book, so I can have a go at reading them all.

I'll do a comparison of all of them and report here. It's been done before but now that I've been working professionally for what seems like years but is in fact only a year (between the RTM and beta 2), I think I may see things differently.

It will also be fun to compare the first and the 2nd edition of Programming WPF :)

Question is, should I order the 3D Petzold? We'll see after I'm done with the rest.

Anyone wants to commission me to write "Writing controls for WPF: Put some sparkle in your cider!"?

Technorati Tags: , , , ,

Thursday, 16 August 2007

Xceed DataGrid for WPF v1.2

 We've used the WPF DataGrid successfully on the National Express project, and the guys at Xceed are very prompt to answer questions and very quick to fix bugs we encountered with the first version of their products.

I'm being told it's now top quality and probably the best DataGrid available. And it's just been updated! Check their News Headlines page for the new features.

Technorati Tags: , , , ,

Wednesday, 8 August 2007

On why you shouldn't really subclass through XAML

As I am reviewing some code at the moment, I have been looking for this blog entry from Rob for a while, and just found it again: Building a control which holds content: CustomControl vs. MarkupSubclassing vs. UserControl. Included in my specification references, but posting it so I can reuse it as a reference.

And the ever so useful Neil (when are you getting a blog back?) points me to an article by Kevin on the same subject: Don't subclass a Panel, unless you're making a Panel.

It always amazes me that people, after x years of OOD, still don't see a problem in using inheritance instead of combination / encapsulation.

Then again these guidelines postdate most of the uses I've seen so far so you can't really blame anyone.

Technorati Tags: , , ,

Thursday, 2 August 2007

WPF Tips'n'Tricks #5: Receive notifications for dependency properties

Receiving notifications for dependency property changes on an existing object is a very common scenario. The way to do it properly is not very obvious. So much so that while reviewing some code, I found the following snippet.

// Believe it or not, this seems to be the only way to get change
// notifications for DPs unless you derive from the relevant
// class and override OnPropertyChanged.

PropertyDescriptor prop = TypeDescriptor.GetProperties(obj)["Prop"];
prop.AddValueChanged(obj, delegate { viewModel.RaisePropertyChanged("Prop"); });

There's a few issues with this code. The first one is that you reflect on the CLR property anchoring the dependency property, and not the dependency property itself. For example, the following code wouldn't work.

public Dock Dock { get { return DockPanel.GetDock(this); } }
public void TestDockProperty()
{
    PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this)["Dock"];
    descriptor.AddValueChanged(this, delegate(object sender, EventArgs args) { MessageBox.Show("ValueChanged!"); });

    DockPanel.SetDock(this, Dock.Top);
}

The reason is that the PropertyDescriptor points to the CLR property, not to the dependency property.

The second issue is a problem of performance. TypeDescriptor.GetProperties reflects on every call and doesn't cache the result, so its cost is O(n). Here's the result of iterating several times on the code using TypeDescriptor.

  • 1,000 iterations : 00:00:00.2811402
  • 10,000 iterations : 00:00:01.4369388
  • 100,000 iterations : 00:00:14.1194856

So what is the correct way to do it? Say hi to DependencyTypeDescriptor. Here's the code rewritten to use DependencyProperties.

DependencyPropertyDescriptor prop = DependencyPropertyDescriptor.FromProperty(ParentObject.PropProperty, obj.GetType());
            prop.AddValueChanged(obj, delegate { viewModel.RaisePropertyChanged("Prop"); });

If you execute the code in the small benchmark application we used previously, the results are completely different.

  • 1,000 iterations : 00:00:00.00
  • 10,000 iterations : 00:00:00.00
  • 100,000 iterations : 00:00:00.0312378

As you can see in the source code, I simply use a DateTime before and after the call, and everything runs on the UI thread.

And the source is stored on box.net for those that want a peek. Be aware it's a visual Studio 2008 solution and project.

Download the source.

Monday, 30 July 2007

WPF / Control interop, the blended way...

More of a bookmark for later, but seems Leslie and Jeremiah are doing fancy stuff with win32 controls and getting rid of the Hwnd limitation. Well done!

Edit: Leslie gave the link to the source code in the comments, so here it is. Thanks Leslie! http://www.codeplex.com/WPFWin32Renderer/Release

Technorati Tags: , , , , ,

Friday, 27 July 2007

So there *are* new things for WPF in 3.5

Visual Studio 2008 beta 2 has just been released, and with it an announcement of new features and bug fixes for WPF. And the best bit for me:

Data binding and journaling by URI work together.

For the WPF application we released to National Express with Netstore, this bug hit us very hard, as we designed a whole navigation system based on passing context / data objects around while keeping navigation by URL (memory footprint being the main reason why you want to navigate by URL.) What used to happen was that any Binding associated with a dependency property that supported Journaling would not be re-established. My good friend Neil Mosafi (seems to not have a blog anymore) was the one that found the bug.

Question for Microsoft though, is there going to be a HotFix for the issue? Some applications in the wild would definitely benefit from having a fix, rather than rely on inheriting every control and overriding each journaled dependency property manually.

As I'm writing this entry, my mind wanders and hope that one day WPF applications will work more like the browser, keeping a page as KeepAlive for a known number of pages or memory footprint, and only release a page when the history stack takes up too much memory. Maybe in .net 4 with WPF (which would be wpf 2.0, if 3.5 is WPF 1.5. Interesting arithmetic, WPF = .net - 2).

Oh the thrill. I'll be starting cooking some WPF examples next week as soon as I switch back to booting Vista instead of MacOS X (have a look at VMWare Fusion. Now if they could integrate their Unity feature with the vista DWM, I could get accelerated graphics WPF development in visual studio within macos. Hmmm...)

Technorati Tags: , ,

Friday, 29 June 2007

WPF Attached Events Addendum

Some of you may remember my article on attached events. There's now more clarification from the WPF SDK blog. Considering the extensive email exchange I had with Wolf Schmidt about the topic and its coverage in the SDK, I wouldn't be surprised if he had something to do with that article. An excerpt from our conversation is in order.

Now that I've spent so much time on an email to one individual customer, I think I smell a WPF SDK blog entry coming :-)

The point is, the MSDN people are very accessible and very helpful, and answer with passion and accuracy. And they hang on the WPF forum as well so don't hesitate to drop your questions there.

Technorati Tags: , ,

Service Pack on the way?

A while ago, Rob Relyea mentioned on the forums that they had someone working on community and bugs in the WPF team.

I also remember reading a few days ago a Microsoft blogger talking about a service pack.

And Neil has pointed out that bugs are starting to get closed down on the Connect site.

And now, another proof, in the form of a link list:

Service pack may you come. And if other bugs could be fixed, including the dependency property journaling and persistence counter for user controls, that would be nice Microsoft :)

 

Technorati Tags: , , ,

Wednesday, 27 June 2007

Multiple mice and cursors on WPF applications

For those that want to do WPF development with multiple cursors, Microsoft released a new version of the MultiPoint SDK. 

Download details: Microsoft Windows MultiPoint Software Development Kit (SDK)

Technorati Tags:

Tuesday, 12 June 2007

Validation in WPF with Enterprise Library

A very good news for those that require enterprise

Technorati Tags: , ,

quality validation, there's now a project to integrate WPF validation and Enterprise Library Validation Application Block.