Sortie de la version 0.5 de Dvp.NET
La librairie open source .NET regroupant des fonctionnalités issues des membres du club Developpez.com

Le , par tomlev, Rédacteur/Modérateur
La version 0.5 de la librairie Dvp.NET est disponible !



Pour installer Dvp.NET, le plus simple est d'utiliser Nuget, le gestionnaire de packages pour Visual Studio, comme expliqué ici. Vous pouvez aussi télécharger la librairie directement en utilisant les liens à la fin de ce post.

Encore une fois, de nombreuses nouveautés sont au programme de cette version. Et comme d'habitude, c'est un peu hétéroclite : il y en a pour tous les goûts ou presque... voici la liste des nouveautés :

  • Assembly Developpez.Dotnet :
    • Classe StreamExtensions :
      • Méthode d’extension Tee : duplique ce qu'on écrit sur un flux vers un autre flux (ou plusieurs). Similaire à la commande UNIX tee
    • Classe TextWriterExtensions :
      • Méthode d’extension Tee : comme StreamExtensions.Tee, mais pour les TextWriter. Exemple :
        Code C# : Sélectionner tout
        1
        2
        3
        4
        5
        6
            // Copie dans le log tout ce qu'on écrit sur la console 
            using(var logFile = new StreamWriter("log.txt", true)) 
            using (var output = Console.Out.Tee(logFile)) 
            { 
                output.WriteLine("Hello"); 
            }
    • Classe EnumerableExtensions :
      • Méthodes d’extension MinBy/MaxBy/Min(IComparer)/Max(IComparer) : correction d'un bug dans le cas d'une séquence vide (ça renvoyait la valeur par défaut alors qu'il fallait lever une exception, comme pour les méthodes Min/Max standards de Linq)
      • Méthodes d’extension AllMaxBy/AllMinBy : comme MaxBy/MinBy, mais renvoie tous les éléments qui ont la valeur max/min (au lieu d'un seul)
      • Méthode d'extension ElementDefaultValue : permet d'obtenir la valeur par défaut du type d'élément d'une collection (utile quand on travaille avec des types anonymes)
      • Méthode d’extension TakeLast : optimisation du cas où la collection implémente IList<TSource>
      • Méthode d’extension AggregateByPairs : comme Aggregate, mais prend les éléments de la liste 2 par 2. Exemple d'application : on a un itinéraire sous forme d’une liste de villes étapes, et une fonction qui renvoie la distance entre 2 villes. Pour avoir la distance totale, on peut faire ça :
        Code C# : Sélectionner tout
        var totalDistance = cities.AggregateByPairs(0, (sum, a, b) => sum + Distance(a, b))
      • Méthode d’extension SequenceEqualBy : comme SequenceEqual, mais permet de spécifier le critère d'égalité :
        Code C# : Sélectionner tout
        1
        2
        3
        4
        5
        // Comparaison des listes selon l'id des éléments: 
        if (list1.SequenceEqualBy(list2, x => x.Id)) 
        { 
            ... 
        }
      • Méthode d’extension Replace : remplace l'élément spécifié de la séquence par un autre :
        Code C# : Sélectionner tout
        list.Replace("foo", "bar");
      • Méthodes d’extension InsertBefore/InsertAfter : insère un élément dans une séquence avant ou après chaque occurrence de l'élément spécifié :
        Code C# : Sélectionner tout
        1
        2
        3
        var input = new[] { "foo", "baz", "bar", "baz" }; 
        var result = input.InsertAfter("baz", "zoo"); 
        // result = { "foo", "baz", "zoo", "bar", "baz", "zoo" }
      • Méthodes d'extension InsertBeforeFirst/InsertAfterFirst : insère un élément dans une séquence avant ou après la première occurrence de l'élément spécifié :
        Code C# : Sélectionner tout
        1
        2
        3
        var input = new[] { "foo", "baz", "bar", "baz" }; 
        var result = input.InsertAfterFirst("baz", "zoo"); 
        // result = { "foo", "baz", "zoo", "bar", "baz" }
      • Méthodes d'extension RankBy/RankByDescending : associe à chaque élément son rang selon la clé spécifiée (comme RANK en SQL, bien que ça s'utilise pas tout à fait pareil). Le code suivant :
        Code C# : Sélectionner tout
        1
        2
        3
        4
        5
        6
        7
        8
        9
        var hallOfFame = 
            players.RankByDescending( 
                    p => p.Score, 
                    (p, rank) => { Player = p, Rank = rank }); 
          
        foreach(var x in hallOfFame) 
        { 
            Console.WriteLine("{0}t{1}t{2}", x.Rank, x.Player.Name, x.Player.Score); 
        }
        Produit la sortie suivante :
        1   William 100 
        2 Cheeta 50
        3 Joe 42
        3 Averell 42
        3 Jane 42
        6 Jack 25
        6 Flipper 25
        8 Tarzan 1
      • Méthodes d'extension DenseRankBy/DenseRankByDescending : idem, mais sans trous dans le classement (comme DENSE_RANK en SQL). Le code précédent avec DenseRankByDescending produit la sortie suivante :
        1   William 100 
        2 Cheeta 50
        3 Joe 42
        3 Averell 42
        3 Jane 42
        4 Jack 25
        4 Flipper 25
        5 Tarzan 1
      • Méthodes d’extension LeftOuterJoin/RightOuterJoin/FullOuterJoin : permettent d’effectuer plus facilement des jointures externes, qui ne sont pas très intuitives avec les opérateurs standards de Linq. Exemple :
        Code C# : Sélectionner tout
        1
        2
        3
        4
        5
        6
            var result = 
                list1.LeftOuterJoin( 
                    list2, 
                    x1 => x1.Id, 
                    x2 => x2.Id, 
                    (x1, x2) => new { x1, x2 });
    • Classe DateTimeExtensions :
      • Méthode d’extension Truncate : tronque une date au composant spécifié (année, mois, jour, heure, minute, seconde, milliseconde). Exemple :
        Code C# : Sélectionner tout
        var firstDayOfMonth = DateTime.Now.Truncate(DateTimeComponent.Month)
      • Méthode StartOfWeek : renvoie la date de début de la semaine spécifiée (année et numéro de semaine) (cf. demande #1405).
    • Classe StringExtensions :
      • Méthodes d’extension From/To : correction d’un bug : si la chaine spécifiée dans le To n'était pas trouvée, ça renvoyait une chaine vide, au lieu de renvoyer toute la fin de la chaine.
      • Méthode d’extension Truncate : tronque une chaine de caractères à la longueur spécifiée.
    • Classe ReflectionExtensions :
      • Méthodes d'extension SetValue pour PropertyInfo et FieldInfo. Les méthodes "standard" PropertyInfo.SetValue et FieldInfo.SetValue ne fonctionnent pas avec les types valeurs, à cause du boxing. Ces nouvelles méthodes d'extension sont génériques (pour éviter le boxing) et prennent l'instance par référence (pour qu'on modifie bien l'objet d'origine et non une copie). On peut aussi les utiliser avec des types référence, histoire de pas avoir à se poser la question...
        Code C# : Sélectionner tout
        1
        2
        MyStruct obj = new MyStruct(); 
        typeof(MyStruct).GetProperty("Foo").SetValue(ref obj, 42);
    • Classe EncodingExtensions :
      • Méthode d’extension TryGetString : Tente de décoder une chaine de caractères à partir d'un tableau d'octets pour un encodage donné. Renvoie false si des données non valides pour cet encodage sont détectées :
        Code C# : Sélectionner tout
        1
        2
        3
        string text; 
        if (!Encoding.UTF8.TryGetString(bytes, out text)) 
            Console.WriteLine("Données non valides");
      • Méthode d’extension IsValid : Vérifie si un tableau d'octets contient des données valides pour un encodage donné.
    • Classe CoreExtensions :
      • Méthode d'extension PreserveStackTrace : prépare une exception pour la relancer sans perdre la pile d'origine. Normalement, quand on relance dans un catch, il suffit de faire throw;, mais dans certains cas on ne peut pas faire ça (par exemple si on veut relancer la InnerException de l'exception interceptée). Exemple :
        Code C# : Sélectionner tout
        1
        2
        3
        4
        5
        6
        7
        8
            try 
            {	         
                Foo(); 
            } 
            catch (TargetInvocationException ex) 
            { 
                throw ex.InnerException.PreserveStackTrace(); 
            }
    • Classe NumberConverter (conversion de nombres en toutes lettres) :
      • Comme promis lors de la sortie de la version précédente : conversion de nombres en anglais (US et GB) !
        • La langue est choisie automatiquement en fonction de la culture courante si vous utilisez la classe NumberConverter, mais il est possible d’obtenir un convertisseur pour une culture spécifique avec la méthode GetSpeller.
        • Il est possible d’implémenter des convertisseurs pour d’autres langues en implémentant l’interface INumberSpeller

    • Classe OrderedDictionary<TKey, TValue> : un dictionnaire qui maintient l'ordre d'insertion des clés (comme System.Collections.Specialized.OrderedDictionary, mais en générique)
    • Classe XmlDumper : une sorte de sérialiseur XML simplifié, qui permet de convertir à peu près n’importe quel objet en XML. Ça peut être utile pour générer facilement du XML avec une structure libre à partir d’un objet anonyme, par exemple :
      Code C# : Sélectionner tout
      1
      2
      3
      4
      5
      6
      7
      var toto = new 
      { 
          Foo = 42, 
          Bar = "Hello world", 
          Baz = new { X = 50, Y = 100 } 
      }; 
      var xml = XmlDumper.ToXml(toto, "Toto");
      Ce qui donne le XML suivant :
      Code XML : Sélectionner tout
      1
      2
      3
      <Toto Foo="42" Bar="Hello world"> 
        <Baz X="50" Y="100" /> 
      </Toto>
      Bien sûr, ce n’est pas un remplacement de la "vraie" serialization XML... Ca ne permet pas de contrôler le schema XML généré, ni de reconvertir le XML en un objet. Mais c’est utile dans certains cas, par exemple pour générer un log XML sans schéma strict.
    • Classe DataProtectionProvider : fournit un moyen de chiffrer des données (texte ou binaire) sans avoir à gérer une clé de chiffrage. Ca se base sur la Data Protection API de Windows (via la classe ProtectedData). Les données chiffrées ne sont déchiffrables que par l'utilisateur qui les a chiffrées, ou un utilisateur sur la même machine (selon les paramètres utilisés). Pratique pour stocker des mots de passe de connexion par exemple…
      Code C# : Sélectionner tout
      1
      2
      3
      var provider = new DataProtectionProvider(); 
      string password = "hello world"; 
      string protectedPassword = provider.ProtectString(password);
    • Classe LocalizedDescriptionAttribute : comme DescriptionAttribute, mais permet de spécifier une clé de ressource plutôt qu'un texte en dur, de façon à avoir une description localisée.
  • Assembly Developpez.Dotnet.System :
    • Propriété SystemInfos.ThemeInfo : renvoie des infos sur le thème (Aero, Luna, etc) utilisé par le système
  • Assembly Developpez.Dotnet.Windows (WPF) :
    • Classe RatingControl : corrigé les images par défaut (le fond n'était pas transparent, si bien que changer la couleur de fond du contrôle n'avait pas d'effet visible)
    • Classe FormView : contrôle permettant d’afficher et éditer les propriétés d’un objet sous forme de formulaire (comme avec les DetailsView et FormView d'ASP.NET). Il y a quelques types de champ prédéfinis (TextFormField, ComboBoxFormField, CheckBoxFormField), et on peut facilement créer des champs personnalisés en spécifiant le template manuellement :
      Code XAML : Sélectionner tout
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      <dvp:FormView IsInEditMode="True" DataContext="{Binding Movie}"> 
          <dvp:TextFormField Header="Title" Binding="{Binding Title}" /> 
          <dvp:ComboBoxFormField Header="Media type" Binding="{Binding MediaType}" ItemsSource="{dvp:EnumValues local:MediaType}" /> 
          <dvp:ComboBoxFormField Header="Director" Binding="{Binding Director}" ItemsSource="{Binding DataContext.Directors, ElementName=root}" DisplayMemberPath="Name" /> 
          <dvp:CheckBoxFormField Header="In stock" Binding="{Binding InStock}" /> 
          <dvp:FormField Header="Rating"> 
              <dvp:FormField.EditorTemplate> 
                  <DataTemplate> 
                      <dvp:RatingControl Value="{Binding Rating}" 
                                         RatingMode="Decimal" 
                                         Stretch="None" HorizontalAlignment="Left"/> 
                  </DataTemplate> 
              </dvp:FormField.EditorTemplate> 
          </dvp:FormField> 
          <dvp:FormField Header="Release date"> 
              <dvp:FormField.EditorTemplate> 
                  <DataTemplate> 
                      <DatePicker SelectedDate="{Binding ReleaseDate}" /> 
                  </DataTemplate> 
              </dvp:FormField.EditorTemplate> 
          </dvp:FormField> 
      </dvp:FormView>
      Résultat :
    • Classe ErrorProvider : fournit des propriétés attachées pour mettre en valeur une erreur de saisie (dans un formulaire par exemple). Ce système est plus souple et plus léger à mettre en œuvre que le mécanisme existant dans WPF. L’approche ressemble un peu à celle du composant ErrorProvider de WinForms, sauf qu'on peut l'utiliser en XAML. Ce code :
      Code XAML : Sélectionner tout
      1
      2
      3
      4
      5
      6
      7
      8
      9
              <Label Grid.Row="0" Grid.Column="0" Content="Name" /> 
              <TextBox Grid.Row="0" Grid.Column="1" 
                       Text="{Binding Name}" 
                       dvp:ErrorProvider.ErrorMessage="{Binding Errors[Name]}" /> 
        
              <Label Grid.Row="1" Grid.Column="0" Content="Age" /> 
              <TextBox Grid.Row="1" Grid.Column="1" 
                       Text="{Binding Age}" 
                       dvp:ErrorProvider.ErrorMessage="{Binding Errors[Age]}" />
      Donne le résultat suivant :

      On peut aussi changer l'icône d'erreur, et son positionnement.
    • Classe ViewModelBase :
      • Méthode SetProperty : facilite les notifications de changement de valeur des propriétés. Au lieu d’écrire ça :
        Code C# : Sélectionner tout
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        private string _name; 
        public string Name 
        { 
            get { return _name; } 
            set 
            { 
                if (value != _name) 
                { 
                    _name = value; 
                    OnPropertyChanged("Name"); 
                } 
            } 
        }
        On peut maintenant écrire ça, pour obtenir le même effet :
        Code C# : Sélectionner tout
        1
        2
        3
        4
        5
        6
        private string _name; 
        public string Name 
        { 
            get { return _name; } 
            set { SetProperty(ref _name, value, "Name"); } 
        }
    • Classe ViewModelExtensions :
      • Méthode InitializeViewModelCommands : fournit un mécanisme pour initialiser automatiquement les commandes d'un ViewModel, en décorant avec des attributs les méthodes qui implémentent les commandes. Cela évite pas mal de code de plomberie...
        Code C# : Sélectionner tout
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        public class MyViewModel : ViewModelBase 
        { 
            public MyViewModel() 
            { 
                this.InitializeViewModelCommands(); 
            } 
          
            public ICommand FooCommand { get; set; } 
            public ICommand BarCommand { get; set; } 
          
            // Nom de la commande déterminé automatiquement 
            // Convention : nom de la commande = nom de la méthode + "Command" 
            [CommandExecute] 
            private void Foo() 
            { 
            } 
          
            // Nom de la commande spécifié explicitement 
            [CommandExecute("BarCommand")] 
            private void ExecuteBar () 
            { 
            } 
          
            [CommandCanExecute("BarCommand")] 
            private bool CanExecuteBar() 
            { 
                return true; 
            } 
        }

    • Classe CollectionViewShaper : permet la mise en forme (groupement, tri, filtrage) d'une CollectionView à l'aide de Linq (plus de détails ici), via des méthodes d’extension. Par exemple, si une ListView est bindée sur la collection People, on peut gérer la mise en forme comme ceci :
      Code C# : Sélectionner tout
      1
      2
      3
      4
      5
      6
      7
      var query = 
          from p in People.ShapeView() 
          where p.Age >= 18 
          orderby p.LastName, p.FirstName 
          group p by p.Country; 
        
      query.Apply();
    • Classe ImageBehavior (affichage d’image GIF animée) : correction de bugs :
      • Certains fichiers GIF ne contiennent pas l’image entière dans chaque frame, mais seulement la partie qui change. Ce cas est maintenant géré correctement
      • Les métadonnées de l’image (délai, positionnement etc) ne pouvaient pas être lues sous Windows XP à cause d’une limitation de l’OS. Ce problème est maintenant résolu en décodant manuellement les métadonnées.
    • Classe ListBoxBehavior : fournit des fonctionnalités supplémentaires pour le contrôle ListBox
      • Propriété attachée SelectedItems : permet de binder la propriété SelectedItems de la ListBox (qui est normalement en lecture seule) pour gérer la multisélection en MVVM. Il faut juste créer une collection dans le ViewModel, et le behavior se charge de la synchroniser avec le SelectedItems de la ListBox :
        Code XAML : Sélectionner tout
        1
        2
        3
        <ListBox ItemsSource="{Binding Items}" 
                 DisplayMemberPath="Name" 
                 dvp:ListBoxBehavior.SelectedItems="{Binding SelectedItems}" />
    • Classe TextBlockBehavior : fournit des fonctionnalités supplémentaires pour le contrôle TextBlock
      • Propriété attachée RichText : permet d'afficher dynamiquement du texte riche dans un TextBlock, via une chaine qui contient du XAML. Cela permet notamment de localiser du texte mis en forme
        Code XAML : Sélectionner tout
        <TextBlock dvp:TextBlockBehavior.RichText="{Binding MessageWithRichXamlText}" />

  • Assembly Developpez.Dotnet.Windows.Forms (Windows Forms):
    • Classe WinFormsExtensions
      • Méthode d’extension ApplyResources : permet d'appliquer à la volée les ressources localisées d'une Form ou d'un UserControl quand on change de langue, sans avoir à recréer la Form :
        Code C# : Sélectionner tout
        1
        2
        3
        4
        5
        void SelectLanguage(string language) 
        { 
            Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(language); 
            this.ApplyResources(); 
        }
      • Méthode d’extension InvokeIfRequired : exécute une action sur le thread de l'UI, en utilisant Invoke si nécessaire :
        Code C# : Sélectionner tout
        1
        2
        3
        4
        5
        6
        7
        8
        9
        // Exécuté dans un worker thread... 
        void Countdown() 
        { 
            for (int i = 10; i >= 0; i--) 
            { 
                Thread.Sleep(1000); 
                label1.InvokeIfRequired(() => label1.Text = i.ToString()); 
            } 
        }

  • Assembly Developpez.Dotnet.Drawing (GDI, librairie graphique de Windows Forms) :
    • Classe BitmapExtensions :
      • Méthode d'extension TransformColors : applique une matrice de transformation de couleurs à une image. Les transformations les plus courantes sont prédéfinies :
        Code C# : Sélectionner tout
        1
        2
        3
        4
        5
        6
        // Niveaux de gris 
        image.TransformColors(ColorTransforms.GrayScale); 
        // Négatif 
        image.TransformColors(ColorTransforms.Negative); 
        // Sepia 
        image.TransformColors(ColorTransforms.Sepia);
        Résultats :





J'espère que toutes ces nouveautés vous seront utiles ! N'hésitez pas à nous suggérer des nouveautés et à signaler les bugs sur le gestionnaire de projet

Téléchargements


Vous avez aimé cette actualité ? Alors partagez-la avec vos amis en cliquant sur les boutons ci-dessous :


 Poster une réponse

Avatar de stailer stailer - Membre chevronné https://www.developpez.com
le 16/01/2012 à 13:59
Très utiles ! j'aime beaucoup les nouveautés, notamment les ViewsModels et le CollectionView pour mes dévs en Silverlight.

Merci beaucoup pour cette librairie gratuite !
Avatar de alex_vino alex_vino - Membre émérite https://www.developpez.com
le 16/01/2012 à 14:12
Merci infiniment tomlev, excellent travail

Est-il possible de proposer de nouvelles extensions ? Si oui, comment ?
Avatar de tomlev tomlev - Rédacteur/Modérateur https://www.developpez.com
le 16/01/2012 à 14:16
Citation Envoyé par alex_vino  Voir le message
Est-il possible de proposer de nouvelles extensions ? Si oui, comment ?

Salut,

Tu peux proposer tes contributions sur le forum du projet, ou sur le forum Contribuez de la rubrique .NET
Offres d'emploi IT
Développeur WEB PHP F/H
VACALIANS GROUP - Languedoc Roussillon - SETE (34)
Développeur Web FULL-STACK
VACALIANS GROUP - Languedoc Roussillon - SETE (34)
RESPONSABLE WEB ANALYTICS F/H
VACALIANS GROUP - Languedoc Roussillon - SETE (34)

Voir plus d'offres Voir la carte des offres IT
Responsable bénévole de la rubrique Microsoft DotNET : Hinault Romaric -