Detecting dependency property changes in WinRT

Very poorPoorAverageGoodExcellent (No Ratings Yet) 
Loading ... Loading ...

Today I’d like to share a trick I used while developing my first Windows Store application. I’m very new to this technology and it’s my first article about it, so I hope I won’t make a fool of myself…

It’s often useful to be notified when the value of a dependency property changes; many controls expose events for that purpose, but it’s not always the case. For instance, recently I was trying to detect when the Content property of a ContentControl changed. In WPF, I would have used the DependencyPropertyDescriptor class, but it’s not available in WinRT.

Fortunately, there is a mechanism which is available on all XAML platforms, and can solve this problem: binding. So, the solution is just to create a class with a dummy property that is bound to the property we want to watch, and call a handler when the value of the dummy property changes. To make it cleaner and hide the actual implementation, I wrapped it as an extension method that returns an IDisposable:

    public static class DependencyObjectExtensions
    {
        public static IDisposable WatchProperty(this DependencyObject target,
                                                string propertyPath,
                                                DependencyPropertyChangedEventHandler handler)
        {
            return new DependencyPropertyWatcher(target, propertyPath, handler);
        }

        class DependencyPropertyWatcher : DependencyObject, IDisposable
        {
            private DependencyPropertyChangedEventHandler _handler;

            public DependencyPropertyWatcher(DependencyObject target,
                                             string propertyPath,
                                             DependencyPropertyChangedEventHandler handler)
            {
                if (target == null) throw new ArgumentNullException("target");
                if (propertyPath == null) throw new ArgumentNullException("propertyPath");
                if (handler == null) throw new ArgumentNullException("handler");

                _handler = handler;

                var binding = new Binding
                {
                    Source = target,
                    Path = new PropertyPath(propertyPath),
                    Mode = BindingMode.OneWay
                };
                BindingOperations.SetBinding(this, ValueProperty, binding);
            }

            private static readonly DependencyProperty ValueProperty =
                DependencyProperty.Register(
                    "Value",
                    typeof(object),
                    typeof(DependencyPropertyWatcher),
                    new PropertyMetadata(null, ValuePropertyChanged));

            private static void ValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                var watcher = d as DependencyPropertyWatcher;
                if (watcher == null)
                    return;

                watcher.OnValueChanged(e);
            }

            private void OnValueChanged(DependencyPropertyChangedEventArgs e)
            {
                var handler = _handler;
                if (handler != null)
                    handler(this, e);
            }

            public void Dispose()
            {
                _handler = null;
                // There is no ClearBinding method, so set a dummy binding instead
                BindingOperations.SetBinding(this, ValueProperty, new Binding());
            }
        }
    }

It can be used like this:

// Subscribe
watcher = myControl.WatchProperty("Content", myControl_ContentChanged);

// Unsubscribe
watcher.Dispose();

I hope you will find this useful!

Using C# 5 caller info attributes when targeting earlier versions of the .NET framework

Very poorPoorAverageGoodExcellent (2 votes) 
Loading ... Loading ...

Caller info attributes are one of the new features of C# 5. They’re attributes applied to optional method parameters that enable you to pass caller information implicitly to a method. I’m not sure that description is very clear, so an example will help you understand:

        static void Log(
            string message,
            [CallerMemberName] string memberName = null,
            [CallerFilePath] string filePath = null,
            [CallerLineNumber] int lineNumber = 0)
        {
            Console.WriteLine(
                "[{0:g} - {1} - {2} - line {3}] {4}",
                DateTime.UtcNow,
                memberName,
                filePath,
                lineNumber,
                message);
        }

The method above takes several parameters intended to pass information about the caller: calling member name, source file path and line number. The Caller* attributes make the compiler pass the appropriate values automatically, so you don’t have to specify the values for these parameters:

        static void Foo()
        {
            Log("Hello world");
            // Equivalent to:
            // Log("Hello world", "Foo", @"C:\x\y\z\Program.cs", 18);
        }

This is of course especially useful for logging methods…

Notice that the Caller* attributes are defined in the .NET Framework 4.5. Now, suppose we use Visual Studio 2012 to target an earlier framework version (e.g. 4.0): the caller info attributes don’t exist in 4.0, so we can’t use them… But wait! What if we could trick the compiler into thinking the attributes exist? Let’s define our own attributes, taking care to put them in the namespace where the compiler expects them:

namespace System.Runtime.CompilerServices
{
    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
    public class CallerMemberNameAttribute : Attribute
    {
    }

    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
    public class CallerFilePathAttribute : Attribute
    {
    }

    [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)]
    public class CallerLineNumberAttribute : Attribute
    {
    }
}

If we compile and run the program, we can see that our custom attributes are taken into account by the compiler. So they don’t have to be defined in mscorlib.dll like the “real” ones, they just have to be in the right namespace, and the compiler accepts them. This enables us to use this cool feature when targeting .NET 4.0, 3.5 or even 2.0!

Note that a similar trick enabled the creation of extension methods when targeting .NET 2.0 with the C# 3 compiler: you just had to create an ExtensionAttribute class in the System.Runtime.CompilerServices namespace, and the compiler would pick it up. This is also what enabled LinqBridge to work.

kick it on DotNetKicks.com

Posted in Tricks. Tags: , . 8 Comments »

Little known new features in Visual Studio 2012

Very poorPoorAverageGoodExcellent (5 votes) 
Loading ... Loading ...

Visual Studio 2012 RC is out since last week, and even though I didn’t have much time to play with it yet, I think I like it so far. Lots of things have already been said about the design, and about the most important new features, but there are also many smaller and less remarkable improvements that make life easier for us. Since I have seen little or nothing written about those, I thought I would make a list of what I noticed so far.

Better Edit and Continue: improved debug experience with anonymous methods

Edit and continue is a very useful feature that has been present in Visual Studio for a long time. It’s great when you need to fix some code in the middle of a step-by-step debugging session without restarting the application completely. This feature has always had a limitation: you couldn’t use it in a method that contained an anonymous method:

Modifying a ’method’ which contains a lambda expression will prevent the debug session from continuing while Edit and Continue is enabled.

Before .NET 3.5, it wasn’t really a problem since anonymous methods were not very common, but since Linq was introduced and lambda expressions became more widely used, this limitation began to grow more and more annoying.

Well, good news: Visual Studio 2012 fixed that! You can now use Edit and Continue in a method that contains lambda expressions or Linq queries. Note that the limitation hasn’t completely disappeared: you still can’t modify a statement that contains an anonymous method. Note the slightly different error message:

Modifying a statement which contains a lambda expression will prevent the debug session from continuing while Edit and Continue is enabled.

But you can modify everything else in the method body, which is a great improvement. Note that editing a method that contains anonymous types is also supported, as long as you don’t modify the anonymous type itself.

Optimized event handler autocompletion

Visual Studio has a nice autocompletion feature that allow you to generate an event handler automatically when you type += and Tab after an event name :

image

But the new EventHandler(…) part is redundant, because since C# 2, method groups are implicitly convertible to compatible delegate types. Visual Studio 2012 fixes this and generates the shorter form:

image

OK, this is a very small change, but the previous behavior was really annoying me… I had actually suggested this improvement on Connect, so I’m glad to see that it was implemented.

Improved Find/Replace

The Find dialog in Visual Studio had not seen any improvement for as long as I can remember (probably since VS2003 or VS2005), so it was time for a change… In VS2012, it has been replaced with the Quick Find feature from the Productivity Power Tools extension. It appears as a small panel in the top right corner of the text editor, much less obtrusive than the old dialog:

image

It provides the following features:

  • incremental search (matches are highlighted as you type in the search box)
  • quick access to options such as match case, match whole word, or regex through the search field dropdown
  • support for .NET regular expressions (the old Find dialog was using a different kind of regex, not fully compatible with the .NET regex syntax)

If for some reason you need the full Find dialog, it’s still there: there’s a menu item to access it in the search field dropdown.

Quick launch

Where’s that command again? In the Debug menu or the Project menu? I can’t remember, and I don’t know the keyboard shortcut…

Sounds familiar? For me it does… Visual Studio has so many features that sometimes it can be hard to find what you’re looking for. That’s why the new Quick Access feature is a very welcome addition; it appears as a search box in the top right corner of the IDE, and allows you to type what you want to do:

image

Again, this feature comes from the Productivity Power Tools extension, and has been included in Visual Studio itself. It has also been given a more prominent place in the IDE (in VS2010 it was only accessible through the Ctrl+Q shortcut).

Smarter Solution Explorer

The Solution Explorer used to show only the files in your project, but nothing about what was in the files; If you want to see the classes and members, you had to switch to the Class View. Visual Studio 2012 changes that: now you can see what is declared in a file, just by expanding the node in the Solution Explorer:

image

This feature had been in Eclipse for a long time, so it was time for Visual Studio to catch up Clignement d'œil.

A few other interesting features of the new Solution Explorer:

  • Scope to This: allows to re-root the tree to a specific node (e.g. if you want to see only the content of a folder). The re-rooted tree can be viewed in a separate view.
  • Pending Changes Filter: show only pending changes (if source control is active for the current project)
  • Open Files Filter: show only open files
  • Sync With Active Document: quickly locate the current document in the Solution Explorer (very useful for large solutions)

And yes, that’s yet another feature that comes from Productivity Power Tools (it was known as the Solution Navigator), with a few improvements.

ALL CAPS MENUS

Menus in VS2012 are in ALL CAPS, and it’s not exactly the most popular change… there has been tons of negative feedback about this! Frankly, I’m a bit surprised that people pay so much importance to such an insignificant detail, when there are so many more important things to discuss. Personally, I found it a bit unsettling when I saw the first screenshots, but when I got my hands on the RC I found that it didn’t bother me at all. I guess most people will just get used to it in the end…

Anyway, the reason I mention this is to say that if you really don’t like the ALL CAPS menus, you can get the normal casing back with a simple registry tweak. Just open regedit, go to the HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0\General key, create a DWORD value named SuppressUppercaseConversion and set it to 1.

kick it on DotNetKicks.com

[WPF] Using Linq to shape data in a CollectionView

Very poorPoorAverageGoodExcellent (5 votes) 
Loading ... Loading ...

WPF provides a simple mechanism for shaping collections of data, via the ICollectionView interface and its Filter, SortDescriptions and GroupDescriptions properties:

// Collection to which the view is bound
public ObservableCollection People { get; private set; }
...

// Default view of the People collection
ICollectionView view = CollectionViewSource.GetDefaultView(People);

// Show only adults
view.Filter = o => ((Person)o).Age >= 18;

// Sort by last name and first name
view.SortDescriptions.Add(new SortDescription("LastName", ListSortDirection.Ascending));
view.SortDescriptions.Add(new SortDescription("FirstName", ListSortDirection.Ascending));

// Group by country
view.GroupDescriptions.Add(new PropertyGroupDescription("Country"));

Even though this technique is not difficult to use, it has a few drawbacks:

  • The syntax is a bit clumsy and unnatural: the fact that the filter parameter is an object whereas we know it’s actually of type Person makes the code less readable because of the cast, and the specification of the sort and group descriptions is a little repetitive
  • Specifying the property names as strings introduces a risk of error, since they’re not verified by the compiler

In the last few years, we got used to use Linq to do this kind of things… it would be nice to be able to do the same for the shaping of an ICollectionView.

Let’s see what syntax we could use to do it with Linq… something like this perhaps?

People.Where(p => p.Age >= 18)
      .OrderBy(p => p.LastName)
      .ThenBy(p => p.FirstName)
      .GroupBy(p => p.Country);

Or, with the Linq query comprehension syntax:

from p in People
where p.Age >= 18
orderby p.LastName, p.FirstName
group p by p.Country;

Obviously, this is not enough: this code only creates a query on the collection, it doesn’t modify the CollectionView… but with just a little extra work, we can get the desired result:

var query =
    from p in People.ShapeView()
    where p.Age >= 18
    orderby p.LastName, p.FirstName
    group p by p.Country;

query.Apply();

The ShapeView method returns a wrapper which encapsulates the default view of the collection, and exposes Where, OrderBy and GroupBy methods with appropriate signatures to specify the shaping of the CollectionView. Creating the query has no direct effect, the changes are only applied to the view when Apply is called: that’s because it’s better to apply all changes at the same time, using ICollectionView.DeferRefresh, to avoid causing a refresh of the view for each clause of the query. When Apply is called, we can see that the view is correctly updated to reflect the query.

This solution allows to define the filter, sort and grouping in a strongly-typed way, which implies that the code is verified by the compiler. It’s also more concise and readable than the original code… Just be careful with one thing: some queries that are correct from the compiler’s point of view won’t be applicable to a CollectionView. For instance, if you try to group the data by the first letter of the last name (p.LastName.Substring(0, 1)), the GroupBy method will fail because only properties are supported by PropertyGroupDescription.

Note that the wrapper won’t overwrite the shaping properties of the CollectionView if you don’t specify the corresponding Linq clause, so you can just modify the current view without specifying everything again. If you need to clear the properties, you can use the ClearFilter, ClearSort and ClearGrouping methods:

// Remove the grouping and add a sort criteria
People.ShapeView()
      .ClearGrouping()
      .OrderBy(p => p.LastName);
      .Apply();

Note that as for a normal Linq query, it’s possible to use either the query comprehension syntax or to call the methods directly, since the former is just syntactic sugar for the latter.

Finally, here’s the complete code of the wrapper and the associated extension methods:

    public static class CollectionViewShaper
    {
        public static CollectionViewShaper<TSource> ShapeView<TSource>(this IEnumerable<TSource> source)
        {
            var view = CollectionViewSource.GetDefaultView(source);
            return new CollectionViewShaper<TSource>(view);
        }

        public static CollectionViewShaper<TSource> Shape<TSource>(this ICollectionView view)
        {
            return new CollectionViewShaper<TSource>(view);
        }
    }

    public class CollectionViewShaper<TSource>
    {
        private readonly ICollectionView _view;
        private Predicate<object> _filter;
        private readonly List<SortDescription> _sortDescriptions = new List<SortDescription>();
        private readonly List<GroupDescription> _groupDescriptions = new List<GroupDescription>();

        public CollectionViewShaper(ICollectionView view)
        {
            if (view == null)
                throw new ArgumentNullException("view");
            _view = view;
            _filter = view.Filter;
            _sortDescriptions = view.SortDescriptions.ToList();
            _groupDescriptions = view.GroupDescriptions.ToList();
        }

        public void Apply()
        {
            using (_view.DeferRefresh())
            {
                _view.Filter = _filter;
                _view.SortDescriptions.Clear();
                foreach (var s in _sortDescriptions)
                {
                    _view.SortDescriptions.Add(s);
                }
                _view.GroupDescriptions.Clear();
                foreach (var g in _groupDescriptions)
                {
                    _view.GroupDescriptions.Add(g);
                }
            }
        }

        public CollectionViewShaper<TSource> ClearGrouping()
        {
            _groupDescriptions.Clear();
            return this;
        }

        public CollectionViewShaper<TSource> ClearSort()
        {
            _sortDescriptions.Clear();
            return this;
        }

        public CollectionViewShaper<TSource> ClearFilter()
        {
            _filter = null;
            return this;
        }

        public CollectionViewShaper<TSource> ClearAll()
        {
            _filter = null;
            _sortDescriptions.Clear();
            _groupDescriptions.Clear();
            return this;
        }

        public CollectionViewShaper<TSource> Where(Func<TSource, bool> predicate)
        {
            _filter = o => predicate((TSource)o);
            return this;
        }

        public CollectionViewShaper<TSource> OrderBy<TKey>(Expression<Func<TSource, TKey>> keySelector)
        {
            return OrderBy(keySelector, true, ListSortDirection.Ascending);
        }

        public CollectionViewShaper<TSource> OrderByDescending<TKey>(Expression<Func<TSource, TKey>> keySelector)
        {
            return OrderBy(keySelector, true, ListSortDirection.Descending);
        }

        public CollectionViewShaper<TSource> ThenBy<TKey>(Expression<Func<TSource, TKey>> keySelector)
        {
            return OrderBy(keySelector, false, ListSortDirection.Ascending);
        }

        public CollectionViewShaper<TSource> ThenByDescending<TKey>(Expression<Func<TSource, TKey>> keySelector)
        {
            return OrderBy(keySelector, false, ListSortDirection.Descending);
        }

        private CollectionViewShaper<TSource> OrderBy<TKey>(Expression<Func<TSource, TKey>> keySelector, bool clear, ListSortDirection direction)
        {
            string path = GetPropertyPath(keySelector.Body);
            if (clear)
                _sortDescriptions.Clear();
            _sortDescriptions.Add(new SortDescription(path, direction));
            return this;
        }

        public CollectionViewShaper<TSource> GroupBy<TKey>(Expression<Func<TSource, TKey>> keySelector)
        {
            string path = GetPropertyPath(keySelector.Body);
            _groupDescriptions.Add(new PropertyGroupDescription(path));
            return this;
        }

        private static string GetPropertyPath(Expression expression)
        {
            var names = new Stack<string>();
            var expr = expression;
            while (expr != null && !(expr is ParameterExpression) && !(expr is ConstantExpression))
            {
                var memberExpr = expr as MemberExpression;
                if (memberExpr == null)
                    throw new ArgumentException("The selector body must contain only property or field access expressions");
                names.Push(memberExpr.Member.Name);
                expr = memberExpr.Expression;
            }
            return String.Join(".", names.ToArray());
        }
    }

kick it on DotNetKicks.com

Posted in WPF. Tags: , , . 3 Comments »

[WPF] Creating parameterized styles with attached properties

Very poorPoorAverageGoodExcellent (3 votes) 
Loading ... Loading ...

Today I’d like to share a trick that I used quite often in the past few months. Let’s assume that in order to improve the look of your application, you created custom styles for the standard controls:

OK, I’m not a designer… but it will serve the purpose well enough to illustrate my point ;) . These styles are very simple, they’re just the default styles of CheckBox and RadioButton in which I only changed the templates to replace the BulletChromes with these awesome blue tick marks. Here’s the code:

        <Style x:Key="{x:Type CheckBox}" TargetType="{x:Type CheckBox}">
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="Background" Value="{StaticResource CheckBoxFillNormal}"/>
            <Setter Property="BorderBrush" Value="{StaticResource CheckBoxStroke}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="FocusVisualStyle" Value="{StaticResource EmptyCheckBoxFocusVisual}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type CheckBox}">
                        <BulletDecorator Background="Transparent"
                                         SnapsToDevicePixels="true">
                            <BulletDecorator.Bullet>
                                <Border BorderBrush="{TemplateBinding BorderBrush}"
                                        Background="{TemplateBinding Background}"
                                        BorderThickness="1"
                                        Width="11" Height="11" Margin="0,1,0,0">
                                    <Grid>
                                        <Path Name="TickMark"
                                              Fill="Blue"
                                              Data="M0,4 5,9 9,0 4,5"
                                              Visibility="Hidden" />
                                        <Rectangle Name="IndeterminateMark"
                                                   Fill="Blue"
                                                   Width="7" Height="7"
                                                   HorizontalAlignment="Center"
                                                   VerticalAlignment="Center"
                                                   Visibility="Hidden" />
                                    </Grid>
                                </Border>
                            </BulletDecorator.Bullet>
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              Margin="{TemplateBinding Padding}"
                                              RecognizesAccessKey="True"
                                              SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </BulletDecorator>
                        <ControlTemplate.Triggers>
                            <Trigger Property="HasContent" Value="true">
                                <Setter Property="FocusVisualStyle" Value="{StaticResource CheckRadioFocusVisual}"/>
                                <Setter Property="Padding" Value="4,0,0,0"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                            </Trigger>
                            <Trigger Property="IsChecked" Value="True">
                                <Setter TargetName="TickMark" Property="Visibility" Value="Visible" />
                            </Trigger>
                            <Trigger Property="IsChecked" Value="{x:Null}">
                                <Setter TargetName="IndeterminateMark" Property="Visibility" Value="Visible" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style x:Key="{x:Type RadioButton}" TargetType="{x:Type RadioButton}">
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="Background" Value="#F4F4F4"/>
            <Setter Property="BorderBrush" Value="{StaticResource CheckBoxStroke}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type RadioButton}">
                        <BulletDecorator Background="Transparent">
                            <BulletDecorator.Bullet>
                                <Grid VerticalAlignment="Center" Margin="0,1,0,0">
                                    <Ellipse Width="11" Height="11"
                                             Stroke="{TemplateBinding BorderBrush}"
                                             StrokeThickness="1"
                                             Fill="{TemplateBinding Background}" />
                                    <Ellipse Name="TickMark"
                                             Width="7" Height="7"
                                             Fill="Blue"
                                             Visibility="Hidden" />
                                    <Ellipse Name="IndeterminateMark"
                                             Width="3" Height="3"
                                             Fill="Blue"
                                             Visibility="Hidden" />
                                </Grid>
                            </BulletDecorator.Bullet>
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              Margin="{TemplateBinding Padding}"
                                              RecognizesAccessKey="True"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </BulletDecorator>
                        <ControlTemplate.Triggers>
                            <Trigger Property="HasContent" Value="true">
                                <Setter Property="FocusVisualStyle" Value="{StaticResource CheckRadioFocusVisual}"/>
                                <Setter Property="Padding" Value="4,0,0,0"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                            </Trigger>
                            <Trigger Property="IsChecked" Value="True">
                                <Setter TargetName="TickMark" Property="Visibility" Value="Visible" />
                            </Trigger>
                            <Trigger Property="IsChecked" Value="{x:Null}">
                                <Setter TargetName="IndeterminateMark" Property="Visibility" Value="Visible" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

OK, so you now have beautiful controls that are going to make the app a big success, management is happy, everything is for the best… until you realize that in another view of the application, the controls need to have the same style, but with green tick marks!

The first solution that comes to mind is to duplicate the style, and replace blue with green in the copy. But since you’re a good developer who cares about best practices, you know that duplicate code is evil: if you ever need to make changes to the style of the blue CheckBox, you will also have to modify the green one… and perhaps the red one, and the black one, etc. Clearly it would soon become unmanageable. So we need to refactor, but how? Ideally we would pass parameters to the style, but a style is not a method that you can call with various parameters…

What we need is an extra property that controls the color of the tick marks, so we can bind to this property in the template. A possible approach is to create custom controls that inherit CheckBox and RadioButton, with an extra TickBrush property… but personnally I don’t really like this approach, I always prefer to use the built-in controls when they can fit the bill.

Anyway, there is an easier solution: we just need to create a ThemeProperties class with an attached property of type Brush:

    public static class ThemeProperties
    {
        public static Brush GetTickBrush(DependencyObject obj)
        {
            return (Brush)obj.GetValue(TickBrushProperty);
        }

        public static void SetTickBrush(DependencyObject obj, Brush value)
        {
            obj.SetValue(TickBrushProperty, value);
        }

        public static readonly DependencyProperty TickBrushProperty =
            DependencyProperty.RegisterAttached(
                "TickBrush",
                typeof(Brush),
                typeof(ThemeProperties),
                new FrameworkPropertyMetadata(Brushes.Black));
    }

We change the templates a bit to replace the hard-coded color with a binding to this property:

                                ...

                                <!-- CheckBox -->
                                        <Path Name="TickMark"
                                              Fill="{TemplateBinding my:ThemeProperties.TickBrush}"
                                              Data="M0,4 5,9 9,0 4,5"
                                              Visibility="Hidden" />
                                        <Rectangle Name="IndeterminateMark"
                                                   Fill="{TemplateBinding my:ThemeProperties.TickBrush}"
                                                   Width="7" Height="7"
                                                   HorizontalAlignment="Center"
                                                   VerticalAlignment="Center"
                                                   Visibility="Hidden" />

                                ...

                                <!-- RadioButton -->
                                    <Ellipse Name="TickMark"
                                             Width="7" Height="7"
                                             Fill="{TemplateBinding my:ThemeProperties.TickBrush}"
                                             Visibility="Hidden" />
                                    <Ellipse Name="IndeterminateMark"
                                             Width="3" Height="3"
                                             Fill="{TemplateBinding my:ThemeProperties.TickBrush}"
                                             Visibility="Hidden" />

And when we use the controls, we set the property to the desired tick color:

<CheckBox Content="Checked" IsChecked="True" my:ThemeProperties.TickBrush="Blue" />

So we can now have controls that share the same style, but have different colors for the tick mark:

Isn’t it great? However there is a small problem left: since controls on the same view all use the same tick color, it’s not very convenient to repeat the color on each one. It would be nice to be able to specify the color just once, on the root of the view… Well, as it happens, dependency properties have a nice feature that allows to do exactly that: value inheritance. We just need to specify the Inherits flag in the declaration of the TickBrush property:

        public static readonly DependencyProperty TickBrushProperty =
            DependencyProperty.RegisterAttached(
                "TickBrush",
                typeof(Brush),
                typeof(ThemeProperties),
                new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.Inherits));

With this flag, the property becomes “ambient”: we only need to specify its value on a parent control, and all descendant controls will automatically inherit the value. So if you need a view where all the checkboxes and radiobuttons are red, just set the TickBrush property to Red on the root element of the view.

Obviously this concept can be extended to other cases: actually, every time an element of the template must change based on arbitrary criteria, this technique can be used. It can be a good alternative to duplicating a template when you only need to change a small part of it.

kick it on DotNetKicks.com

[WPF 4.5] Subscribing to an event using a markup extension

Very poorPoorAverageGoodExcellent (No Ratings Yet) 
Loading ... Loading ...

It’s been a while since I last wrote about markup extensions… The release of Visual Studio 11 Developer Preview, which introduces a number of new features to WPF, just gave me a reason to play with them again. The feature I’m going to discuss here is perhaps not the most impressive, but it fills in a gap of the previous versions: the support of markup extensions for events.

Until now, it was possible to use a markup extension in XAML to assign a value to a property, but we couldn’t do the same to subscribe to an event. In WPF 4.5, it is now possible. So here is a small example of the kind we can do with it…

When using the MVVM pattern, we often associate commands of the ViewModel with controls of the view, via the binding mechanism. This approach usually works well, but it has some downsides:

  • it introduces a lot of boilerplate code in the ViewModel
  • not all controls have a Command property (actually, most don’t), and when this property exists, it corresponds only to one event of the control (e.g. the click on a button). There is no really easy way to “bind” the other events to commands of the ViewModel

It would be nice to be able to bind events directly to ViewModel methods, like this:

        <Button Content="Click me"
                Click="{my:EventBinding OnClick}" />

With the OnClick method defined in the ViewModel:

        public void OnClick(object sender, EventArgs e)
        {
            MessageBox.Show("Hello world!");
        }

Well, this is now possible! Here’s a proof of concept… The EventBindingExtension class shown below first gets the DataContext of the control, then looks for the specified method on the DataContext, and eventually returns a delegate for this method:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Markup;

    public class EventBindingExtension : MarkupExtension
    {
        public EventBindingExtension() { }

        public EventBindingExtension(string eventHandlerName)
        {
            this.EventHandlerName = eventHandlerName;
        }

        [ConstructorArgument("eventHandlerName")]
        public string EventHandlerName { get; set; }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (string.IsNullOrEmpty(EventHandlerName))
                throw new ArgumentException("The EventHandlerName property is not set", "EventHandlerName");

            var target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));

            EventInfo eventInfo = target.TargetProperty as EventInfo;
            if (eventInfo == null)
                throw new InvalidOperationException("The target property must be an event");

            object dataContext = GetDataContext(target.TargetObject);
            if (dataContext == null)
                throw new InvalidOperationException("No DataContext found");

            var handler = GetHandler(dataContext, eventInfo, EventHandlerName);
            if (handler == null)
                throw new ArgumentException("No valid event handler was found", "EventHandlerName");

            return handler;
        }

        #region Helper methods

        static object GetHandler(object dataContext, EventInfo eventInfo, string eventHandlerName)
        {
            Type dcType = dataContext.GetType();

            var method = dcType.GetMethod(
                eventHandlerName,
                GetParameterTypes(eventInfo));
            if (method != null)
            {
                if (method.IsStatic)
                    return Delegate.CreateDelegate(eventInfo.EventHandlerType, method);
                else
                    return Delegate.CreateDelegate(eventInfo.EventHandlerType, dataContext, method);
            }

            return null;
        }

        static Type[] GetParameterTypes(EventInfo eventInfo)
        {
            var invokeMethod = eventInfo.EventHandlerType.GetMethod("Invoke");
            return invokeMethod.GetParameters().Select(p => p.ParameterType).ToArray();
        }

        static object GetDataContext(object target)
        {
            var depObj = target as DependencyObject;
            if (depObj == null)
                return null;

            return depObj.GetValue(FrameworkElement.DataContextProperty)
                ?? depObj.GetValue(FrameworkContentElement.DataContextProperty);
        }

        #endregion
    }

This class can be used as shown in the example above.

As it is now, this markup extension has an annoying limitation: the DataContext must be set before the call to ProvideValue, otherwise it won’t be possible to find the event handler method. A solution could be to subscribe to the DataContextChanged event to look for the method after the DataContext is set, but in the meantime we still need to return something… and we can’t return null, because it would cause an exception (since you can’t subscribe to an event with a null handler). So we need to return a dummy handler generated dynamically from the event signature. It makes things a bit harder… but it’s still feasible.

Here’s a second version that implements this improvement :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Windows;
using System.Windows.Markup;

    public class EventBindingExtension : MarkupExtension
    {
        private EventInfo _eventInfo;

        public EventBindingExtension() { }

        public EventBindingExtension(string eventHandlerName)
        {
            this.EventHandlerName = eventHandlerName;
        }

        [ConstructorArgument("eventHandlerName")]
        public string EventHandlerName { get; set; }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (string.IsNullOrEmpty(EventHandlerName))
                throw new ArgumentException("The EventHandlerName property is not set", "EventHandlerName");

            var target = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));

            var targetObj = target.TargetObject as DependencyObject;
            if (targetObj == null)
                throw new InvalidOperationException("The target object must be a DependencyObject");

            _eventInfo = target.TargetProperty as EventInfo;
            if (_eventInfo == null)
                throw new InvalidOperationException("The target property must be an event");

            object dataContext = GetDataContext(targetObj);
            if (dataContext == null)
            {
                SubscribeToDataContextChanged(targetObj);
                return GetDummyHandler(_eventInfo.EventHandlerType);
            }

            var handler = GetHandler(dataContext, _eventInfo, EventHandlerName);
            if (handler == null)
            {
                Trace.TraceError(
                    "EventBinding: no suitable method named '{0}' found in type '{1}' to handle event '{2'}",
                    EventHandlerName,
                    dataContext.GetType(),
                    _eventInfo);
                return GetDummyHandler(_eventInfo.EventHandlerType);
            }

            return handler;

        }

        #region Helper methods

        static Delegate GetHandler(object dataContext, EventInfo eventInfo, string eventHandlerName)
        {
            Type dcType = dataContext.GetType();

            var method = dcType.GetMethod(
                eventHandlerName,
                GetParameterTypes(eventInfo.EventHandlerType));
            if (method != null)
            {
                if (method.IsStatic)
                    return Delegate.CreateDelegate(eventInfo.EventHandlerType, method);
                else
                    return Delegate.CreateDelegate(eventInfo.EventHandlerType, dataContext, method);
            }

            return null;
        }

        static Type[] GetParameterTypes(Type delegateType)
        {
            var invokeMethod = delegateType.GetMethod("Invoke");
            return invokeMethod.GetParameters().Select(p => p.ParameterType).ToArray();
        }

        static object GetDataContext(DependencyObject target)
        {
            return target.GetValue(FrameworkElement.DataContextProperty)
                ?? target.GetValue(FrameworkContentElement.DataContextProperty);
        }

        static readonly Dictionary<Type, Delegate> _dummyHandlers = new Dictionary<Type, Delegate>();

        static Delegate GetDummyHandler(Type eventHandlerType)
        {
            Delegate handler;
            if (!_dummyHandlers.TryGetValue(eventHandlerType, out handler))
            {
                handler = CreateDummyHandler(eventHandlerType);
                _dummyHandlers[eventHandlerType] = handler;
            }
            return handler;
        }

        static Delegate CreateDummyHandler(Type eventHandlerType)
        {
            var parameterTypes = GetParameterTypes(eventHandlerType);
            var returnType = eventHandlerType.GetMethod("Invoke").ReturnType;
            var dm = new DynamicMethod("DummyHandler", returnType, parameterTypes);
            var il = dm.GetILGenerator();
            if (returnType != typeof(void))
            {
                if (returnType.IsValueType)
                {
                    var local = il.DeclareLocal(returnType);
                    il.Emit(OpCodes.Ldloca_S, local);
                    il.Emit(OpCodes.Initobj, returnType);
                    il.Emit(OpCodes.Ldloc_0);
                }
                else
                {
                    il.Emit(OpCodes.Ldnull);
                }
            }
            il.Emit(OpCodes.Ret);
            return dm.CreateDelegate(eventHandlerType);
        }

        private void SubscribeToDataContextChanged(DependencyObject targetObj)
        {
            DependencyPropertyDescriptor
                .FromProperty(FrameworkElement.DataContextProperty, targetObj.GetType())
                .AddValueChanged(targetObj, TargetObject_DataContextChanged);
        }

        private void UnsubscribeFromDataContextChanged(DependencyObject targetObj)
        {
            DependencyPropertyDescriptor
                .FromProperty(FrameworkElement.DataContextProperty, targetObj.GetType())
                .RemoveValueChanged(targetObj, TargetObject_DataContextChanged);
        }

        private void TargetObject_DataContextChanged(object sender, EventArgs e)
        {
            DependencyObject targetObj = sender as DependencyObject;
            if (targetObj == null)
                return;

            object dataContext = GetDataContext(targetObj);
            if (dataContext == null)
                return;

            var handler = GetHandler(dataContext, _eventInfo, EventHandlerName);
            if (handler != null)
            {
                _eventInfo.AddEventHandler(targetObj, handler);
            }
            UnsubscribeFromDataContextChanged(targetObj);
        }

        #endregion
    }

So this is the kind of things we can do thanks to this new WPF feature. We could also imagine a behavior system similar to what we can do with attached properties, e.g. to execute a standard action when an event occurs. There are lots of possible applications for this, I leave it to you to find them ;)

kick it on DotNetKicks.com

Tail recursion in C#

Very poorPoorAverageGoodExcellent (2 votes) 
Loading ... Loading ...

Regardless of the programming language you’re using, there are tasks for which the most natural implementation uses a recursive algorithm (even if it’s not always the optimal solution). The trouble with the recursive approach is that it can use a lot of space on the stack: when you reach a certain recursion depth, the memory allocated for the thread stack runs out, and you get a stack overflow error that usually terminates the process (StackOverflowException in .NET).

Terminal recursion? What’s that?

Some languages, more particularly functional languages, have native support for an optimization technique called tail recursion. The idea is that if the recursive call is the last instruction in a recursive function, there is no need to keep the current call context on the stack, since we won’t have to go back there: we only need to replace the parameters with their new values, and jump back to the beginning of the function. So the recursion is transformed into an iteration, so it can’t cause a stack overflow. This notion being quite new to me, I won’t try to give a full course about tail recursion… much smarter people already took care of it! I suggest you follow the Wikipedia link above, which is a good starting point to understand tail recursion.

Unfortunately, the C# compiler doesn’t support tail recursion, which is a pity, since the CLR supports it. However, all is not lost! Some people had a very clever idea to work around this issue: a technique called “trampoline” (because it makes the function “bounce”) that allows to easily transform a recursive algorithm into an iterative algorithm. Samuel Jack has a good explanation of this concept on his blog. In the rest of this article, we will see how to apply this technique to a simple algorithm, using the class from Samuel Jack’s article; then I’ll present another implementation of the trampoline, which I find more flexible.

A simple use case in C#

Let’s see how we can transform a simple recursive algorithm, like the computation of the factorial of a number, into an algorithm that uses tail recursion (incidentally, the factorial can be computed much more efficiently with a non-recursive algorithm, but let’s assume we don’t know that…). Here’s a basic implementation that results directly from the definition:

BigInteger Factorial(int n)
{
    if (n < 2)
        return 1;
    return n * Factorial(n - 1);
}

(Note the use of BigInteger: if we are to make the recursion deep enough to observe the effects of tail recursion, the result will be far beyond the capacity of an int or even a long…)

If we call this method with a large value (around 20000 on my machine), we get an error which was quite predictable: StackOverflowException. We made so many nested call to the Factorial method that we exhausted the capacity of the stack. So we’re going to modify this code so that it can benefit from tail recursion…

As mentioned above, the key requirement for tail recursion is that the method calls itself as the last instruction. It seems to be the case here… but it’s not: the last operation is actually the multiplication, which can’t be executed until we know the result of Factorial(n-1). So we need to redesign this method so that it ends with a call to itself, with different arguments. To do that, we can add a new parameter named product, which will act as an accumulator:

BigInteger Factorial(int n, BigInteger product)
{
    if (n < 2)
        return product;
    return Factorial(n - 1, n * product);
}

For the first call, we’ll just have to pass 1 for the initial value of the accumulator.

We now have a method that meets the requirements for tail recursion: the recursive call to Factorial really is the last instruction. Now that we have put the algorithm in this form, the final transformation to enable tail recursion using Samuel Jack’s trampoline is trivial:

Bounce<int, BigInteger, BigInteger> Factorial(int n, BigInteger product)
{
    if (n < 2)
        return Trampoline.ReturnResult<int, BigInteger, BigInteger>(product);
    return Trampoline.Recurse<int, BigInteger, BigInteger>(n - 1, n * product);
}
  • Instead of returning the final result directly, we call Trampoline.ReturnResult to tell the trampoline that we now have a result
  • The recursive call to Factorial is replaced with a call to Trampoline.Recurse, which tells the trampoline that the method needs to be called again with different parameters

This method can’t be used directly: it returns a Bounce object, and we don’t really know what to do with this… To execute it, we use the Trampoline.MakeTrampoline method, which returns a new function on which tail recursion is applied. We can then use this new function directly:

Func<int, BigInteger, BigInteger> fact = Trampoline.MakeTrampoline<int, BigInteger, BigInteger>(Factorial);
BigInteger result = fact(50000, 1);

We can now compute the factorial of large numbers, with no risk of causing a stack overflow… Admittedly, it’s not very efficient: as mentioned before, there are better ways of computing a factorial, and furthermore, computations involving BigIntegers are much slower than with ints or longs.

Can we make it better?

Well, you can guess that I wouldn’t be asking the question unless the answer was yes… The trampoline implementation demonstrated above does its job well enough, but I think it could be made more flexible and easier to use:

  • It only works if you have 2 parameters (of course we can adapt it for a different number of parameters, but then we need to create new methods with adequate signatures for each different arity)
  • The syntax is quite unwieldy: there are 3 type arguments, and we need to specify them every time because the compiler doesn’t have enough information to infer them automatically
  • Having to use MakeTrampoline just to create a new function that we can then call isn’t very convenient; it would be more intuitive to have an Execute method that returns the result directly

And finally, I think the terminology isn’t very explicit… Names like Trampoline and Bounce sound like fun, but they don’t really reveal the intent.

So I tried to improve the system to make it more convenient. My solution is based on lambda expressions. There is only one type argument (the return type), and the parameters are passed trough a closure, so there is no need for multiple methods to handle different numbers of parameters. Here’s what the Factorial method looks like with my implementation:

RecursionResult<BigInteger> Factorial(int n, BigInteger product)
{
    if (n < 2)
        return TailRecursion.Return(product);
    return TailRecursion.Next(() => Factorial(n - 1, n * product));
}

It can be used as follows:

BigInteger result = TailRecursion.Execute(() => Factorial(50000, 1));

It’s more flexible, more concise, and more readable…in my opinion at leastSourire. The downside is that performance is slightly worse than before (it takes about 20% longer to compute the factorial of 50000), probably because of the delegate creation at each level of recursion.

Here’s the full code for the TailRecursion class:

public static class TailRecursion
{
    public static T Execute<T>(Func<RecursionResult<T>> func)
    {
        do
        {
            var recursionResult = func();
            if (recursionResult.IsFinalResult)
                return recursionResult.Result;
            func = recursionResult.NextStep;
        } while (true);
    }

    public static RecursionResult<T> Return<T>(T result)
    {
        return new RecursionResult<T>(true, result, null);
    }

    public static RecursionResult<T> Next<T>(Func<RecursionResult<T>> nextStep)
    {
        return new RecursionResult<T>(false, default(T), nextStep);
    }

}

public class RecursionResult<T>
{
    private readonly bool _isFinalResult;
    private readonly T _result;
    private readonly Func<RecursionResult<T>> _nextStep;
    internal RecursionResult(bool isFinalResult, T result, Func<RecursionResult<T>> nextStep)
    {
        _isFinalResult = isFinalResult;
        _result = result;
        _nextStep = nextStep;
    }

    public bool IsFinalResult { get { return _isFinalResult; } }
    public T Result { get { return _result; } }
    public Func<RecursionResult<T>> NextStep { get { return _nextStep; } }
}
Is there a better way to accomplish tail recursion in C#?

Sure! But it gets a little tricky, and it’s not pure C#. As I mentioned before, the CLR supports tail recursion, through the tail instruction. Ideally, the C# compiler would automatically generate this instruction for methods that are eligible to tail recursion, but unfortunately it’s not the case, and I don’t think this will ever be supported given the low demand for this feature.

Anyway, we can cheat a little by helping the compiler to do its job: the .NET Framework SDK provides tools named ildasm (IL disassembler) and ilasm (IL assembler), which can help to fill the gap between C# and the CLR… Let’s go back to the classical recursive implementation of Factorial, which doesn’t yet use tail recursion:

static BigInteger Factorial(int n, BigInteger product)
{
	if (n < 2)
		return product;
	return Factorial(n - 1, n * product);
}

If we compile this code and disassemble it with ilasm, we get the following IL code:

.method private hidebysig static valuetype [System.Numerics]System.Numerics.BigInteger
        Factorial(int32 n,
                  valuetype [System.Numerics]System.Numerics.BigInteger product) cil managed
{
  // Code size       41 (0x29)
  .maxstack  3
  .locals init (valuetype [System.Numerics]System.Numerics.BigInteger V_0,
           bool V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.2
  IL_0003:  clt
  IL_0005:  ldc.i4.0
  IL_0006:  ceq
  IL_0008:  stloc.1
  IL_0009:  ldloc.1
  IL_000a:  brtrue.s   IL_0010

  IL_000c:  ldarg.1
  IL_000d:  stloc.0
  IL_000e:  br.s       IL_0027

  IL_0010:  ldarg.0
  IL_0011:  ldc.i4.1
  IL_0012:  sub
  IL_0013:  ldarg.0
  IL_0014:  call       valuetype [System.Numerics]System.Numerics.BigInteger [System.Numerics]System.Numerics.BigInteger::op_Implicit(int32)
  IL_0019:  ldarg.1
  IL_001a:  call       valuetype [System.Numerics]System.Numerics.BigInteger [System.Numerics]System.Numerics.BigInteger::op_Multiply(valuetype [System.Numerics]System.Numerics.BigInteger,
                                                                                                                                      valuetype [System.Numerics]System.Numerics.BigInteger)
  IL_001f:  call       valuetype [System.Numerics]System.Numerics.BigInteger Program::Factorial(int32,
                                                                                                valuetype [System.Numerics]System.Numerics.BigInteger)
  IL_0024:  stloc.0
  IL_0025:  br.s       IL_0027

  IL_0027:  ldloc.0
  IL_0028:  ret
} // end of method Program::Factorial

It’s a bit hard on the eye if you’re not used to read IL code, but we can see roughly what’s going on… The recursive call is at offset IL_001f; this is where we’re going to fiddle with the generated code to introduce tail recursion. If we look at the documentation for the tail instruction, we see that it must immediately precede a call instruction, and that the instruction following the call must be ret (return). Right now, we have several instructions following the recursive call, because the compiler introduced a local variable to store the return value. We just need to modify the code so that it doesn’t use this variable, and add the tail instruction in the right place:

.method private hidebysig static valuetype [System.Numerics]System.Numerics.BigInteger
        Factorial(int32 n,
                  valuetype [System.Numerics]System.Numerics.BigInteger product) cil managed
{
  // Code size       41 (0x29)
  .maxstack  3
  .locals init (valuetype [System.Numerics]System.Numerics.BigInteger V_0,
           bool V_1)
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldc.i4.2
  IL_0003:  clt
  IL_0005:  ldc.i4.0
  IL_0006:  ceq
  IL_0008:  stloc.1
  IL_0009:  ldloc.1
  IL_000a:  brtrue.s   IL_0010

  IL_000c:  ldarg.1
  IL_000d:  ret		// Return directly instead of storing the result in V_0
  IL_000e:  nop

  IL_0010:  ldarg.0
  IL_0011:  ldc.i4.1
  IL_0012:  sub
  IL_0013:  ldarg.0
  IL_0014:  call       valuetype [System.Numerics]System.Numerics.BigInteger [System.Numerics]System.Numerics.BigInteger::op_Implicit(int32)
  IL_0019:  ldarg.1
  IL_001a:  call       valuetype [System.Numerics]System.Numerics.BigInteger [System.Numerics]System.Numerics.BigInteger::op_Multiply(valuetype [System.Numerics]System.Numerics.BigInteger,
                                                                                                                                      valuetype [System.Numerics]System.Numerics.BigInteger)
  IL_001f:  tail.
  IL_0020:  call       valuetype [System.Numerics]System.Numerics.BigInteger Program::Factorial(int32,
                                                                                                valuetype [System.Numerics]System.Numerics.BigInteger)
  IL_0025:  ret		// Return directly instead of storing the result in V_0

} // end of method Program::Factorial

If we reassemble this code with ilasm, we get a new executable, which runs without issues even for large values which made the old code crashSourire. Performance is also pretty good: about 3 times as fast than the version using the Trampoline class. If we compare the performance for smaller values (so that the old code doesn’t crash), we can see that it’s also 3 times as fast as the recursive version with no tail recursion.

Of course, this is just a proof of concept… it doesn’t seem very realistic to perform this transformation manually in a “real” project. However, it might be possible to create a tool that rewrites assemblies automatically after the compilation to introduce tail recursion.

kick it on DotNetKicks.com Shout it

[WPF] Display an animated GIF image

Very poorPoorAverageGoodExcellent (12 votes) 
Loading ... Loading ...

WPF is a great technology, but sometimes it seems to be missing some really basic features… A frequently mentioned example is the lack of support for animated GIF images. Actually, the GIF format itself is supported by the imaging API, but the Image control only shows the first frame of the animation.

Many solutions to this problem have been proposed on technical forums and blogs, usually variations of the following approaches:

  • Use the MediaElement control: unfortunately this control only supports URI like file:// or http://, not the pack:// URI schema used for WPF resources; this means the image can’t be included in the resources, it has to be in a separate file. Furthermore, transparency for GIF images isn’t supported in MediaElement, which makes the final result quite ugly
  • Use the PictureBox control from Windows Forms, via a WindowsFormsHost: I personnally dislike using WinForms controls in WPF, it really looks like a hack…
  • Create a custom control that inherits Image and handles the animation. Some solutions take advantage of the ImageAnimator class from System.Drawing (GDI), others use a WPF animation to change the current frame. It’s a rather “clean” approach, but it forces you to use a specific control for GIF images. Also, the solution using ImageAnimator turns out not to be very smooth, the animation is quite jerky.

As you might have guessed, I don’t find any of these solutions really satisfying… Furthermore, none of the implementations I’ve seen of the third approach handles the duration of each frame properly, they only assume that all frames last 100ms (which is almost always true, but almost isn’t good enough IMHO…). So I kept the best ideas from each approach I’ve seen, and I came up with my own solution. Here are the goals I set to attain:

  • No dependency on Windows Forms or GDI
  • Display the animated image in a standard Image control
  • Use the same XAML code for normal and animated images
  • Support for transparency
  • Correct handling of frame duration

To achieve this result, I started from a very simple, even obvious idea: to animate the image, all you have to do is apply an animation to the Source property of the Image control. WPF provides all the necessary tools to do that; in this case, the ObjectAnimationUsingKeyFrames class fits the bill perfectly: it allows to specify at what exact time a given value should be assigned to the property, which makes it easy to take the frame duration into account.

The next problem is to extract the frames from the image: fortunately WPF supports this natively, and the BitmapDecoder class provides a Frames property to do exactly that. So, no big difficulty so far…

Finally, last obstacle: extract the duration of each frame. It’s the part that took me the longest, because I needed to do some research… I first thought I would need to read the file manually and decode the binary data myself. But eventually the solution is quite simple, and takes advantage of the BitmapMetadata class. The only difficulty has been to find the “path” of the metadata that contains the delay, but after a few minutes of trial and error, here it is: /grctlext/Delay.

The final solution is implemented as an attached property named AnimatedSource, that applies to the Image control, and can be used instead of Source:

<Image Stretch="None" my:ImageBehavior.AnimatedSource="/Images/animation.gif" />

This property can also be assigned a normal (not animated) image, it will be displayed normally; therefore this property can be used without worrying about whether the image to display will be animated or not.

So in the end, all the goals have been achieved, and we even get some icing on the cake: this solution also works in the designer (at least in Visual Studio 2010), so the animation is immediately visible when you set the AnimatedSource property :)

Without further ado, here’s the complete code:

    public static class ImageBehavior
    {
        #region AnimatedSource

        [AttachedPropertyBrowsableForType(typeof(Image))]
        public static ImageSource GetAnimatedSource(Image obj)
        {
            return (ImageSource)obj.GetValue(AnimatedSourceProperty);
        }

        public static void SetAnimatedSource(Image obj, ImageSource value)
        {
            obj.SetValue(AnimatedSourceProperty, value);
        }

        public static readonly DependencyProperty AnimatedSourceProperty =
            DependencyProperty.RegisterAttached(
              "AnimatedSource",
              typeof(ImageSource),
              typeof(ImageBehavior),
              new UIPropertyMetadata(
                null,
                AnimatedSourceChanged));

        private static void AnimatedSourceChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            Image imageControl = o as Image;
            if (imageControl == null)
                return;

            var oldValue = e.OldValue as ImageSource;
            var newValue = e.NewValue as ImageSource;
            if (oldValue != null)
            {
                imageControl.BeginAnimation(Image.SourceProperty, null);
            }
            if (newValue != null)
            {
                imageControl.DoWhenLoaded(InitAnimationOrImage);
            }
        }

        private static void InitAnimationOrImage(Image imageControl)
        {
            BitmapSource source = GetAnimatedSource(imageControl) as BitmapSource;
            if (source != null)
            {
                var decoder = GetDecoder(source) as GifBitmapDecoder;
                if (decoder != null && decoder.Frames.Count > 1)
                {
                    var animation = new ObjectAnimationUsingKeyFrames();
                    var totalDuration = TimeSpan.Zero;
                    BitmapSource prevFrame = null;
                    FrameInfo prevInfo = null;
                    foreach (var rawFrame in decoder.Frames)
                    {
                        var info = GetFrameInfo(rawFrame);
                        var frame = MakeFrame(
                            source,
                            rawFrame, info,
                            prevFrame, prevInfo);

                        var keyFrame = new DiscreteObjectKeyFrame(frame, totalDuration);
                        animation.KeyFrames.Add(keyFrame);

                        totalDuration += info.Delay;
                        prevFrame = frame;
                        prevInfo = info;
                    }
                    animation.Duration = totalDuration;
                    animation.RepeatBehavior = RepeatBehavior.Forever;
                    if (animation.KeyFrames.Count > 0)
                        imageControl.Source = (ImageSource)animation.KeyFrames[0].Value;
                    else
                        imageControl.Source = decoder.Frames[0];
                    imageControl.BeginAnimation(Image.SourceProperty, animation);
                    return;
                }
            }
            imageControl.Source = source;
            return;
        }

        private static BitmapDecoder GetDecoder(BitmapSource image)
        {
            BitmapDecoder decoder = null;
            var frame = image as BitmapFrame;
            if (frame != null)
                decoder = frame.Decoder;

            if (decoder == null)
            {
                var bmp = image as BitmapImage;
                if (bmp != null)
                {
                    if (bmp.StreamSource != null)
                    {
                        bmp.StreamSource.Position = 0;
                        decoder = BitmapDecoder.Create(bmp.StreamSource, bmp.CreateOptions, bmp.CacheOption);
                    }
                    else if (bmp.UriSource != null)
                    {
                        Uri uri = bmp.UriSource;
                        if (bmp.BaseUri != null && !uri.IsAbsoluteUri)
                            uri = new Uri(bmp.BaseUri, uri);
                        decoder = BitmapDecoder.Create(uri, bmp.CreateOptions, bmp.CacheOption);
                    }
                }
            }

            return decoder;
        }

        private static BitmapSource MakeFrame(
            BitmapSource fullImage,
            BitmapSource rawFrame, FrameInfo frameInfo,
            BitmapSource previousFrame, FrameInfo previousFrameInfo)
        {
            DrawingVisual visual = new DrawingVisual();
            using (var context = visual.RenderOpen())
            {
                if (previousFrameInfo != null && previousFrame != null &&
                    previousFrameInfo.DisposalMethod == FrameDisposalMethod.Combine)
                {
                    var fullRect = new Rect(0, 0, fullImage.PixelWidth, fullImage.PixelHeight);
                    context.DrawImage(previousFrame, fullRect);
                }

                context.DrawImage(rawFrame, frameInfo.Rect);
            }
            var bitmap = new RenderTargetBitmap(
                fullImage.PixelWidth, fullImage.PixelHeight,
                fullImage.DpiX, fullImage.DpiY,
                PixelFormats.Pbgra32);
            bitmap.Render(visual);
            return bitmap;
        }

        private class FrameInfo
        {
            public TimeSpan Delay { get; set; }
            public FrameDisposalMethod DisposalMethod { get; set; }
            public double Width { get; set; }
            public double Height { get; set; }
            public double Left { get; set; }
            public double Top { get; set; }

            public Rect Rect
            {
                get { return new Rect(Left, Top, Width, Height); }
            }
        }

        private enum FrameDisposalMethod
        {
            Replace = 0,
            Combine = 1,
            RestoreBackground = 2,
            RestorePrevious = 3
        }

        private static FrameInfo GetFrameInfo(BitmapFrame frame)
        {
            var frameInfo = new FrameInfo
            {
                Delay = TimeSpan.FromMilliseconds(100),
                DisposalMethod = FrameDisposalMethod.Replace,
                Width = frame.PixelWidth,
                Height = frame.PixelHeight,
                Left = 0,
                Top = 0
            };

            BitmapMetadata metadata;
            try
            {
                metadata = frame.Metadata as BitmapMetadata;
                if (metadata != null)
                {
                    const string delayQuery = "/grctlext/Delay";
                    const string disposalQuery = "/grctlext/Disposal";
                    const string widthQuery = "/imgdesc/Width";
                    const string heightQuery = "/imgdesc/Height";
                    const string leftQuery = "/imgdesc/Left";
                    const string topQuery = "/imgdesc/Top";

                    var delay = metadata.GetQueryOrNull<ushort>(delayQuery);
                    if (delay.HasValue)
                        frameInfo.Delay = TimeSpan.FromMilliseconds(10 * delay.Value);

                    var disposal = metadata.GetQueryOrNull<byte>(disposalQuery);
                    if (disposal.HasValue)
                        frameInfo.DisposalMethod = (FrameDisposalMethod) disposal.Value;

                    var width = metadata.GetQueryOrNull<ushort>(widthQuery);
                    if (width.HasValue)
                        frameInfo.Width = width.Value;

                    var height = metadata.GetQueryOrNull<ushort>(heightQuery);
                    if (height.HasValue)
                        frameInfo.Height = height.Value;

                    var left = metadata.GetQueryOrNull<ushort>(leftQuery);
                    if (left.HasValue)
                        frameInfo.Left = left.Value;

                    var top = metadata.GetQueryOrNull<ushort>(topQuery);
                    if (top.HasValue)
                        frameInfo.Top = top.Value;
                }
            }
            catch (NotSupportedException)
            {
            }

            return frameInfo;
        }

        private static T? GetQueryOrNull<T>(this BitmapMetadata metadata, string query)
            where T : struct
        {
            if (metadata.ContainsQuery(query))
            {
                object value = metadata.GetQuery(query);
                if (value != null)
                    return (T) value;
            }
            return null;
        }

        #endregion
    }

And here’s the DoWhenLoaded extension method used in the code above:

public static void DoWhenLoaded<T>(this T element, Action<T> action)
    where T : FrameworkElement
{
    if (element.IsLoaded)
    {
        action(element);
    }
    else
    {
        RoutedEventHandler handler = null;
        handler = (sender, e) =>
        {
            element.Loaded -= handler;
            action(element);
        };
        element.Loaded += handler;
    }
}

Enjoy :)

Update: the code that retrieves the frame duration only works on Windows Seven, and on Windows Vista if the Platform Update is installed (untested). The default duration (100ms) will be used instead on other versions of Windows. I will update the article if I find a solution that works on all operating systems (I know I could use System.Drawing.Bitmap, but I’d rather not depend on this…)

Update 2: as pointed out by Klaus in the comments, the ImageBehavior class didn’t handle some important attributes of the frames: the diposal method (whether a frame should entirely replace the previous one, or be combined with it), and the frame position (Left/Top/Width/Height). I updated the code to handle these attributes properly. Thank you Klaus!

Update 3: a commenter on the French version of my blog pointed out a problem when the AnimatedSource is an image in a resource dictionary; the UriSource wasn’t correctly interpreted when it was a relative URI. This problem is now fixed. Thank you, “anonymous”!

Update 4: uploaded an example project to demonstrate the code.

Update 5: yet another bug fix, for when you use a BitmapImage initialized from a stream. Thanks to Mizutama for spotting this one!

Update 6: rather than posting improvements to this blog post, I eventually created a project on CodePlex where this class will be maintained. You can also install it using NuGet, the package id is WpfAnimatedGif. Thanks to Diego Mijelshon for the suggestion!

kick it on DotNetKicks.com

Posted in WPF. Tags: , , . 51 Comments »

[WPF] How to bind to data when the DataContext is not inherited

Very poorPoorAverageGoodExcellent (21 votes) 
Loading ... Loading ...

The DataContext property in WPF is extremely handy, because it is automatically inherited by all children of the element where you assign it; therefore you don’t need to set it again on each element you want to bind. However, in some cases the DataContext is not accessible: it happens for elements that are not part of the visual or logical tree. It can be very difficult then to bind a property on those elements…

Let’s illustrate with a simple example: we want to display a list of products in a DataGrid. In the grid, we want to be able to show or hide the Price column, based on the value of a ShowPrice property exposed by the ViewModel. The obvious approach is to bind the Visibility of the column to the ShowPrice property:

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                    Visibility="{Binding ShowPrice,
                        Converter={StaticResource visibilityConverter}}"/>

Unfortunately, changing the value of ShowPrice has no effect, and the column is always visible… why? If we look at the Output window in Visual Studio, we notice the following line:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=ShowPrice; DataItem=null; target element is ‘DataGridTextColumn’ (HashCode=32685253); target property is ‘Visibility’ (type ‘Visibility’)

The message is rather cryptic, but the meaning is actually quite simple: WPF doesn’t know which FrameworkElement to use to get the DataContext, because the column doesn’t belong to the visual or logical tree of the DataGrid.

We can try to tweak the binding to get the desired result, for instance by setting the RelativeSource to the DataGrid itself:

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                    Visibility="{Binding DataContext.ShowPrice,
                        Converter={StaticResource visibilityConverter},
                        RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}"/>

Or we can add a CheckBox bound to ShowPrice, and try to bind the column visibility to the IsChecked property by specifying the element name:

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                    Visibility="{Binding IsChecked,
                        Converter={StaticResource visibilityConverter},
                        ElementName=chkShowPrice}"/>

But none of these workarounds seems to work, we always get the same result…

At this point, it seems that the only viable approach would be to change the column visibility in code-behind, which we usually prefer to avoid when using the MVVM pattern… But I’m not going to give up so soon, at least not while there are other options to consider ;)

The solution to our problem is actually quite simple, and takes advantage of the Freezable class. The primary purpose of this class is to define objects that have a modifiable and a read-only state, but the interesting feature in our case is that Freezable objects can inherit the DataContext even when they’re not in the visual or logical tree. I don’t know the exact mechanism that enables this behavior, but we’re going to take advantage of it to make our binding work…

The idea is to create a class (I called it BindingProxy for reasons that should become obvious very soon) that inherits Freezable and declares a Data dependency property:

    public class BindingProxy : Freezable
    {
        #region Overrides of Freezable

        protected override Freezable CreateInstanceCore()
        {
            return new BindingProxy();
        }

        #endregion

        public object Data
        {
            get { return (object)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
    }

We can then declare an instance of this class in the resources of the DataGrid, and bind the Data property to the current DataContext:

<DataGrid.Resources>
    <local:BindingProxy x:Key="proxy" Data="{Binding}" />
</DataGrid.Resources>

The last step is to specify this BindingProxy object (easily accessible with StaticResource) as the Source for the binding:

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                    Visibility="{Binding Data.ShowPrice,
                        Converter={StaticResource visibilityConverter},
                        Source={StaticResource proxy}}"/>

Note that the binding path has been prefixed with “Data”, since the path is now relative to the BindingProxy object.

The binding now works correctly, and the column is properly shown or hidden based on the ShowPrice property.

[Entity Framework] Using Include with lambda expressions

Very poorPoorAverageGoodExcellent (8 votes) 
Loading ... Loading ...

I’m currently working on a project that uses Entity Framework 4. Even though lazy loading is enabled, I often use the ObjectQuery.Include method to eagerly load associated entities, in order to avoid database roundtrips when I access them:

var query =
    from ord in db.Orders.Include("OrderDetails")
    where ord.Date >= DateTime.Today
    select ord;

Or if I also want to eagerly load the product:

var query =
    from ord in db.Orders.Include("OrderDetails.Product")
    where ord.Date >= DateTime.Today
    select ord;

However, there’s something that really bothers me with this Include method: the property path is passed as a string. This approach has two major drawbacks:

  • It’s easy to make a mistake when typing the property path, and since it’s a string, the compiler doesn’t complain. So we get a runtime error, rather than a compilation error.
  • We can’t take advantage of IDE features like Intellisense and refactoring. If we rename a property in the model, automatic refactoring won’t check the content of the string. We have to manually update all calls to Include that refer to this property, with the risk of missing some of them in the process…

It would be much more convenient to use a lambda expression to specify the property path. The principle is well known, and frequently used to avoid using a string to refer to a property.

The trivial case, where the property to include is directly accessible from the source, is pretty easy to handle, and many implementation can be found on the Internet. We just need to use a method that extracts the property name from an expression :

    public static class ObjectQueryExtensions
    {
        public static ObjectQuery<T> Include<T>(this ObjectQuery<T> query, Expression<Func<T, object>> selector)
        {
            string propertyName = GetPropertyName(selector);
            return query.Include(propertyName);
        }

        private static string GetPropertyName<T>(Expression<Func<T, object>> expression)
        {
            MemberExpression memberExpr = expression.Body as MemberExpression;
            if (memberExpr == null)
                throw new ArgumentException("Expression body must be a member expression");
            return memberExpr.Member.Name;
        }
    }

Using that extension method, the code from the first sample can be rewritten as follows:

var query =
    from ord in db.Orders.Include(o => o.OrderDetails)
    where ord.Date >= DateTime.Today
    select ord;

This code works fine, but only for the simplest cases… In the second example, we also want to eagerly load the OrderDetail.Product property, but the code above can’t handle that case. Indeed, the expression we would use to include the Product property would be something like o.OrderDetails.Select(od => od.Product), but the GetPropertyName method can only handle property accesses, not method calls, and it works only for an expression with a single level.

To get the full path of the property to include, we have to walk through the whole expression tree to extract the name of each property. It sounds like a complicated task, but there’s a class that can help us with it: ExpressionVisitor. This class was introduced in .NET 4.0 and implements the Visitor pattern to walk through all nodes in the expression tree. It’s just a base class for implementing custom visitors, and it does nothing else than just visiting each node. All we need to do is inherit it, and override some methods to extract the properties from the expression. Here are the methods we need to override:

  • VisitMember : used to visit a property or field access
  • VisitMethodCall : used to visit a method call. Even though method calls aren’t directly related to what we want to do, we need to change its behavior in the case of Linq operators: the default implementation visits each parameter in their normal order, but for extension method like Select or SelectMany, we need to visit the first parameter (the this parameter) last, so that we retrieve the properties in the correct order.

    Here’s a new version of the Include method, along with the ExpressionVisitor implementation:

        public static class ObjectQueryExtensions
        {
            public static ObjectQuery<T> Include<T>(this ObjectQuery<T> query, Expression<Func<T, object>> selector)
            {
                string path = new PropertyPathVisitor().GetPropertyPath(selector);
                return query.Include(path);
            }
    
            class PropertyPathVisitor : ExpressionVisitor
            {
                private Stack<string> _stack;
    
                public string GetPropertyPath(Expression expression)
                {
                    _stack = new Stack<string>();
                    Visit(expression);
                    return _stack
                        .Aggregate(
                            new StringBuilder(),
                            (sb, name) =>
                                (sb.Length > 0 ? sb.Append(".") : sb).Append(name))
                        .ToString();
                }
    
                protected override Expression VisitMember(MemberExpression expression)
                {
                    if (_stack != null)
                        _stack.Push(expression.Member.Name);
                    return base.VisitMember(expression);
                }
    
                protected override Expression VisitMethodCall(MethodCallExpression expression)
                {
                    if (IsLinqOperator(expression.Method))
                    {
                        for (int i = 1; i < expression.Arguments.Count; i++)
                        {
                            Visit(expression.Arguments[i]);
                        }
                        Visit(expression.Arguments[0]);
                        return expression;
                    }
                    return base.VisitMethodCall(expression);
                }
    
                private static bool IsLinqOperator(MethodInfo method)
                {
                    if (method.DeclaringType != typeof(Queryable) && method.DeclaringType != typeof(Enumerable))
                        return false;
                    return Attribute.GetCustomAttribute(method, typeof(ExtensionAttribute)) != null;
                }
            }
        }
    

    I already talked about the VisitMethodCall method, so I won’t explain it further. The implementation of VisitMember is very simple: we just push the member name on a stack. Why a stack ? That’s because the expression is not visited in the order one would intuitively expect. For instance, in an expression like o.OrderDetails.Select(od => od.Product), the first visited node is not o but the call to Select, because what precedes it (o.OrderDetails) is actually the first parameter of the static Select method… To retrieve the properties in the correct order, we put them on a stack so that we can read them back in reverse order when we need to build the property path.

    The GetPropertyPath method probably doesn’t need a long explanation: it initializes the stack, visits the expression, and builds the property path from the stack.

    We can now rewrite the code from the second example as follows:

    var query =
        from ord in db.Orders.Include(o => OrderDetails.Select(od => od.Product))
        where ord.Date >= DateTime.Today
        select ord;
    

    This method also works for more complex cases. Let’s add a few new entities to our model: one or more discounts can be applied to each purchased product, and each discount is linked to a sales campaign. If we need to retrieve the associated discounts and campaigns in the query results, we can write something like that:

    var query =
        from ord in db.Orders.Include(o => OrderDetails.Select(od => od.Discounts.Select(d => d.Campaign)))
        where ord.Date >= DateTime.Today
        select ord;
    

    The result is the same as if we had passed “OrderDetails.Discounts.Campaign” to the standard Include method. Since the nested Select calls impair the readability, we can also use a different expression, with the same result:

    var query =
        from ord in db.Orders.Include(o => o.OrderDetails
                                            .SelectMany(od => od.Discounts)
                                            .Select(d => d.Campaign))
        where ord.Date >= DateTime.Today
        select ord;
    

    To conclude, I just have two remarks regarding this solution:

    • A similar extension method is included in the Entity Framework Feature CTP4 (see this article for details). So it is possible that it will eventually be included in the framework (perhaps in a service pack for .NET 4.0 ?).
    • Even though this solution targets Entity Framework 4.0, it should be possible to adapt it for EF 3.5. The ExpressionVisitor class is not available in 3.5, but there is another implementation of it in Joseph Albahari’s LINQKit. I didn’t try it, but it should work the same way…

    kick it on DotNetKicks.com