Another .NET Blog

To content | To menu | To search

Wednesday 1 September 2010

[PostSharp] Fire INotifyPropertyChanged.OnPropertyChanged for read-only properties depending on other properties

One problem of the INotifyPropertyChanged aspect concerns automatic notification of read-only properties which depend on other properties.

Indeed, say you have this class, on which the aspect is applied:

[NotifyPropertyChanged]
public class Test
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public string FullName { get { return FirstName + " " + LastName; } }
}

If you change the values of FirstName or LastName, the OnPropertyChanged event will be fired, and the view will be able to display the new values of the properties. But if a control of your view is bound to the FullName property, it won't be updated. A solution would be to declare FullName as an automatic property, and update it in the setters of FirstName and LastName. Not very practical.

In this article, I will show you how to extend the aspect, in order to make it fire the event for dependent properties when a "parent" property is modified.

Continue reading...

Thursday 15 July 2010

[PostSharp] [FluentValidation] Automatic entity validation with IDataErrorInfo

This post is an english translation of this french post.

One way to manage data validation when using WPF is to implement the interface IDataErrorInfo on the classes to validate, and to modify the XAML file so that WPF automatically uses the functions of this interface to validate the value of the properties (See here for an example).

The problem with this, is that you have to alter your entities to add some logic inside them, which makes them become more than entities. One way to avoid that is provided by FluentValidation, which allows you to deport the validation logic outside of your entities, inside another class, where you can define some validation rules for your entity.

But as we always want our entities to continue to implement IDataErrorInfo, we have to operate a mix with FluentValidation. You can find a way to achieve that in this thread.

This thread was the starting point of the solution I'm going to propose to you, to fix this problematic in an easy way...

Continue reading...

[PostSharp] [Caliburn] - Automatically call NotifyOfPropertyChange on the view models

Here, I won't explain what are Caliburn and PostSharp. Their respective documentations, examples and samples already do that very well. But I will show you how to create an aspect which will be applied by PostSharp on the view models of a WPF assembly.

And as a result, on runtime, each time a public property will be changed, the event PropertyChanged of the interface INotifyPropertyChanged will be fired, and the WPF view will be able to refresh its state.

If you already know PostSharp, or have been on their website, you have certainly noticed that they already propose an aspect which intends to implement the interface INotifyPropertyChanged, and to call PropertyChanged when the value of a property is changed.

And if you already know Caliburn, you know that the classes you must inherit from to implement your view models inherit themselves from an abstract class named PropertyChangedBase, which implements INotifyPropertyChanged, and which proposes a function named NotifyOfPropertyChange, to which you give as a parameter the name of the modified property.

The aspect I'm going to show you will allow us to mix these 2 methods.

Continue reading...

Monday 28 June 2010

[PostSharp] [FluentValidation] Validation de classes grâce à IDataErrorInfo

Une manière de gérer la validation des données lorsqu'on utilise WPF est de faire implémenter l'interface IDataErrorInfo par les classes à valider, et de modifier votre fichier XAML pour que WPF utilise automatiquement les fonctions de cette interface pour valider la valeur des propriétés. (Un exemple en action ici).

Le souci avec cette méthode est que vos entités deviennent un peu plus que des entités de base. Et vous vous dites que finalement, ça ne serait pas mal d'externaliser la validation de ces entités dans une autre classe. Et pourquoi pas de définir des règles que votre entité se doit de respecter pour être valide. Pour cela, il existe FluentValidation.

Mais pour continuer à utiliser IDataErrorInfo, on doit maintenant utiliser FluentValidation au sein des fonctions définies par IDataErrorInfo. C'est ce que propose ce thread dans le forum de FluentValidation.

C'est en partant de cet article que je vais vous montrer le cheminement qui m'a amené à utiliser PostSharp pour régler en beauté (j'espère en tout cas) cette problématique.

Continue reading...

Tuesday 22 June 2010

[PostSharp] [Caliburn] - Appeler automatiquement NotifyOfPropertyChange pour les ViewModels

Dans cet article, je ne vais pas vous expliquer ce que sont Caliburn et PostSharp, leurs documentations et exemples respectifs le font déjà très bien, mais je vais expliquer comment créer un aspect que Postsharp va appliquer à des classes que nous définirons, et qui aura pour résultat d'implémenter l'interface INotifyPropertyChanged dans ces classes, et d'appeler automatiquement l'évènement PropertyChanged lorsque la valeur des propriétés publiques de ces classes va être modifiée.

Si vous connaissez déjà Postsharp, ou avez été regardé sur leur site, vous aurez sûrement remarqué qu'il existe déjà un aspect qui permet d'implémenter l'interface INotifyPropertyChanged, et d'appeler PropertyChanged à chaque changement de valeur de la propriété.

De même, si vous connaissez Caliburn, vous aurez également remarqué que les classes dont vous devez dériver pour implémenter vos ViewModels dérivent elles-même d'une classe abstraite nommée PropertyChangedBase, qui implémente INotifyPropertyChanged, et qui propose une fonction nommée NotifyOfPropertyChange, à laquelle vous passez comme paramètre le nom de la propriété qui a été modifiée.

L'aspect que je vais vous montrer va nous permettre de mixer ces 2 approches.

Continue reading...

Friday 18 December 2009

Methode d'extension pour agir sur l'UI depuis un autre thread en WPF

Je profite d'en avoir parlé lors de mon dernier post pour vous donner une méthode d'extension toute faite qui vous permettra d'appeler automatiquement BeginInvoke sur le Dispatcher d'un contrôle WPF si l'action que vous voulez exécuter sur le contrôle se passe depuis un autre thread que celui sur lequel tourne l'application:

namespace System.Windows.Threading
{
    public static class DispatcherExtensions
    {
        /// 
        /// Executes the action on the thread of the UI if needed, or on the current thread if not
        /// 
        /// The Dispatcher of the control
        /// The action to execute
        /// The dispatcher or the action are null
        public static void CheckAccessAndDo(this Dispatcher dispatcher, Action action)
        {
            CheckAccessAndDo(dispatcher, DispatcherPriority.Normal, action);
        }

        /// 
        /// Executes the action on the thread of the UI if needed, or on the current thread if not
        /// 
        /// The Dispatcher of the control
        /// The priority of the action
        /// The action to execute
        /// The dispatcher or the action are null
        public static void CheckAccessAndDo(this Dispatcher dispatcher, DispatcherPriority priority, Action action)
        {
            if (dispatcher == null) throw new ArgumentNullException("dispatcher");
            if (action == null) throw new ArgumentNullException("action");

            if (dispatcher.CheckAccess())
                action();
            else
            {
                dispatcher.BeginInvoke(priority, action);
            }
        }
    }
}

Pour l'utiliser, c'est très simple et évident:

label.Dispatcher.CheckAccessAndDo(delegate { label.Content = "foo"; } );

De quoi rendre la vie plus facile :p

Exécuter une tâche sur le même thread que celui de l'UI

Le problème est classique: vous créez un thread pour réaliser une opération, et vous voulez que ce thread modifie un composant graphique (comme une ProgressBar par exemple). La solution, que vous devez sûrement connaître, consiste à exécuter l'action en question sur le même thread que celui de l'UI, c'est à dire, en WPF, utiliser la fonction BeginInvoke de la propriété Dispatcher de votre contrôle. Si vous avez un grand nombre de modifications de votre interface utilisateur qui sont effectués depuis une ou plusieurs tâches, plutôt que d'appeler BeginInvoke de multiples fois, il existe une solution toute simple, qui consiste à créer et lancer vos tâches en utilisant une TaskFactory à laquelle vous aurez donné comme TaskScheduler celui chargé de gérer l'UI.

Pour cela, c'est très simple:

public partial class MyUserControl : UserControl
{
    private TaskFactory _ui;

    public MyUserControl()
    {
        InitializeComponent();

        _ui = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext()); 
        _ui.StartNew(() => { Width = 100; } );
    }
}

Et donc toutes les tâches que vous créerez depuis cette TaskFactory seront "schedulées" (je ne sais pas trop comment traduire ça au mieux) sur le thread de l'UI, et donc vous dispensera d'utiliser Dispatcher.BeginInvoke à tout va.

A noter que le code suivant fonctionne tout aussi bien:

public partial class MyUserControl : UserControl
{
    private TaskScheduler _ts;

    public MyUserControl()
    {
        InitializeComponent();

        _ts = TaskScheduler.FromCurrentSynchronizationContext();
        Task.Factory.StartNew(() => { Width = 100; }, _ts);
    }
}