Sortie de la version 0.5 de Dvp.NET
La version 0.5 de la librairie Dvp.NET est disponible !
http://dvp-net.developpez.com/images/logo-dvp.net.png
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 :
- Classe TextWriterExtensions :
- http://dvp-net.developpez.com/images/new.png Méthode d’extension Tee : comme StreamExtensions.Tee, mais pour les TextWriter. Exemple :
Code:
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 :
- http://dvp-net.developpez.com/images/bug.png 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)
- http://dvp-net.developpez.com/images/new.png 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)
- http://dvp-net.developpez.com/images/new.png 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)
- http://dvp-net.developpez.com/images/bug.png Méthode d’extension TakeLast : optimisation du cas où la collection implémente IList<TSource>
- http://dvp-net.developpez.com/images/new.png 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:
var totalDistance = cities.AggregateByPairs(0, (sum, a, b) => sum + Distance(a, b))
- http://dvp-net.developpez.com/images/new.png Méthode d’extension SequenceEqualBy : comme SequenceEqual, mais permet de spécifier le critère d'égalité :
Code:
1 2 3 4 5
| // Comparaison des listes selon l'id des éléments:
if (list1.SequenceEqualBy(list2, x => x.Id))
{
...
} |
- http://dvp-net.developpez.com/images/new.png Méthode d’extension Replace : remplace l'élément spécifié de la séquence par un autre :
Code:
list.Replace("foo", "bar");
- http://dvp-net.developpez.com/images/new.png 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:
1 2 3
| var input = new[] { "foo", "baz", "bar", "baz" };
var result = input.InsertAfter("baz", "zoo");
// result = { "foo", "baz", "zoo", "bar", "baz", "zoo" } |
- http://dvp-net.developpez.com/images/new.png 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:
1 2 3
| var input = new[] { "foo", "baz", "bar", "baz" };
var result = input.InsertAfterFirst("baz", "zoo");
// result = { "foo", "baz", "zoo", "bar", "baz" } |
- http://dvp-net.developpez.com/images/new.png 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:
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
- http://dvp-net.developpez.com/images/new.png 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
- http://dvp-net.developpez.com/images/new.png 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:
1 2 3 4 5 6
| var result =
list1.LeftOuterJoin(
list2,
x1 => x1.Id,
x2 => x2.Id,
(x1, x2) => new { x1, x2 }); |
- Classe DateTimeExtensions :
- Classe StringExtensions :
- Classe ReflectionExtensions :
- http://dvp-net.developpez.com/images/new.png 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:
1 2
| MyStruct obj = new MyStruct();
typeof(MyStruct).GetProperty("Foo").SetValue(ref obj, 42); |
- http://dvp-net.developpez.com/images/new.png 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:
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 :
- http://dvp-net.developpez.com/images/new.png 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:
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) :
- http://dvp-net.developpez.com/images/new.png 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
- http://dvp-net.developpez.com/images/new.png 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)
- http://dvp-net.developpez.com/images/new.png 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:
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:
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. - http://dvp-net.developpez.com/images/new.png 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:
1 2 3
| var provider = new DataProtectionProvider();
string password = "hello world";
string protectedPassword = provider.ProtectString(password); |
- http://dvp-net.developpez.com/images/new.png 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 :
- Assembly Developpez.Dotnet.Windows (WPF) :
- http://dvp-net.developpez.com/images/bug.png 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)
- http://dvp-net.developpez.com/images/new.png 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:
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 :
http://www.developpez.net/forums/att.../formview.png/ - http://dvp-net.developpez.com/images/new.png 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:
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 :
http://www.developpez.net/forums/att...rprovider.png/
On peut aussi changer l'icône d'erreur, et son positionnement. - Classe ViewModelBase :
- http://dvp-net.developpez.com/images/new.png Méthode SetProperty : facilite les notifications de changement de valeur des propriétés. Au lieu d’écrire ça :
Code:
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:
1 2 3 4 5 6
| private string _name;
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value, "Name"); }
} |
- http://dvp-net.developpez.com/images/new.png 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:
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;
}
} |
- http://dvp-net.developpez.com/images/new.png 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:
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 :
- http://dvp-net.developpez.com/images/bug.png 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
- http://dvp-net.developpez.com/images/bug.png 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.
- http://dvp-net.developpez.com/images/new.png 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:
1 2 3
| <ListBox ItemsSource="{Binding Items}"
DisplayMemberPath="Name"
dvp:ListBoxBehavior.SelectedItems="{Binding SelectedItems}" /> |
- http://dvp-net.developpez.com/images/new.png 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:
<TextBlock dvp:TextBlockBehavior.RichText="{Binding MessageWithRichXamlText}" />
- Assembly Developpez.Dotnet.Windows.Forms (Windows Forms):
- Classe WinFormsExtensions
- http://dvp-net.developpez.com/images/new.png 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:
1 2 3 4 5
| void SelectLanguage(string language)
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(language);
this.ApplyResources();
} |
- http://dvp-net.developpez.com/images/new.png Méthode d’extension InvokeIfRequired : exécute une action sur le thread de l'UI, en utilisant Invoke si nécessaire :
Code:
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 :
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