TechDays 2011: Rx talk, slides and source code

Rx, Silverlight, Windows Phone, WPF 3 Comments »

As promised, here is a blog post which shares source code and slides for the Rx talk I gave during last TechDays in Paris. I animated this session with my co-worker Charlotte and with Mitsu.

Download slides here.
Download source code here.

Demo1: Drag’n'drop in a WPF application

The goal was to implement a basic drag’n'drop functionality in a WPF application. The Rx query looks like the following:

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
var query = from mouseDown in this.image.GetMouseLeftButtonDownObservable()
            let downPosition = mouseDown.EventArgs.GetPosition(this)
            let rect = new Rect(downPosition.X - 10, downPosition.Y - 10, 20, 20)
            let delta = mouseDown.EventArgs.GetPosition(this.image)
            from mouseMove in this.GetMouseMoveObservable()
                .Select(ea => ea.EventArgs.GetPosition(this))
                .SkipWhile(p => rect.Contains(p))
                .DoOnce(p => this.onMouseEnter.Begin(this.image))
                .Select(p => p.Offset(delta))
                .TakeUntil(this.GetMouseLeftButtonUpObservable())
                .Finally(() => this.onMouseLeave.Begin(this.image))
            select mouseMove;
 
query.Subscribe(p => this.image.SetPosition(p));



Demo2: online Twitter search and Bing map geolocalization

This time, the goal was to query Twitter asynchronously and to geolocalize the associated Tweets. The Rx query:

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
this.textbox.GetTextChangedObservable()
    .DistinctUntilChanged((ea) => this.textbox.Text)
    .Throttle(TimeSpan.FromMilliseconds(300))
    .ObserveOnDispatcher()
    .Do(ea => this.ShowLoadingIndicator())
    .Select(ea => TweeterHelper.Search(this.textbox.Text))
    .Switch()
    .ObserveOn(Scheduler.Dispatcher)
    .Select(page => TweeterHelper.ParseTwitterSearch(page))
    .Subscribe((tweets) =>
                    {
                        this.HideLoadingIndicator();
                        this.listbox.ItemsSource = tweets;
 
                        TweeterHelper.LocalizeTweets(this.map, tweets);
                    });



Demo3: using the accelerometer in a Windows Phone 7 application

The last demo was about the usage of the accelerometer in a Windows Phone 7 application. Here is the relevant Rx query:

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
private void MoveEllipse(IObservable<Acceleration> accelerationObservable)
{
    accelerationObservable
        .SlidingBuffer(2)
        .Select(accCouple => new Acceleration(accCouple.First(), accCouple.Last()))
        .ObserveOnDispatcher()
        .Do(acc => this.textBlock.Text = acc.ToString())
        .Scan(new Point(x0, y0), (point, acc) => point.Move(acc).ClipTo(horizontalInterval, verticaInterval))
        .Subscribe(p => this.ellipse.SetCenter(p));
}

Doing this session was a really great experience ! I’d like to thank Charlotte and Mitsu for doing it with me. Also, I’d like to thank all users who came to the presentation !

TechDays 2011: Rx talk in Paris

Rx, Silverlight, Windows Phone, WPF 3 Comments »

During the next 3 days, the “Palais des Congrès” in Paris will hosting the TechDays 2011. For the very first time, I’ll have the chance to be part of it as a speaker for a talk about Rx (Reactive Extensions).

The session will take place in room 241, tomorrow Thursday 8, from 1pm to 2pm. Here is the link to the session’s description (in French).

I’ll share presentation slides and source code by the end of the week :-)

MVVM Framework Explorer update and top MVVM Frameworks

Silverlight, Windows Phone, WPF 2 Comments »

A couple of days ago I received an email from Geert van Horrik, a developer working on a new MVVM Framework called Catel. Geert asked me to update my MVVM Framework Explorer app in order to include his new framework. Here is the resulting updated app (click to launch):

Besides adding this new framework, I updated the download count for each framework, which allowed me to do some statistics. Here are the download progression for the most popular MVVM frameworks between July 2010 and January 2011:

Framework July 2010 January 2011 Progression
Calcium 7486 9963 33%
Caliburn 27012 36392 35%
Cinch 9865 15206 54%
CoreMVVM 3373 4419 31%
MEFedMVVM 905 2074 129%
MVVM Foundation 5759 7656 33%
MVVM Helpers 674 1571 133%
MVVM Light 11601 30111 160%
NitoMVVM 446 1098 146%
nRoute 7638 13724 80%
Onyx 2027 2195 8%
WAF 12255 30673 150%

Top progression during the last 6 months:

  1. MVVM Light (by Laurent Bugnion): +160%
  2. MVVM Helpers (by Mark Smith): +133%
  3. MEFedMVVM (by Marlon Grech): +129%
  4. WAF (by Jurgen Berchtel): +150%

Top downloaded frameworks:

  1. Caliburn (by Rob Eisenberg): +36 000 downloads
  2. MVVM Light (by Laurent Bugnion): +30 000 downloads
  3. WAF (by Jurgen Berchtel): +30 000 downloads

Congratulations to their respective authors.

Calcium 7486 9963 33%
Caliburn 27012 36392 35%
Cinch 9865 15206 54%
CoreMVVM 3373 4419 31%
MEFedMVVM 905 2074 129%
MVVM Foundation 5759 7656 33%
MVVM Helpers 674 1571 133%
MVVM Light 11601 30111 160%
NitoMVVM 446 1098 146%
nRoute 7638 13724 80%
Onyx 2027 2195 8%
WAF 12255 30673 150%

Set up the main window of your WPF project

WPF 1 Comment »

Intro: In this post, I’m exploring various techniques we can use in order to have a custom Window in a WPF project.

Today you start a new application. You open Visual Studio, “File”, “New”, “Project”, “WPF Application” and you start typing code… At some point, you might want to tune the main window of your application in order to have a custom header. The most common reason to do so is when you want to render some UI elements outside the standard client area of a window:

For example in order to have something similar to Office 2010 (with icons inside the Window’s header):

Also, you want to make sure you application works also great on Windows XP. This is probably not your personal choice but some guy from the marketing told you: it MUST runs on XP :-)

Let see what are the various options you can choose

Option1: use the WindowStyle = None option on the “standard” WPF Window

  • How to do?

In the XAML (or in the C# code), simply set the value of the WindowStyle property of your Window to None:

1
2
3
4
5
6
7
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" 
        Height="300" Width="250"  
        WindowStyle="None" 
        WindowStartupLocation="CenterScreen">
  • How does it look on Window XP ?

  • How does it look on Windows 7 ?

  • Advantages

- Same solution for Windows XP and Windows 7.

- The client area now occupies the whole Window. We are then able to render elements at the top of the Window in order to re-create the standard window header.

- Very simple to use (minimal changes in your code).

  • Drawbacks

- A lot of work is needed to create the actual header: show the title of the Window, its context menu and the standard window buttons (Minimize, Restore, Close)

- Several problems appears when the Window gets maximized:

The Window occupies the whole screen and hide Windows’s taskbar. You need some interop code to change the MaxHeight/MaxWidth of the Window. You can see this post for more details: Maximizing window (with WindowStyle=None) considering Taskbar

Even though you fix the previous problem, the border of the window is still visible when it gets maximized:

Option2: use Option1 + ResizeMode =NoResize in order to remove the remaining border

You can easily fix the previous problem by registering an event handler on the StateChanged event of the Window. In the event handler, you can set ResizeMode to NoResize (when the Window is maximized) so that the remaining border disappear.

  • How to do?

In the constructor of the Window, you can add the following code:

?View Code CSHARP
1
2
3
4
5
6
7
this.StateChanged += (s, e) =>
{
    if (this.WindowState == WindowState.Maximized)
        this.ResizeMode = ResizeMode.NoResize;
    else
        this.ResizeMode = ResizeMode.CanResize;
};
  • How does it look on Window XP ?

  • How does it look on Windows 7 ?

  • Advantages

- Same solution for Windows XP and Windows 7.

- You fixed the previous issue easily.

  • Drawbacks

- No special drawbacks.

Option3: use Option2 + AllowTransparency = True

By using Option1 or Option2, you can have a much bigger client area than with a traditional Window. However, you still miss the glass effect or Aero. You might try to get this effect by adding transparency to your Window. The way to do so in WPF, is simply to set the value of the AllowTransparency property to true. Note that enabling transparency on the Window imply setting WindowStyle to None.

  • How to do?

You can use the following XAML code:

1
2
3
4
5
6
7
<Window x:Class="WpfApplication_Option3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" 
        WindowStyle="None" 
        AllowsTransparency="True" 
        Background="Transparent">
  • How does it look on Window XP ?

  • How does it look on Windows 7 ?

  • Advantages

- Minimal changes in your existing code

  • Drawbacks

- On Windows 7, you’ll have to do some serious work in order to have the DWM Blur effect (you might need to combine some shaders effects…)

- On Windows 7, you lost the drop shadow of your Window

- You might get into performance issues by turning on this option.

For more details, you can check out this MSDN blog post “Transparent Windows in WPF“:

“The performance of WPF’s transparent windows is a topic of much concern.  WPF is designed to render via DirectX.  We do offer a software rendering fallback, but that is intended to provide a full-featured fallback, not for high performance.  The layered window APIs, on the other hand, take a GDI HDC parameter.  This causes different issues for XP and Vista.

Experience suggests that a full-screen constantly updating layered window on good XP machine can consume as little as 3% CPU in overhead.

Experience suggests that a full-screen constantly updating layered window on good Vista machine can consume as much as 30% CPU in overhead.”

Option4: use interop achieve the same effect as Option2 but without having to set AllowTransparency to true

As we just saw, using adding transparency to a WPF window by using the AllowTransparency property does not look the good way to go. In this last section, we’re going to see another way using Windows native APIs.

The APIs we’re interested in are in the DwmApi.dll library. Here is the associated MSDN documentation:

DwmExtendFrameIntoClientArea s the DWM function that extends the frame into the client area. It takes two parameters; a window handle and a MARGINS structure. MARGINS is used to tell the DWM how much extra the frame should be extended into the client area.

To use the DwmExtendFrameIntoClientArea function, a window handle must be obtained. In WPF, the window handle can be obtained from the Handle property of an HwndSource. In the following example, the frame is extended into the client area on the Loaded event of the window.

Using this API, you can achieve this kind of effect without having to use the AllowTransparency (on Vista or 7 only of course):

On Windows XP, you don’t have DWM and then you’ll not be able to have the glass effect. However, you can still extend the client area of your Window using some other Windows native API.

The easiest way to do all this work is to use the WPF Shell Integration Library, available on CodePlex:

The custom chrome feature allows applications control over the outer frame of the window so that WPF content can be drawn over the title bar. This allows applications to integrate with Aero glass to emulate the Office 2007/2010 look and feel, or to completely replace the frame with its own content without having to manage all the system behaviors that get lost when using WindowStyle.None.

This project also contains Windows 7 taskbar features (those features are now directly integrated in the .Net framework 4.0).

  • How to do ?

You have to setup 2 distinct styles for Windows 7 and Windows XP. You can tweak them but here is the general organization of those styles:

On Windows XP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<Style x:Key="GradientStyle" TargetType="{x:Type local:SelectableChromeWindow}">
    <Setter Property="shell:WindowChrome.WindowChrome">
    <Setter.Value>
        <shell:WindowChrome
        ResizeBorderThickness="6"
        CaptionHeight="40"
        CornerRadius="6,0,6,20"
        GlassFrameThickness="0"/>
    </Setter.Value>
    </Setter>
    <Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:SelectableChromeWindow}">
        <Grid>
            <Border BorderThickness="6" BorderBrush="#3b5998">
            <Border.Background>
                <LinearGradientBrush StartPoint="0,0" EndPoint="0,50" MappingMode="Absolute">
                <GradientStop Offset="0" Color="#8b9dc3"/>
                <GradientStop Offset="1" Color="#3b5998"/>
                </LinearGradientBrush>
            </Border.Background>
            <ContentPresenter Margin="6,26,6,6" Content="{TemplateBinding Content}"/>
            </Border>
            <Button shell:WindowChrome.IsHitTestVisibleInChrome="True"
                VerticalAlignment="Top" 
                HorizontalAlignment="Left" 
                Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(shell:WindowChrome.WindowChrome).ResizeBorderThickness}" 
                Padding="10">
            <Image Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Icon}" Width="32" Height="32"/>
            </Button>
 
            <Button shell:WindowChrome.IsHitTestVisibleInChrome="True"
                VerticalAlignment="Top" 
                HorizontalAlignment="Right"
                Margin="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=WindowCaptionButtonsLocation, Converter={StaticResource CaptionButtonMarginConverter}}"
                Width="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=WindowCaptionButtonsLocation.Width}"
                Height="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=WindowCaptionButtonsLocation.Height}"
                Command="{x:Static shell:SystemCommands.CloseWindowCommand}"
                CommandParameter="{Binding ElementName=ThisWindow}">
            <Bold shell:WindowChrome.IsHitTestVisibleInChrome="False">XXX</Bold>
            </Button>
        </Grid>
        </ControlTemplate>
    </Setter.Value>
    </Setter>
</Style>

As you can see, on Windows XP, you have to create the minimize/restore/close buttons yourself.

On Windows 7:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<Style x:Key="GlassStyle" TargetType="{x:Type local:SelectableChromeWindow}">
    <Setter Property="shell:WindowChrome.WindowChrome">
    <Setter.Value>
        <shell:WindowChrome GlassFrameThickness="-1" />
    </Setter.Value>
    </Setter>
    <Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:SelectableChromeWindow}">
        <Grid>
            <ContentPresenter
                Margin="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=WindowNonClientFrameThickness}" Content="{TemplateBinding Content}"/>
            <Button shell:WindowChrome.IsHitTestVisibleInChrome="True"
                VerticalAlignment="Top" 
                HorizontalAlignment="Left" 
                Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(shell:WindowChrome.WindowChrome).ResizeBorderThickness}" 
                Padding="8">
            <Image Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Icon}" Width="32" Height="32"/>
            </Button>
        </Grid>
        </ControlTemplate>
    </Setter.Value>
    </Setter>
</Style>
  • How does it look on Window XP ?

  • How does it look on Windows 7 ?

  • Advantages

- No performance issue since AllowTransparency is not used

- On Windows 7 the header looks like standard OS windows

  • Drawbacks

- You have 2 distinct solutions for Windows XP and Windows 7. On Windows XP, you have to add the Window’s buttons manually (reduce, maximize, close)

- You must rely on a new assembly Microsoft.Windows.Shell. However, if you don’t want to, you can import the source code in your project: the features are dispatched in two .cs files and released by Microsoft under the MS-PL License.

Conclusion

In any WPF application, the Windows frame itself matters. If you want to render graphical elements outside the client area, you must be careful. You basically have 2 options:

- stick to managed code only and use the AllowTransparency property. However, you must be aware of potential performance issues. Also, you’ll need to do a lot of work on your own.

- use Window native APIs. You’ll have to distinguish Windows OS which have DWM (Vista and 7) and XP. You’ll have optimal performance. The easiest way to do is to use the Shell Integration library project.

Interesting Links

A WPF behavior to improve grouping in your ListBox

WPF No Comments »

A couple of weeks ago I started prototyping with a friend a behavior in order to improve the grouping in the ListBox control. Today, I’m finally taking time to write a post about this adventure :-)

My overall goal was to have the group headers always visible and smoothly moving while the content of the control was scrolled. Here is a video showing the demo application running:

Get the Flash Player to see this content.

Download the code (VS2010 required)

Of course I wanted to have the cleanest implementation possible, and as I think you already know, this where the WPF behavior comes to the rescue ! Let’s see how this is possible.

Note:

  • You must be aware that enabling group in your ListBox will disable UI virtualization. This might not be a problem if the databound collections is small (<100/200) but if the collection is very large, you might get into performance problem. However this limitation might be fixed in the next release of WPF (see my post about it here).
  • This solution is not 100% compatible with keyboard selection and should be improved to work properly.

Anatomy of a ListBox when grouping is enabled

In order to create this behavior, I had to carefully look the Visual Tree of a ListBox when grouping is enabled. I used Snoop to do so, and I was able to get the following picture:

As you can see, for each group, we have a GroupItem control. However, we cannot direcly apply a transform to this element because it both contains the header (in a ContentPresenter) and the items in the group (in an ItemsPresenter).

Introducing the OverlayGroupingBehavior

The behavior actually walks in the visual tree to find out the interesting part. In our case, we want to attach a TranslateTransform to the headers of each GroupItem. Then, using simple mathematics, we can figure out the needed Y-translation to move the header at the top position of the ListBox.

Here are some details about the behavior:

  • the class inherits Behavior<ListBox>
  • we override the OnAttached method, and in this method we register an event handler for the LayoutUpdated of the associated ListBox
  • in the LayoutUpdated handler, we update the transforms
?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;
using DemoAnimatedGroup.Helpers;
 
namespace DemoAnimatedGroup.Behaviors
{
    public class OverlayGroupingBehavior : Behavior<ListBox>
    {
        protected override void OnAttached()
        {
            this.AssociatedObject.LayoutUpdated += new EventHandler(this.OnLayoutUpdated);
        }
 
        private void OnLayoutUpdated(object sender, EventArgs e)
        {
            ListBoxItem topListBoxItem1;
            GroupItem topGroupItem1, topGroupItem2;
            ContentPresenter topPresenter1, topPresenter2 = null;
            double topOffset1, topOffset2 = -1;
 
            // find the first ListBoxItem which is at the top of the control
            topListBoxItem1 = this.GetItemAtMinimumYOffset<ListBoxItem>();
            if (topListBoxItem1 == null)
                return;
 
            // get all group items order by their distance to the top
            var groupItems = TreeHelper.FindVisualChildren<GroupItem>(this.AssociatedObject)
                                       .OrderBy(this.GetYOffset)
                                       .ToList();
 
            // from the GroupItem, find the ContentPresenter on which we can apply the transform
            topGroupItem1 = TreeHelper.FindVisualAncestor<GroupItem>(topListBoxItem1);
            topPresenter1 = TreeHelper.FindVisualChild<ContentPresenter>(topGroupItem1);
            topOffset1 = this.GetYOffset(topPresenter1);
 
            // try to find the next GroupItem and its presenter
            var index = groupItems.IndexOf(topGroupItem1);
            if (index + 1 < groupItems.Count)
            {
                topGroupItem2 = groupItems.ElementAt(index + 1);
                topPresenter2 = TreeHelper.FindVisualChild<ContentPresenter>(topGroupItem2);
                topOffset2 = this.GetYOffset(topPresenter2);            
            }
 
            // update transforms
            if (topOffset2 < 0 || topOffset2 > topPresenter1.ActualHeight)
                this.SetGroupItemOffset(topPresenter1, topOffset1); 
 
            if(topPresenter2 != null)
                topPresenter2.RenderTransform = null;
        }
 
        private T GetItemAtMinimumYOffset<T>() where T : UIElement
        {
            var minOffset = double.MaxValue;
            T topItem = null;
            foreach (var item in TreeHelper.FindVisualChildren<T>(this.AssociatedObject))
            {
                var offset = this.GetYOffset(item);
                if (Math.Abs(offset) <= Math.Abs(minOffset))
                {
                    minOffset = offset;
                    topItem = item;
                }
            }
 
            return topItem;
        }
 
        private void SetGroupItemOffset(ContentPresenter groupHeader, double offset)
        {
            if (groupHeader.RenderTransform as TranslateTransform == null)
                groupHeader.RenderTransform = new TranslateTransform();
 
            ((TranslateTransform)groupHeader.RenderTransform).Y -= offset;
        }
 
        private double GetYOffset(UIElement uiElement)
        {
            var transform = (MatrixTransform) uiElement.TransformToVisual(this.AssociatedObject);
            return transform.Matrix.OffsetY;
        }
    }
}

Using the behavior

It’s more than easy to enable this functionality in any existing app. In the XAML, all you have to do is to attach the behavior to the targeted ListBox:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<ListBox ItemsSource="{Binding Cities}">
    <i:Interaction.Behaviors>
        <Behaviors:OverlayGroupingBehavior/>
    </i:Interaction.Behaviors>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <!-- data template... -->
        </DataTemplate>
    </ListBox.ItemTemplate>
    <ListBox.GroupStyle>
        <GroupStyle>
        <!-- group style -->
        </GroupStyle>
    </ListBox.GroupStyle>
</ListBox>

If you’re not already grouping items in your ListBox, here is how to do it:

?View Code CSHARP
1
2
var cv = CollectionViewSource.GetDefaultView(viewmodel.Cities);
cv.GroupDescriptions.Add(new PropertyGroupDescription("Country"));

Useful resources

Download the code (VS2010 required)

[PDC10] WPF vNext

Events, WPF 1 Comment »

Day 1 of PDC 2010 is now over and I had the chance to watch the “WPF vNext” session by Rob Relyea. You can follow this link if you want to watch the video on-demand.

History

Rob starts with an history of Microsoft products from Windows 95 and IE 1.0…

The Blend team was created to build tools that would meet developers and designers needs. They worked closely with the Avalon team (codename for WPF) to make sure the platform was adequate and toolable.

Then the Cider team started their work in order to have a good integration in Visual Studio.

At this point, .Net 3.0 hasn’t shipped yet (it was in 2006), but Microsoft already has the vision of having XAML-based technology in the browser (with what would become Silverlight) and on the phone.

Silverlight & WPF

Silverlight

  • focuses on premium media experiences and business applications
  • suitable for most other types of application

WPF

  • complex ISV (Independent Software Vendors) applications
  • key scenarios includes DX and Hwnd interop

Convergence

  • bringing key features of WPF into Silverlight
  • WPF will support Silverlight hosting in the next version

ISV needs

  • great Windows applications
  • modern UI
  • seamless integration
  • rich content

Microsoft adoption of WPF

  • Visual Studio 2010
  • Expression Studio
  • Web Matrix
  • Powershell ISE
  • more to announce from Microsoft, but not during this PDC…

WPF vNext

  • integration of the Ribbon in WPF
  • improved collections handling in background thread (simplify the problem related to the UI thread)
  • improved UI virtualizing and grouping (right now virtualization is disabled as soon as you group data in an ItemsControl)
  • seamless integration: new SilverlightHost control (so we’ll be able to have DeepZoom in WPF !)
  • hwnd-based will no longer have airspace problem (for example, a Winforms control is always rendered on top of all other WPF controls).

As a conclusion, it’s good to see Microsoft finally giving some information about the future of WPF. The most important part I guess is to understand that Microsoft is still doing improvements on WPF and positioning WPF as the key technology for building apps with modern UI on Windows. We might have more and more applications switching to Silverlight but I’m sure they are still a lot of need for a technology like WPF which can use the whole power of the Windows OS (wheter it’s interop with native code, DirectX or other technologies).

For more information, you can also check-out a blog post from Pete Brown entitled “The Present and Future of WPF“.

WPF internals part 3 : how Z-Index works ?

WPF 2 Comments »

Almost 1 year ago, I started a series of blog posts entitled “WPF Internals”. I though I’d have more time to write entries on this subject but I wrote only 2 subjects:

Today, I’m ready to share with you part 3: how the Z-Index functionality works ? As for the other article of this series of blog post, the information I’m sharing here is based on my personal understanding of how stuff works. It might be wrong on some points !

The Z-Index is a property which can be set in order to control the order of appearance of your control:

In WPF it’s the Panel type which defines an attached property called Zindex:

?View Code CSHARP
1
2
3
4
5
public static readonly DependencyProperty ZIndexProperty = DependencyProperty.RegisterAttached(
	"ZIndex", 
	typeof(int), 
	typeof(Panel), 
	new FrameworkPropertyMetadata(0, new PropertyChangedCallback(Panel.OnZIndexPropertyChanged)));

which register a PropertyChangedCallback to be notified whenever its value changes. This method finally calls another method:

?View Code CSHARP
1
2
3
4
5
6
7
8
internal void InvalidateZState()
{
    if (!this.IsZStateDirty && (this._uiElementCollection != null))
    {
        base.InvalidateZOrder();
    }
    this.IsZStateDirty = true;
}

As you can see, the value of the IsZStateDirty property is set to true. We’ll soon see when this value is used. The InvalidateZOrder() is actually found in the Visual class. Here is a brief reminder of the core WPF types:

So, in the Visual type we have the InvalidateZOrder() method:

?View Code CSHARP
1
2
3
4
5
6
7
8
9
[FriendAccessAllowed]
internal void InvalidateZOrder()
{
    if (this.VisualChildrenCount != 0)
    {
        this.SetFlags(true, VisualFlags.NodeRequiresNewRealization);
        /* … */
    }
}

Which, as you can see, update the value of an enumeration (VisualFlags). Then the chain of method call stops here. The next interesting steps is when the GetVisualChild method (from the FrameworkElement type) gets called in the Panel type:

?View Code CSHARP
1
2
3
4
if (this.IsZStateDirty)
{
    this.RecomputeZState();
}

The RecomputeZState is a private method of the Panel class. The goal of this method is to update an array of int which is used as a lookup-table in order to convert the visual elements from their logical positions to their visual positions. At the end of this method, which is by the way highly-optimized with stuff like this

?View Code CSHARP
1
2
3
4
5
6
7
8
9
int z = _elements[i] != null
? (int)z = _elements[i].GetValue(ZIndexProperty)
: zIndexDefaultValue;
 
stableKeyValues.Add(((Int64)z << 32) + i);
lutRequired |= z < prevZ;
prevZ = z;
 
isDiverse |= (z != consonant);

the IZStateDirty value is set to false, and the zLut (z-order look up table, an int[]) is up-to-date. The the GetVisualChild method simply use the lookup table to convert logical position to visual position

?View Code CSHARP
1
2
int num = (this._zLut != null) ? this._zLut[index] : index;
return this._uiElementCollection[num];

Summary:

  • The Z-Index functionality of WPF is implemented using an attached property
  • This attached property is defined in the Panel type
  • When the value of the attached property changes, a flag is set at the Visual level and at the Panel level
  • When the GetVisualChild methods gets called on the Panel, the dirty status of the Z-Index is check
  • If necessary, a lookup-table is computed to convert logical position (in the Children collection) from visual position
  • Changing the ZIndex property of a child object does not change its position within the collection. The ordering within the collection remains the same

Attributes-based validation in a WPF MVVM application

.Net, CodeProject, WPF No Comments »

Today, I’m proud to share with you my very first article available on CodeProject. This article presents a technique which can be used in order to add validation in a WPF MVVM application based on attribute. Basically, it means that you can write validation logic like that (notice the attribute associated to this property):

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
[Required(ErrorMessage = "Field 'FirstName' is required.")]
public string FirstName
{
    get
    {
        return this.firstName;
    }
    set
    {
        this.firstName = value;
        this.OnPropertyChanged("FirstName");
    }
}

Of course the article comes with a nice demo application:

You can read the full article here: Attributes-based validation in a WPF MVVM application


MVVM Frameworks Explorer updated

Silverlight, Windows Phone, WPF 8 Comments »

Today I’m releasing a new version of my MVVM Frameworks Explorer application. You can find the updated version here: http://www.japf.fr/silverlight/mvvm/index.html

Here is a list of the changes in this new version:

  • application updated to Silverlight 4
  • support is now detailed for WPF, Silverlight and Windows Phone
  • new frameworks added (MEFedMVVM…)
  • framework’s logo added
  • download count added (based on the information I found on CodePlex website)
  • about window

As always, feel free to give feedback :-)

Where does the default TwoWay binding comes from ?

.Net, WPF No Comments »

I got a comment on my post about a very simple MVVM application about the fact that removing the TwoWay mode on a binding did not change the behavior of the application. This is a quick occasion for me to share a quick explanation about this.

Actually and as you already know if you can write XAML like Text={Binding …} it is only because Text is a Dependency Property. Also, dependency properties are defined in a static way (so that if you have 50 textboxes you don’t have to instantiate 50 times the Text property). The default behavior for the mode of the binding (TwoWay, OneWay, etc.) can be found in the static declaration of the dependency property. For example, in the case of the Text property of the TextBox we have:

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
TextProperty = DependencyProperty.Register(
	"Text", 
	typeof(string), 
	typeof(TextBox), 
	new FrameworkPropertyMetadata(
		string.Empty, 
		FrameworkPropertyMetadataOptions.Journal 
		| FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
	new PropertyChangedCallback(TextBox.OnTextPropertyChanged), 
	new CoerceValueCallback(TextBox.CoerceText),
	true, 
	UpdateSourceTrigger.LostFocus));

The interesting part here if of course the BindsTwoWayByDefault option. Note that this is the only default option available (we can’t have a OneWayToSource binding by default).

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in