Let There Be Code RSS 2.0
# Monday, July 05, 2010

Je viens de publier un nouvel article sur le développement 32bits et 64bits.

Avec l’arrivée du Framework 4.0 et de Visual Studio 2010, Microsoft a fait de gros effort sur le développement d’applications 64bits avec Visual Studio 2010. Patrice Lamarche nous livre dans ce billet l’un des changements majeur concernant la politique de compilation de vos projets UI avec Visual Studio 2010.

Au-delà de l’IDE, le Framework 4.0, et plus précisément la classe System.Environment, nous fournit des propriétés permettant de savoir si l’OS est en 32 ou 64bits, ou de récupérer le répertoire Program File (x86) ou encore le répertoire Windows\SYSWOW64…

Quelles sont les différences entre ces OS ? Comment des applications 32 bits et 64 bits cohabitent ? Comment les prendre en compte dans nos développements ?

Monday, July 05, 2010 8:23:06 AM (Romance Daylight Time, UTC+02:00)  #    Voir Commentaires
C# | Visual Studio
# Saturday, May 15, 2010

image

Parmi les nombreuses nouveautés du développement d’addin VSTO, nous retrouvons bien évidemment le Ribbon, qui est maintenant disponible depuis l’Explorer d’Outlook 2010. A l’ombre de cette grande nouveauté, d’autres font leur apparition mais passent un peu inaperçu.  

Dans le développement d’addin VSTO pour Outlook 2010, il est aujourd’hui possible de définir des icones personnalisées pour certains répertoires.  Comme vous pouvez le voir sur l’image ci-contre, j’ai défini une icône custom pour 2 de mes répertoires. La classe MAPIFolder possède maintenant une méthode SetCustomIcon qui prend en paramètre une instance de la classe StdPicture :

  1. /// <summary>
  2. /// Sets a custom icon that is specified by Picture for the folder
  3. /// </summary>
  4. /// <param name="Picture">Specifies the custom icon for the folder</param>
  5. void SetCustomIcon(stdole.StdPicture Picture);

 

 

Afin d’obtenir une instance de type StdPicture à partir d’un objet de type Bitmap (ou Image), il faut créer une classe qui hérite de AxHost. Cette classe est un wrapper de contrôle ActiveX et possède une méthode statique (et protected) qui se nomme GetIPictureDispFromPicture :

  1. sealed public class ConvertImage : System.Windows.Forms.AxHost
  2. {
  3.     private ConvertImage()
  4.         : base(null)
  5.     {
  6.     }
  7.     public static stdole.StdPicture ConvertToStdPicture(System.Drawing.Image image)
  8.     {
  9.         return (stdole.StdPicture)GetIPictureDispFromPicture(image);
  10.     }
  11. }

Le tour est joué, il n’y a plus qu’à faire appel à la méthode SetCustomIcon :

  1. private void SetCustomIcon(MAPIFolder folder, System.Drawing.Bitmap image)
  2. {
  3.     folder.SetCustomIcon(ConvertImage.ConvertToStdPicture(image));
  4. }
Saturday, May 15, 2010 5:03:02 PM (Romance Daylight Time, UTC+02:00)  #    Voir Commentaires
C# | VSTO
# Tuesday, December 08, 2009

Si vous avez déjà fait de la Reflection alors vous connaissez surement la méthode GetCustomAttributes(bool inherit) de la classe MemberInfo qui permet de retrouver la liste des attributs d’un membre d’un type.

 

Comme vous vous en doutez le paramètre booléen inherit permet d’indiquer au framework s’il doit rechercher également dans les types de base (du style vous avez une propriété abstraite avec des attributs dans la classe de base, et cette propriété est « overridée » dans une classe fille).

Vous écrivez le code d’appel à la méthode GetCustomAttributes, vous exécutez et vous remarquez que l’attribut de la classe de base n’est pas trouvé.

 

Un petit tour sur la msdn : http://msdn.microsoft.com/en-us/library/kff8s254.aspx  

D’après la msdn voici à quoi sert le paramètre booléen inherit : 

 

image 

 

C’est donc bien ce que nous avions compris… le booléen permet d’indiquer que l’on veut également récupérer les attributs du membre des types de base.

L’exemple donné sur la msdn confirme bien l’utilisation de ce paramètre :

 

image 

 

Là je me pose la question : c’est quoi l’arnaque ? Qu’est-ce que j’ai pu louper dans l’utilisation de cette méthode ?

 

Comme d’habitude, qui vient à mon secours dans ces moments là ? Reflector!

Et là c’est l’hallu… Je vous laisse en juger par vous même :

 

clip_image001 

 

Eh oui vous voyez comme moi, le paramètre bool inherit n’est pas utilisé… en fait ici il ne sert à rien…

Certains diront que c’est un bug. Moi je préfère dire que ce n’en ai pas un, que c’est juste une méthode qui n’est pas tout à fait terminée… chez moi j’appelle ça un bug normal, mais peu importe.

 

Heureusement il y a toujours une solution !! Il suffit d’utiliser la méthode statique System.Attribute.GetCustomAttributes(MemberInfo m, bool inherit).  

Comme vous pouvez le voir ci-dessous celle-ci fait bien ce qu’on lui demande de faire :

 

clip_image005 

 

Ce genre d’oubli me rassure tout de même, car je me dis que finalement ce sont des hommes comme vous et moi qui codent le framework.

Tuesday, December 08, 2009 5:10:02 PM (Romance Standard Time, UTC+01:00)  #    Voir Commentaires
C# | Framework .Net
# Thursday, November 05, 2009

Après les collections de projets, une autre évolution de TFS 2010 c’est la possibilité d’organiser les requêtes d’un projet dans un arbre de répertoires.

SDK TFS 2008 et la classe StoredQueryCollection :

Avec TFS 2008, nous avons juste la possibilité de ranger les requêtes par “Team Queries” et My Queries”. Il est donc assez facile de créer une combobox présentant la liste des requêtes d’un projet afin d’en sélectionner une et d’en afficher le résultat :

queryCombo

La récupération des requêtes se fait depuis la classe Project par la propriété StoredQueries qui nous retourne une instance de StoredQueryCollection :

WorkItemStore store = new WorkItemStore("serverName");
Project project = store.Projects["projectName"];
StoredQueryCollection storedQueries = project.StoredQueries;

Pour remplir notre combobox il suffit de parcourir une première fois la liste StoredQueryCollection afin de récupérer les requêtes publique (Team Queries) puis une seconde fois pour récupérer les requêtes privées (My Queries) :

this.comboBox1.Items.Add(new QueryItem("  ----- Team Queries -----"));
foreach (StoredQuery query in storedQueries)
{
	if (query.QueryScope == QueryScope.Public)
    {
    	this.comboBox1.Items.Add(new QueryItem(query));
    }
}

this.comboBox1.Items.Add(new QueryItem("  ----- Private Queries -----")); 
foreach (StoredQuery query2 in storedQueries)
{
	if (query2.QueryScope != QueryScope.Public)
    {
	    this.comboBox1.Items.Add(new QueryItem(query2));
    }
}

SDK TFS 2010 et la classe QueryHierarchy :

Aujourd’hui avec TFS 2010 nous avons la possibilité de mieux ordonner les requêtes d’un projet. Le treeview du TeamExplorer illustre bien la nouvelle organisation des requêtes :

TeamExplorerQueryHierarchy

Dans cet exemple nous allons recréer ce treeview. Mais tout d’abord, intéressons-nous au modèle objets du TFS SDK 2010.

Le diagramme ci-dessous montre que le modèle objets des requêtes est basé sur le pattern Composite. En effet, on retrouve une classe abstraite QueryItem, une classe spécialisée QueryFolder, héritant de QueryItem et possédant une liste de QueryItem et une classe QueryDefinition, qui est la feuille de l’arbre, c’est à dire une requête. Il ne reste plus qu’à parcourir ce graphe d’objets afin de se créer son Treeview.

 

classDiagramQueryHierarchy 

Première chose, récupérer la hiérarchie de requêtes. De la même façon que l’on récupérait la liste des StoredQueries avec le TFS SDK 2008, on va récupérer l’objet QueryHierarchy depuis une instance de Project, puis parcourir cette hiérarchie :

WorkItemStore store = new WorkItemStore(@"serverName\collectionName");
Project project = store.Projects["projectName"];
QueryHierarchy queryHierarchy = project.QueryHierarchy;
LoadQueries(queryHierarchy, null);

La méthode LoadQueries crée d’abord un noeud représentant le répertoire courant puis parcours les sous-éléments. On retrouve ici un appel récursif dans le cas où l’on itère sur un objet de type QueryFolder :

public void LoadQueries(QueryFolder queryFolder, TreeNode parentNode)
{
	TreeNode folderNode = CreateQueryItemNode(queryFoldern parentNode);
	foreach (var item in queryFolder)
    {
    	if (item is QueryFolder)
    		LoadQueries((QueryFolder)item, folderNode);
	    else
    	    CreateQueryItemNode(item, folderNode);
	}
}

La méthode CreateQueryItemNode est assez simple. Il suffit juste de créer un noeud dans le treeview :

private void CreateQueryItemNode(QueryItem query, TreeNode parentNode)
{
	TreeNode queryNode = new TreeNode(query.Name);
	if (parentNode != null)
	    parentNode.Nodes.Add(queryNode);
	else
		this.treeview1.Nodes.Add(queryNode);

	return queryNode;
}

On obtient un treeview semblable à celui du TeamExplorer. Il ne reste plus qu’à ajouter les icônes et à modifier les ImageIndex de chaque noeud. Pour l’améliorer on préférera également un chargement asynchrone et des objets TreeNode spécialisé tel que FolderNode et QueryNode :

image

Tout ceci sera bien sûr disponible dans mon addin Outlook WorkItems Extension en version 2010 prévu (normalement) pour fin novembre.

Thursday, November 05, 2009 9:32:30 AM (Romance Standard Time, UTC+01:00)  #    Voir Commentaires
C# | Outlook Work Items Extension | TFS SDK
# Monday, November 02, 2009

Dans la nouvelle version de TFS, c’est à dire 2010, plusieurs nouveautés sont apparues. Ces nouveautés ont forcément engendré quelques modifications au niveau du SDK de TFS et on peut voir notamment que certaines classes du SDK 2008 sont maintenant obsolètes.

Comme je le disais dans un précédent post, je suis en train de réécrire une nouvelle version de mon addin TFS pour Outlook, Outlook Work Items Extension, pour 2 raisons : ajouter des nouvelles fonctionnalités, mais surtout faire en sorte qu’il fonctionne pour TFS 2010 et TFS 2008. Eh oui, j’ai essayé de l’utiliser en me connectant sur un serveur 2010 et là j’ai eu quelques soucis… Je vais donc essayer de vous expliquer quels sont les points bloquants et comment je migre mon code.

1ère étape : Mise à jour des références

Dans les projets référençant le SDK, supprimer les références du TFS SDK 2008 (version 9.0) par les assembly du SDK 2010 (version 10.0). Après installation de VS 2010 vous trouverez les assemblies dans le GAC, dans \Program Files\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies et dans \Program Files\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0.

Dans mon cas, j’utilise les assemblies suivantes :

  • Microsoft.TeamFoundation.dll
  • Microsoft.TeamFoundation.Client.dll
  • Microsoft.TeamFoundation.WorkItemTracking.Clients.dll
  • Microsoft.TeamFoundation.WorkItemTracking.Controls.dll

Remarque intéressante : les applications utilisant le SDK 2010 vont pouvoir s’exécuter en 64bits puisque contrairement aux SDK 2008, les assemblies de 2010 sont disponible en 32bits mais aussi en 64bits.

2ème étape : Compiler et parcourir les warnings

Cette étape consiste à retrouver tous les warnings concernant l’utilisation de types ou de méthodes obsolètes.

3ème étape : Mettre les mains dans le camboui !

Pour ma part j’utilisais le controle DomainProjectPicker, qui permet d’afficher la boite de dialogue de sélection de Team Projects. Dans la version 2010, cette classe est obsolète. En effet, maintenant dans TFS 2010 il y a la notion de collections de projets, qui n’existait pas dans 2008. Le contrôle de sélection d’un Team Project a donc changé et il faut maintenant utiliser le TeamProjectPicker.

Avec le SDK 2008 j’avais écrit le code suivant :

List<FavoriteTeamProject> favorites = FavoritesTeamProjectManager.GetFavoritesProjects();
using (DomainProjectPicker picker = new DomainProjectPicker(DomainProjectPickerMode.AllowMultiSelect | DomainProjectPickerMode.AllowProjectSelect))
{
	picker.SelectedServer = new TeamFoundationServer("serverName");
    WorkItemStore wis = new WorkItemStore(s);
    ArrayList list = new ArrayList();
    foreach (var project in item)
    {
    	list.Add(wis.Projects["projectName"].Uri.ToString());
	}
    picker.DefaultSelectedProjects = new SortedList();
    picker.DefaultSelectedProjects.Add(s.Uri.ToString(), list);
	
	if (picker.ShowDialog() == DialogResult.OK)
    {
    	var selectedProjects = picker.SelectedProjects;
	}
}
Avec le SDK de TFS 2010 il faut utiliser le contrôle TeamProjectPicker.

  • L’initialisation du serveur TFS sélectionné par défaut se fait via la propriété SelectedTeamProjectCollection, en lui fournissant le nom du serveur et la collection: serverName\collectionName.
  • L’initialisation des projets sélectionnés via une simple liste de ProjectInfo que l’on affecte à la propriété SelectedProjects du picker

using (TeamProjectPicker picker = new TeamProjectPicker(TeamProjectPickerMode.MultiProject, false))
{
	picker.SelectedTeamProjectCollection = new TeamFoundationServer(@"serverName\collectionName");
	List<ProjectInfo> list = new List<ProjectInfo>();
    ProjectInfo pi = new ProjectInfo("projectUri", "projectName", ProjectState.WellFormed);
    list.Add(pi);
	picker.SelectedProjects = list.ToArray();
    
	if (picker.ShowDialog() == DialogResult.OK)
    {
    	var selectedProjects = picker.SelectedProjects;
	}
}

Dans le prochain post nous verrons comment migrer l’utilisation des requêtes qui se faisait avec la classe StoredQuery avec le SDK 2008 et qui se fait maintenant avec les classes QueryHierarchy, QueryFolder et QueryDefinition pour le SDK 2010.

Monday, November 02, 2009 1:36:59 AM (Romance Standard Time, UTC+01:00)  #    Voir Commentaires
C# | Outlook Work Items Extension | TFS | TFS SDK
# Wednesday, October 28, 2009

Voici une petite méthode d’extension qui permet d’effectuer une recherche de manière récursive dans un treeview en lui spécifiant un prédicat :

public static class TreeNodeExtension
{
	public static IEnumerable<TreeNode> FindNodes(this TreeNodeCollection nodesCollection, Func<TreeNode, bool> predicate)
	{
		var nodes = nodesCollection.Cast<TreeNode>();
		return nodes.SelectMany(n => FindNodes(n.Nodes, predicate).Union(nodes.Where(n2 => predicate(n2))));
	}
}
Le SelectMany permet de mettre à plat l’appel récursif. Si on utilise un Select à la place du SelectMany on obtient une liste de liste de nœud. Le SelectMany est l’équivalent de 2 from comme ceci :
return 	from n in nodes
		from child in n.Nodes
		where predicate(child)
		select child;

Pour l’utiliser ce n’est pas bien compliqué…

Je voudrai récupérer la liste des TreeNode de type FileNode et qui sont sélectionnés :

var checkedFilesNode = treeView1.Nodes.FindNodes(n => n is FileNode && n.Checked == true);
Wednesday, October 28, 2009 12:18:07 PM (Romance Standard Time, UTC+01:00)  #    Voir Commentaires
C# | Linq
Archive
<August 2010>
SunMonTueWedThuFriSat
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
Benoît Laut
Sign In
All Content © 2010, Benoît Laut
DasBlog theme 'Business' created by Christoph De Baene (delarou)