Depuis Silverlight 4, l’une des nouveautés au niveau du binding concerne la possibilité de l’appliquer directement au niveau des DependencyObjects et non plus seulement aux FrameworkElements.
Concrètement, cela signifie qu’il est maintenant possible d’écrire ce genre ce code:
1: <Rectangle Fill="Red"
2: x:Name="rect"
3: Height="50"
4: Width="100"
5: RenderTransformOrigin="0.5,0.5"
6: Grid.Row="0">
7: <Rectangle.RenderTransform>
8: <RotateTransform Angle="{Binding ElementName=slider, Path=Value}" />
9: </Rectangle.RenderTransform>
10: </Rectangle>
11:
12: <Slider x:Name="slider"
13: Width="100"
14: Grid.Row="1"
15: Minimum="0"
16: Maximum="180"
17: Value="0" />
Cependant, on peut vouloir réaliser le même genre d’opérations mais directement par code. Traditionnellement, pour faire cela, il faut appeler la méthode SetBinding de l’objet que l’on souhaite binder. Le problème, c’est que les DependencyObjects ne proposent pas cette méthode:
Si l’on souhaite faire son binding par code, il est nécessaire de passer par la méthode SetBinding de la classe BindingOperations:
Une petit tour dans Reflector nous apprend qu’au final, c’est la même chose car la méthode SetBinding, de FrameworkElement, ne fait qu’appeler la méthode SetBinding de BindingOperations:
Tout simple mais bon à savoir 
A+
Avec WCF RIA Services, les DomainServices permettent d’exposer des méthodes qui seront accessibles par le client. De plus, les AuthenticationServices permettent de gérer la sécurité: où aller chercher les informations permettant d’identifier les utilisateurs, etc.
On pourrait tout à fait vouloir utiliser son DomainService directement au sein de son AuthenticationService, comme de la façon suivante par exemple:
1: [EnableClientAccess]
2: public class AuthenticationService : AuthenticationBase<User>
3: {
4: protected override User GetAuthenticatedUser(System.Security.Principal.IPrincipal principal)
5: {
6: var currentUser = base.GetAuthenticatedUser(principal);
7:
8: var membershipUser = Membership.GetUser(principal.Identity.Name, true);
9: currentUser.UserID = (Guid)membershipUser.ProviderUserKey;
10: currentUser.NumberOfDedicaces = this.m_Service != null ? this.m_Service.GetDedicacesCountForUser(currentUser.UserID) : 0;
11:
12: return currentUser;
13: }
14: }
Le problème, c’est que si vous exécutez ce code, vous obtiendrez l’erreur suivante:
Pour corriger ce problème, il est nécessaire d’initialiser le DomainService, en utilisant la méthode Initialize:
1: // Initialize the DomainService
2: this.m_Service.Initialize(this.ServiceContext);
D’ailleurs, si l’on regarde la documentation de la méthode Initialize, on voit qu’il est écrit qu’il est nécessaire d’appeler cette méthode avant de faire appel à une méthode du DomainService:
Une fois cette méthode appelée, il n’y a plus de problèmes 
A+
Il y a quelques temps, je vosu avais donné une solution pour disposer de données en design time lorsque vous développez votre application WPF. L’objectif de cette technique était de faciliter la collaboration entre le développeur et le designer car ce dernier dispose désormais de données (fictives) pour convevoir l’interface de l’application.
Dans la Beta 2 de Visual Studio 2010, Microsoft a rajouté de nouvelles propriétés et une nouvelle MarkupExtension permettant d’exposer des données en design time.
Pour cela, il est nécessaire d’utiliser la propriété d:DataContext et la MarkupExtension nommée d:DesignInstance. Pour les utiliser, il faut commencer par rajouter les namespaces suivant à votre fichier XAML:
1: xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
2: xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
Puis, rajouter cette ligne qui permet d’indiquer que le préfixe “d” ne doit pas être compilé/interprétré à l’exécution:
A présent, on peut indiquer que l’on souhaite disposer de données en design-time:
1: xmlns:DesignTime="clr-namespace:TestDesignTime.ViewModels.DesignTime"
2: d:DataContext="{d:DesignInstance DesignTime:Demo, IsDesignTimeCreatable=True}">
Ainsi, j’indique qu’en mode design, le DataContext de ma fenêtre est affecté par une instance du type Demo qui est dans le répertoire ViewModels.DesignTime. Par contre, en mode runtime, je lui passe une instance du type Demo, qui est dans le répertoire ViewModels:
1: private void Grid_Loaded(object sender, RoutedEventArgs e)
2: {
3: this.DataContext = new Demo();
4: }
Lorsque l’on regarde l’application dans Visual Studio, on voit des données:
Qui sont bien différentes de celles que l’on a en mode runtime:
On peut même avoir les 2 en même temps 
Avec cette nouvelle fonctionnalité, Microsoft tend à améliorer encore plus la collaboration entre les développeurs et les désigners, ainsi qu’à augmentez leur productivité !
Deux liens pour en savoir plus:
A+
Voila une problématique que j’ai rencontré récemment et qui n’est pas aussi simple à régler que ce que l’on pourrait penser. Imaginer que l’on vous demande d’appeler un objet COM (tel que Analysis Services, au moyen de Microsoft.AnalysisServices.AdomdClient) mais qu’on vous impose de faire de l’impersonation (dans un service WCF par exemple) pour que vous puissiez tracer qui exécute la requête MDX.
Ni une, ni deux: vous mettez en place l’impersonation dans votre service WCF. Ainsi, vous commencez par rajouter cette ligne dans votre fichier web.config:
1: <identity impersonate="true" />
Puis, dans votre code, vous récupérer l’Identity de l’utilisateur courant et vous appelez la méthode Impersonate:
1: if (HttpContext.Current != null)
2: {
3: if (HttpContext.Current.User != null)
4: {
5: if (HttpContext.Current.User.Identity != null)
6: {
7: IIdentity identity = HttpContext.Current.User.Identity;
8: WindowsIdentity windowsIdentity = identity as WindowsIdentity;
9: if (windowsIdentity != null)
10: {
11: using (WindowsImpersonationContext wiCtx = windowsIdentity.Impersonate())
12: {
13: // Call to Analysis Services here
14: }
15: }
16: }
17: }
18: }
Vous exécutez votre code et là, en traçant les requêtes, vous vous apercevez que c’est un compte système qui exécute les requêtes: il semble donc y avoir un problème avec votre impersonnation…
En fait, il s’avère que votre code est correct. Le problème, expliqué ici, réside dans le fait que les objets COM utilise un modèle de thread STA (Single Thread Apartment) alors que votre service WCF, en .NET, utilise un modèle de thread MTA (Multithread Apartment). Si vous voulez connaitre la différence, jetez donc un oeil ici: http://stackoverflow.com/questions/127188/could-you-explain-sta-and-mta
Pour résoudre notre problème, la solution est simple: il suffit de créer un nouveau thread et de lui imposer de tourner en STA 
1: theThread = new Thread(new ThreadStart(MySTAThreadStart));
2:
3: // Intialize to an STA so that there will be no thread switch to the STA COM object.
4: theThread.ApartmentState = ApartmentState.STA;
A partir de là, votre code appelera l’objet COM (Analysis Services) avec un modèle de thread STA ce qui permettra de conserver l’impersonnation !
Voila qui, je l’espère, permettra de gagner pas mal de temps à certains d’entre vous 
A+
Il y a eu beaucoup de sessions lors de la PDC 2009 mais parmis celle-ci, j’en attendais une avec plus d’impatience que les autres:
Windows Presentation Foundation 4 Plumbing and Internals
Ayant enfin eu l’occasion de la regarder, je ne saurais que la conseiller à tous les développeurs WPF. Le speaker explique en détails comment fonctionne le binding, comment sont initialisées les propriétés, pourquoi l’interface peut ne pas être réactive (et comment corriger cela), etc…
Vous développez une application WPF et celle-ci est lente à s'exécuter/se lancer ? Vous vous dîtes qu'en WindowsForms, vous n'aviez pas de problèmes donc que la faute revient à la techno ? Et bien vous découvrirez que, souvent, le problème, c'est vous et non la technologie que vous utilisez
(même si, je le conçois, c'est peut-être un peu dur au début).
Bref, une vidéo à ne pas manquer, surtout si vous vous interessez au coeur de la technologie !
A+
Depuis la version 2010, le processus de build de Team Foundation Server a évolué pour utiliser maintenant WF 4 au lieu de ce bon vieux MSBuild.
Ainsi, si l’on souhaite modifier le processus de build, il “suffit” de développer une activité WF 4 et de l’utiliser dans le workflow de build. Pour créer son activité, rien de plus simple: on créé un nouveau projet de type “WF Activity Library” et on rajoute une “Code Activity”:
1: public sealed class HelloWorldActivity : CodeActivity
2: {
3: [Browsable(true)]
4: [DefaultValue(null)]
5: public InArgument<IBuildDetail> CurrentBuild { get; set; }
6:
7: public OutArgument<string> Result { get; set; }
8:
9: protected override void Execute(CodeActivityContext context)
10: {
11: string requestedBy = this.CurrentBuild.Get(context).RequestedBy;
12:
13: context.SetValue(this.Result, "Hello Build Requested By: " + requestedBy);
14: }
15: }
Comme vous pouvez le voir, mon activité est relativement simple: elle prend en paramètres un objet de type IBuildDetail et elle possède un paramètre de retour, de type chaine de caractères.
Dans la méthode Execute, on récupère les informations sur la build en cours et on affecte, au paramètre Result, le nom de la personne qui a demandé la build. Ca y est, notre activité est prête, nous pouvons à présent l’utiliser dans le workflow 
On commence par l’ajouter à la boite à outils:
Attention, pour pouvoir l’ajouter à votre Toolbox, il faut l’ajouter, dans la fenêtre “Choose Toolbox Items” aux activités proposées dans l’onglet “System.Activities Components”:
Puis on la fait glisser/déposer dans le designer du workflow de build:
Comme notre activité manipule un paramètre en entrée, il est nécessaire de lui donner une valeur. Ainsi, dans les propriétés de l’activité, on peut renseigner la valeur “BuildDetail” pour la propriété “CurrentBuild”:
C’est terminé
On sauvegarde et on lance une build: dans le log, on pourra constater que notre activité a correctement été appelée 
Et voila, c’est simple, rapide et très efficace ! Bien sur, l’exemple pris ici est relativement simple mais rien ne vous empêche de faire plus complexe avec, par exemple, des activités asynchrones (AsyncCodeActivity), des activités renvoyant des valeurs (CodeActivity<TResult>), etc..
Note: Ce n’est pas parce que TFS 2010 utilise WF 4 pour le processus de build que vous allez devoir réécrire tous vos scripts MSBuild. En effet, Microsoft a prévu une activité nommée MSBuild qui, comme son nom l’indique, permet d’exécuter une tâche MSBuild au sein d’un workflow de build 

Bon build à tous 
A+
Cela fait maintenant quelques temps que je travaille avec les technologies WPF/Silverlight et je me suis dit qu’il serait bien, pour moi, d’élargir un peu mes domaines d’activités 
Pour cela, je me suis décider à monter en compétences sur un produit qui commence à être bien connu: Team Foundation Server, et plus précisément sur le service de Build.
Je me suis donc créé une jolie VPC avec Visual Studio 2010 Beta 2 et Team Foundation Server 2010 Beta puis j’ai commencé à essayer de faire compiler une petite application par TFS. Et là, c’est le drame: je reçois une bien belle erreur:
TFB210602: Failed to copy
Après avoir cherché sur Internet, j’ai trouvé le post suivant, de Lars Willhelmsen: http://www.larswilhelmsen.com/2009/10/27/tfb210602-failed-to-copy/
Il semblerait que la version actuelle dispose d’un bug relatifs aux paramètres régionaux et que, pour le corriger, il faille coder en dur le chemin vers MSBuild, dans le fichier XAML (fichier qui définit le workflow du processus de build).
Si vous n’avez pas envie de modifier le fichier XAML à la main, Lars propose en téléchargement un fichier que vous pouvez utiliser directement 
A+
J’ai récemment eu besoin de mettre en place un peu de sécurité sur l’un des projets Silverlight sur lequel je travaille. Il fallait faire simple: récupérer l’ensemble des informations de l’utilsiateur connecté.
Pour cela, rien de plus simple: on laisse faire l’authentification Windows qui est nativement gérée par Silverlight 3. Lors de mes tests, qui se faisait avec le serveur Web intégré à Visual Studio (à savoir Cassini), tout se passait bien donc, on passe en production.
Et là, c’est le drame: une fois sur 2, il m’est impossible d’appeler les services WCF utilisés par l’application, car je recevais des erreurs 401 (accès non autorisé).
Après investigations, je suis tombé sur ce site qui m’a finalement donné la raison de l’échec de l’appel des services:
http://developers.de/blogs/damir_dobric/archive/2009/08/22/soap-faults-and-new-network-stack-in-silverlight-3.aspx
La faute revient tout simplement à cette ligne:
1: bool registerResult = WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
A priori tout simple, ce bout de code permet d’indiquer au runtime Silverlight 3 qu’il doit utiliser la “Client HTTP Stack”, plutôt que la “Browser HTTP Stack”, ce qui permet, en cas d’erreur sur un serice WCF, d’avoir le descriptif complet de l’exception plutôt qu'e la fameuse erreur: “Error 404: Not found”.
Cependant, il s’avère que ce bout de code empêche également le proxy de votre service WCF d’envoyer les headers d’authentification ! Du coup, impossible de vous authentifier auprès du service.
Voila, en espérant que cela vous aide et vous évite de perdre trop de temps 
A+
Voici un problème qui, priori, n’en est pas un 
En effet, j’ai récémment eu besoin, dans un plugin utilisé par une application Silverlight utilisant MEF, d’appeler un service WCF. Jusque là, rien de bien sorcier me direz-vous: j’ajoute la référence à mon service et, dans mon plugin, je fais un simple:
1: TheService.Service1Client client = new Service1Client();
Je teste l’application et là, c’est le drame !
Après investigations, il s’avère que c’est parce que l’application principale (qui hoste les plugins) n’as pas de fichier de configuration comportant les informations indiquées dans le fichier de configuration du plugin…
Après quelques recherches sur Internet, je trouve la solution de quelqu’un qui a le même problème en utilisant Prism. Sa solution, simple dans les faits, consiste à ajouter le fichier de configuration du plugin comme lien à l’application principale. Cette solution ne me convenait pas car:
- Mon application principale avait déjà un fichier de configuration
- Je veux que mes plugins soient complètement indépendants les uns des autres et de l’application qui les charges: si celle-ci doit connaitre le contenu des fichiers de configurations des plugins, comment ferais-je le jour où je disposerais d’un plugin tiers ?
Bref, il a donc fallut trouver un idée qui, au final, est simple comme bonjour: puisque les informations (adresse, type de binding, etc.) sont toutes présentes dans le fichier de configuration, pourquoi ne pas y accéder et créer le proxy en lui spécifiant ces informations ?
J’ai donc commencer par mettre le fichier de configuration de mon plugin en Resource puis, à l’aide de la méthode suivante, j’accède à l’adresse du service:
1: /// <summary>
2: /// Reads the address from the file ServiceReferences.ClientConfig.
3: /// </summary>
4: /// <param name="contract">The contract.</param>
5: private static EndpointAddress ReadAddress(string contract)
6: {
7: EndpointAddress result = null;
8:
9: var streamInfo = Application.GetResourceStream(new Uri("/" + GetNameFromFullName(Assembly.GetExecutingAssembly().FullName) + ";component/ServiceReferences.ClientConfig", UriKind.Relative));
10: if (streamInfo != null)
11: {
12: var config = XDocument.Load(streamInfo.Stream);
13: var endpoints = from endpoint in config.Descendants("endpoint")
14: where endpoint.Attribute("contract").Value == contract
15: select new {Address = endpoint.Attribute("address").Value};
16:
17:
18: foreach (var endpoint in endpoints)
19: {
20: result = new EndpointAddress(endpoint.Address);
21: }
22:
23: if (result == null)
24: {
25: throw new InvalidOperationException(string.Format("Cannot create endpoint for contract {0}.", contract));
26: }
27:
28: return result;
29: }
30:
31: throw new InvalidCastException("streamInfo must not be null !");
32: }
33:
34: /// <summary>
35: /// Gets the name from the full name.
36: /// </summary>
37: /// <param name="fullName">The full name.</param>
38: private static string GetNameFromFullName(string fullName)
39: {
40: return fullName.Substring(0, fullName.IndexOf(','));
41: }
Ensuite, il ne reste plus qu’à utiliser cette méthode pour récupérer l’adresse du service et instancier le proxy en lui passant les paramètres:
1: EndpointAddress address = ReadAddress("TheService.Service1");
2: if (address != null)
3: {
4: TheService.Service1Client client = new Service1Client(new BasicHttpBinding(), address);
5: client.SayHelloCompleted += this.client_SayHelloCompleted;
6: client.SayHelloAsync("Thomas");
7: }
Et le tour est joué
Bien sûr, il faut sans doute améliorer cette technique pour qu’elle permette de lire toutes les informations sur le Endpoint (adresse, binding, paramètres de binding, etc.) mais c’est un bon début 
A+
Jamie Rodriguez vient de poster, sur son blog, une liste des nouveautés de WPF relative à la Beta 2 du Framework .NET 4.0:
http://blogs.msdn.com/jaimer/archive/2009/10/23/what-is-new-in-wpf-and-cider-on-the-net-framework-4-and-vs2010-beta-2-release.aspx
Parmis les points intéressants, on peut noter:
- Le support du VisualStateManager pour tous les contrôles
- L’héritage de contexte pour les InputBinding (idéal pour les scénarios utilisant le pattern MVVM): plus besoin de passer par un MarkupExtension personnalisée
- Le support du DataBinding pour les DynamicObjects
- L’intégration de la TaskBar
- Le support complet du MultiTouch
- Et plein de bonnes choses encore !
Pour tout savoir, le mieux restent encore de lire l’article 
A+
J’ai commencé à jouer un peu avec la Beta 2 de Visual Studio 2010 Beta 2 et je dois dire que pour le moment, cela s’annonce plutôt bien: les performances me semblent excellentes et les fonctionnalités annoncées font réver.
Pour preuve: l’intégration de TaskBar de Windows 7 directement au sein de votre application WPF:
Ce n’est qu’un bref aperçu mais qui cela promet 
Je tâcherais, dès que possible, de faire un article relatant les nouveautés de WPF/Silverlight apportées par cette Beta 2 
A+
Je relaye ici une news non technique mais qui peut en intéresser quelques uns. En effet, 6 Octobre 2009, de 10h30 à 11h30, Steve Ballmer (CEO de Microsoft Corporation), échangera pendant près d'une heure avec les développeurs français au cours d'une session de questions-réponses diffusée en direct !
Evénement exceptionnel - Steve Ballmer répond en direct aux questions des développeurs français
Bref, un moment à ne pas manquer si des questions vous mordent la langue 
A+
Imaginons un scénario très simple: je dispose d’une interface graphique me permettant d’afficher une propriété, de type int mais étant en plus nullable:
Si j’exécute directement l’application, la propriété ThePrice n’est pas affectée donc elle prend sa valeur par défaut, à savoir null. Dans ce cas, au niveau de l’interface graphique, on observe le résultat suivant:
Autrement dit, on ne voit…. rien
Ce qu’il serait intéressant, c’est de pouvoir afficher une valeur par défaut, si la propriété ThePrice est nulle. Et pour cela, vous pouvez compter sur la propriété TargetNullValue:
Bien sur, on pourrait parvenir au même résultat en utilisant un convertisseur ou d’autres mécanismes mais bon, pourquoi faire compliqué lorsque l’on peut faire simple 
A+
La majorité des applications que l’on développe au jour le jour doivent forcément, à un moment ou à un autre, afficher des boites de dialogue aux utilisateurs. Que ce soit pour afficher une confirmation, poser une question ou même informer l’utilisateur qu’une exception est survenue: une boite de dialogue est nécessaire.
Dans le cas où l’on utilise le pattern MVVM pour développer ses applications WPF/Silverlight, cette question d’affichage des boites de dialogue est très importante car on souhaite éviter, le plus possible, d’avoir du code spécifique dans les ViewModels de l’application.
Jusqu’a présent, pour réaliser ce genre d’opération, je faisais quelque chose de très simple: j’utilisais une interface (IActions) que j’implémentais au niveau des différentes vues (donc dans le code behind). Puis, au moment d’assigner le DataContext, je passais en paramètre l’instance de la classe qui implémente l’interface (authrement this). Coté ViewModel, je récupérais un objet de type IActions et il ne me restait plus qu’a appeler ces méthodes. Bien que cela fonctionne et ne casse pas le pattern MVVM (je rappelle l’objectif de ce pattern qui n’est pas de n’avoir aucun code behind mais qui est d’avoir le minimum de code beind, celui-ci devant/pouvant être facilement testable), cela ne me plaisait pas vraiment car j’était obligé de modifier chacun des constructeurs de mes ViewModels pour y rajouter un paramètre, etc.
Puis, j’ai (enfin) eu l’occasion de jeter un oeil à Cinch (http://www.codeproject.com/KB/WPF/Cinch.aspx), un framework permettant de simplifier le développement d’applications en utilisant le pattern MVVM. Dans ce framework, l’auteur utilise une technique empruntée à Mark Smith (Mark Smith) pour utiliser un fournisseur de service permettant d’accéder à un ou plusieurs services.
Concrètement, voila comment cela se passe. On comment par créer un ServiceProvider, autrement dit une classe qui va implémenter l’interface IServiceProvider:
/// <summary>
/// This class acts as a resolver for typed services
/// (interfaces and implementations).
/// </summary>
public class ServiceProvider : IServiceProvider
{
#region Data
private readonly Dictionary<Type, object> _services = new Dictionary<Type, object>();
#endregion
#region Public Methods
/// <summary>
/// Clears all services from the resolver list
/// </summary>
public void Clear()
{
if (_services != null && _services.Count > 0)
_services.Clear();
}
/// <summary>
/// Adds a new service to the resolver list
/// </summary>
/// <param name="type">Service Type (typically an interface)</param>
/// <param name="value">Object that implements service</param>
public void Add(Type type, object value)
{
if (type == null)
throw new ArgumentNullException("type");
if (value == null)
throw new ArgumentNullException("value");
lock (_services)
{
// Replacing existing service
if (_services.ContainsKey(type))
_services[type] = value;
// Adding new service
else
_services.Add(type, value);
}
}
/// <summary>
/// Remove a service
/// </summary>
/// <param name="type">Type to remove</param>
public void Remove(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
lock (_services)
{
_services.Remove(type);
}
}
/// <summary>
/// This resolves a service type and returns the implementation. Note that this
/// assumes the key used to register the object is of the appropriate type or
/// this method will throw an InvalidCastException!
/// </summary>
/// <typeparam name="T">Type to resolve</typeparam>
/// <returns>Implementation</returns>
public T Resolve<T>()
{
return (T)GetService(typeof(T));
}
/// <summary>
/// Implementation of IServiceProvider
/// </summary>
/// <param name="serviceType">Service Type</param>
/// <returns>Object implementing service</returns>
public object GetService(Type serviceType)
{
lock (_services)
{
object value;
return _services.TryGetValue(serviceType, out value) ? value : null;
}
}
#endregion
}
A présent, il faut écrire l’interface qui sera exposée et qui va contenir les différentes méthodes utilisables:
/// <summary>
/// Available Button options.
/// Abstracted to allow some level of UI Agnosticness
/// </summary>
public enum CustomDialogButtons
{
Ok,
OkCancel,
YesNo,
YesNoCancel
}
/// <summary>
/// Available Icon options.
/// Abstracted to allow some level of UI Agnosticness
/// </summary>
public enum CustomDialogIcons
{
None,
Information,
Question,
Exclamation,
Stop,
Warning
}
/// <summary>
/// Available DialogResults options.
/// Abstracted to allow some level of UI Agnosticness
/// </summary>
public enum CustomDialogResults
{
None,
Ok,
Cancel,
Yes,
No
}
/// <summary>
/// This interface defines a interface that will allow
/// a ViewModel to show a messagebox
/// </summary>
public interface IMessageBoxService
{
/// <summary>
/// Shows an error message
/// </summary>
/// <param name="message">The error message</param>
void ShowError(string message);
/// <summary>
/// Shows an information message
/// </summary>
/// <param name="message">The information message</param>
void ShowInformation(string message);
/// <summary>
/// Shows an warning message
/// </summary>
/// <param name="message">The warning message</param>
void ShowWarning(string message);
/// <summary>
/// Displays a Yes/No dialog and returns the user input.
/// </summary>
/// <param name="message">The message to be displayed.</param>
/// <param name="icon">The icon to be displayed.</param>
/// <returns>User selection.</returns>
CustomDialogResults ShowYesNo(string message, CustomDialogIcons icon);
/// <summary>
/// Displays a Yes/No/Cancel dialog and returns the user input.
/// </summary>
/// <param name="message">The message to be displayed.</param>
/// <param name="icon">The icon to be displayed.</param>
/// <returns>User selection.</returns>
CustomDialogResults ShowYesNoCancel(string message, CustomDialogIcons icon);
/// <summary>
/// Displays a OK/Cancel dialog and returns the user input.
/// </summary>
/// <param name="message">The message to be displayed.</param>
/// <param name="icon">The icon to be displayed.</param>
/// <returns>User selection.</returns>
CustomDialogResults ShowOkCancel(string message, CustomDialogIcons icon);
}
A noter que si vous désirez empoyer cette technique avec Silverlight, vous devrez adapter le code ci-dessus car les boites de dialogues Silverlight ne permettent pas d’afficher des images ou ne renvoit, comme valeur de retour, que OK et Cancel.
Maintenant que l’interface est définie, il reste à l’implémenter, ce que nous allons faire dans la classe suivante:
/// <summary>
/// This class implements the IMessageBoxService for WPF purposes.
/// </summary>
public class MessageBoxService : IMessageBoxService
{
#region IMessageBoxService Members
/// <summary>
/// Displays an error dialog with a given message.
/// </summary>
/// <param name="message">The message to be displayed.</param>
public void ShowError(string message)
{
ShowMessage(message, "Error", CustomDialogIcons.Stop);
}
/// <summary>
/// Displays an error dialog with a given message.
/// </summary>
/// <param name="message">The message to be displayed.</param>
public void ShowInformation(string message)
{
ShowMessage(message, "Information", CustomDialogIcons.Information);
}
/// <summary>
/// Displays an error dialog with a given message.
/// </summary>
/// <param name="message">The message to be displayed.</param>
public void ShowWarning(string message)
{
ShowMessage(message, "Warning", CustomDialogIcons.Warning);
}
/// <summary>
/// Displays a Yes/No dialog and returns the user input.
/// </summary>
/// <param name="message">The message to be displayed.</param>
/// <param name="icon">The icon to be displayed.</param>
/// <returns>User selection.</returns>
public CustomDialogResults ShowYesNo(string message, CustomDialogIcons icon)
{
return ShowQuestionWithButton(message, icon, CustomDialogButtons.YesNo);
}
/// <summary>
/// Displays a Yes/No/Cancel dialog and returns the user input.
/// </summary>
/// <param name="message">The message to be displayed.</param>
/// <param name="icon">The icon to be displayed.</param>
/// <returns>User selection.</returns>
public CustomDialogResults ShowYesNoCancel(string message, CustomDialogIcons icon)
{
return ShowQuestionWithButton(message, icon, CustomDialogButtons.YesNoCancel);
}
/// <summary>
/// Displays a OK/Cancel dialog and returns the user input.
/// </summary>
/// <param name="message">The message to be displayed.</param>
/// <param name="icon">The icon to be displayed.</param>
/// <returns>User selection.</returns>
public CustomDialogResults ShowOkCancel(string message, CustomDialogIcons icon)
{
return ShowQuestionWithButton(message, icon, CustomDialogButtons.OkCancel);
}
#endregion
#region Private Methods
/// <summary>
/// Shows a standard System.Windows.MessageBox using the parameters requested
/// </summary>
/// <param name="message">The message to be displayed.</param>
/// <param name="heading">The heading to be displayed</param>
/// <param name="icon">The icon to be displayed.</param>
private static void ShowMessage(string message, string heading, CustomDialogIcons icon)
{
MessageBox.Show(message, heading, MessageBoxButton.OK, GetImage(icon));
}
/// <summary>
/// Shows a standard System.Windows.MessageBox using the parameters requested
/// but will return a translated result to enable adhere to the IMessageBoxService
/// implementation required.
///
/// This abstraction allows for different frameworks to use the same ViewModels but supply
/// alternative implementations of core service interfaces
/// </summary>
/// <param name="message">The message to be displayed.</param>
/// <param name="icon">The icon to be displayed.</param>
/// <param name="button"></param>
/// <returns>CustomDialogResults results to use</returns>
private static CustomDialogResults ShowQuestionWithButton(string message, CustomDialogIcons icon, CustomDialogButtons button)
{
MessageBoxResult result = MessageBox.Show(message, "Please confirm...", GetButton(button), GetImage(icon));
return GetResult(result);
}
/// <summary>
/// Translates a CustomDialogIcons into a standard WPF System.Windows.MessageBox MessageBoxImage.
/// This abstraction allows for different frameworks to use the same ViewModels but supply
/// alternative implementations of core service interfaces
/// </summary>
/// <param name="icon">The icon to be displayed.</param>
/// <returns>A standard WPF System.Windows.MessageBox MessageBoxImage</returns>
private static MessageBoxImage GetImage(CustomDialogIcons icon)
{
MessageBoxImage image = MessageBoxImage.None;
switch (icon)
{
case CustomDialogIcons.Information:
image = MessageBoxImage.Information;
break;
case CustomDialogIcons.Question:
image = MessageBoxImage.Question;
break;
case CustomDialogIcons.Exclamation:
image = MessageBoxImage.Exclamation;
break;
case CustomDialogIcons.Stop:
image = MessageBoxImage.Stop;
break;
case CustomDialogIcons.Warning:
image = MessageBoxImage.Warning;
break;
}
return image;
}
/// <summary>
/// Translates a CustomDialogButtons into a standard WPF System.Windows.MessageBox MessageBoxButton.
/// This abstraction allows for different frameworks to use the same ViewModels but supply
/// alternative implementations of core service interfaces
/// </summary>
/// <param name="btn">The button type to be displayed.</param>
/// <returns>A standard WPF System.Windows.MessageBox MessageBoxButton</returns>
private static MessageBoxButton GetButton(CustomDialogButtons btn)
{
MessageBoxButton button = MessageBoxButton.OK;
switch (btn)
{
case CustomDialogButtons.Ok:
button = MessageBoxButton.OK;
break;
case CustomDialogButtons.OkCancel:
button = MessageBoxButton.OKCancel;
break;
case CustomDialogButtons.YesNo:
button = MessageBoxButton.YesNo;
break;
case CustomDialogButtons.YesNoCancel:
button = MessageBoxButton.YesNoCancel;
break;
}
return button;
}
/// <summary>
/// Translates a standard WPF System.Windows.MessageBox MessageBoxResult into a
/// CustomDialogIcons.
/// This abstraction allows for different frameworks to use the same ViewModels but supply
/// alternative implementations of core service interfaces
/// </summary>
/// <param name="result">The standard WPF System.Windows.MessageBox MessageBoxResult</param>
/// <returns>CustomDialogResults results to use</returns>
private static CustomDialogResults GetResult(MessageBoxResult result)
{
CustomDialogResults customDialogResults = CustomDialogResults.None;
switch (result)
{
case MessageBoxResult.Cancel:
customDialogResults = CustomDialogResults.Cancel;
break;
case MessageBoxResult.No:
customDialogResults = CustomDialogResults.No;
break;
case MessageBoxResult.None:
customDialogResults = CustomDialogResults.None;
break;
case MessageBoxResult.OK:
customDialogResults = CustomDialogResults.Ok;
break;
case MessageBoxResult.Yes:
customDialogResults = CustomDialogResults.Yes;
break;
}
return customDialogResults;
}
#endregion
}
Et voila, le plus dur est fait ! En effet, maintenant, il suffit simplement d’utiliser tout cela. Ainsi, dans votre ViewModel de base, créer 2 champs privés et 1 propriété:
public static readonly ServiceProvider ServiceProvider = new ServiceProvider();
private IMessageBoxService m_Prompt;
public IMessageBoxService Prompt
{
get { return m_Prompt; }
}
Puis, rajoutez 2 constructeurs (dont un statique) qui vont se charger:
- d’ajouter, au ServiceProvider, une instance de classe qui implémente le service de MessageBox
- d’initialiser la propriété servant à appeler des boites de dialogues
static ViewModelBase()
{
// Regiser defaults
RegisterDefaultServices();
}
protected ViewModelBase()
{
// Fetch sefault services
FetchDefaultServices();
}
private static void RegisterDefaultServices()
{
// Add the service to the service provider
ServiceProvider.Add(typeof(IMessageBoxService), new MessageBoxService());
}
private void FetchDefaultServices()
{
// Retrieve the service from the service provider
m_Prompt = this.Resolve<IMessageBoxService>();
}
/// <summary>
/// This resolves a service type and returns the implementation.
/// </summary>
/// <typeparam name="T">Type to resolve</typeparam>
/// <returns>Implementation</returns>
protected T Resolve<T>()
{
return ServiceProvider.Resolve<T>();
}
Dès lors, vous n’avez plus qu’à utiliser la propriété Prompt, dans chacun de vos ViewModel héritant de ViewModelBase, pour pouvoir affichier des boites de dialogues:
Le résultat est sans appel !
L’avantage de cette technique, c’est qu’elle respecte à 100% le pattern MVVM mais surtout, que vous pouvez l’étendre comme bon vous semble pour rajouter vos propres services (comme un service de Log):
- on créé l’interface
- on développe la classe qui implémente l’interface
- on enregistre le service (de log) dans le service provider
- dans un ViewModel (de base ou non), on appele la méthode Resolve pour récupérer l’instance du service que l’on vient d’enregistrer !
C’est simple, rapide et très efficace !
A vos claviers 
A+
Microsoft vient de mettre à disposition plusieurs exemples expliquant montrant l'extensibilité des designers WPF/Silverlight dans Visual Studio 2010:
Property Editors
Custom Dialog Property Value Editor
Custom dialog property editor that launches a dialog to set a FileName property
Custom Inline Value Editor
Custom inline property value editor
Custom Extended Property Value Editor
Custom extended property value editor
Adorners
Custom Autosize Adorner
Custom adorner that sets the Autosize property
Custom Rail Adorner
Custom rail adorner that adjusts the opacity of a control
Custom Inner Rail Adorner
Custom rail adorner that adjusts the RenderTransform of a control
In-place Editing
Custom adorner that enables in-place text editing
Advanced
Custom Context Menu
Custom context menu that sets the Background of a control
Custom Feature Connector
Custom feature connector that displays the pending and activated designer features
Custom Surrogate Policy
Surrogate policy that enables a custom primary selection policy
Voila de quoi rendre heureux les développeurs que vous êtes 
A+
Unity
est le conteneur IoC (Inversion of Controls, inversion de contrôles) mis à disposition par Microsoft.
Celui-ci permet de faire de l’injection de dépendances, afin de vous permettre de développer des applications faiblement couplées. Dans le cadre d’un article que je suis en train d’écrire, j’ai tenté d’utiliser un container Unity pour utiliser un service WCF.
Au niveau de la configuration, j’ai donc utiliser ceci:
Puis j’ai créer un petit singleton qui va configurer mon container et me le retourner:
Le problème, c’est que si j’exécute mon code, au moyen du code suivant:
Je reçoit cette erreur:
Resolution of the dependency failed, type = "NwEmployeesViewer.Client.WPF.NorthwindSvc.INorthwindService", name = "". Exception message is: The current build operation (build key Build Key[NwEmployeesViewer.Client.WPF.NorthwindSvc.NorthwindServiceClient, null]) failed: The current build operation (build key Build Key[NwEmployeesViewer.Client.WPF.NorthwindSvc.NorthwindServiceClient, null]) failed: The type NorthwindServiceClient has multiple constructors of length 2. Unable to disambiguate. (Strategy type DynamicMethodConstructorStrategy, index 0) (Strategy type BuildPlanStrategy, index 3)
Pour faire clair, le problème semble venir du fait que le contructeur des services WCF possède plusieurs surcharges (un vide, un pour spécifier un endpoint, etc.) et que Unity n’est pas en mesure de trouver le constructeur par défaut (le constructeur vide). Il va donc falloir lui forcer la main, à savoir lui indiquer que le constructeur à utiliser prend en paramètre le nom de notre endpoint:
Et le tour est joué ! 
A+
Une grande majorité des ordinateurs portables vendus actuellement dispose d’un grand nombre de fonctionnalités (lecteur de SmartCard, prise HDMI, etc.) qui sont, pour la plupart, souvent inutilisées.
Cependant, avec l’arrivée de Windows Seven, l’une de ces fonctionnalités prend tout son sens: l’authentification biométrique. En effet, jusqu’à maitenant, cette authentification devait passer par des logiciels tiers, la plupart du temps développés les constructeurs.
Fort heureusement, Windows Seven dispose d’une nouvelle API permettant de programmer/manipuler les lecteurs biométriques de votre ordinateur. Ainsi, il devient possible, avec un peu de PInvoke, de créer un petit wrapper de l’API managé.
Pour vous simplifier la vie, j’ai créé ce petit wrapper managé. Pour le moment, seule la méthode WinBioIdentifyWithCallback est implémentée (mais il est facilement possible de l’enrichir). Cette méthode permet de vérifier, de façon asynchrone, que l’utilisateur qui vient d’utiliser le lecteur biométrique est effectivement un utilisateur reconnu:
Dans le cas d’un utilisateur non reconnu, l’application reçoit un évènement indiquant la cause du problème:
Au niveau de l’utilisation, c’est tout ce qu’il y a de plus simple:
Il est à noter que ce wrapper repose sur 3 DLLs:
- Biometric.Wrapper.dll: Il s’agit de la DLL managée faisant appel aux méthodes non managées
- Interop.WinBio.dll: C’est la DLL qui contient la définition des méthodes non managées (autrement dit le code PInvoke). Plutôt que d’écrire moi-même ce code, j’ai préféré le générer automatiquement au moyen de l’outil PInvoker. C’est rapide, efficace et en cas de problèmes, l’auteur de l’outil est très réactif donc n’hésitez pas à y jeter un oeil !
- PInvoker.Marshal.dll: DLL générée par l’outil PInvoker et qui contient la définition des types utilisés dans Interop.WinBio.dll
Pour télécharger l’ensemble, c’est par ici: http://morpheus.developpez.com/blog/BiometricWrapper/BiometricWrapper.zip
A+
Tous les développeurs Silverlight ont déjà rencontré l’erreur suivante lorsqu’ils travaillent avec WCF:
The remote server returned an error: NotFound.
Quoi de plus frustrant de savoir qu’une exception est déclenchée, sur le serveur, mais de ne pas en connaitre la cause !
Avec Silverlight 2, pour débugger ce genre d’erreurs, il n’y a pas 36 solutions: on remonte ces manches et on se triture les méninges pour essayer de savoir quelle exception pourrait survenir, sur le code serveur.
Avec Silverlight 3, le modèle de programmation des erreurs SOAP a été amélioré et on est maintenant capable de remonter, coté client, l’erreur qui est survenu sur le serveur. Mais avant de rentrer dans les détails, il convient de chercher pourquoi, à l’heure actuelle, l’erreur SOAP n’est pas renvoyée au client.
En fait, lorqu’une exception est déclenchée, celle-ci provoque l’envoi d’un code réponse HTTP 500. Or, dans son implémentation, Silverlight n’est capable de comprendre/intercepter que les code 200. Pour faire en sorte que le message d’erreur soit correctement envoyé au client, il est donc nécessaire, lorsqu’une exception est déclenchée, de lui faire renvoyer un code d’erreur 200, dans tous les cas.
Pour cela, plusieurs étapes sont nécessaires. La première consiste à créer, coté serveur, un “endpoint behavior” qui va se charger d’intercepter les réponses envoyées au client et, lorsqu’il s’agit de fautes, de renvoyer le code réponse 200:
public class SilverlightFaultBehavior : BehaviorExtensionElement, IEndpointBehavior
{
#region Properties
public override Type BehaviorType
{
get { return typeof(SilverlightFaultBehavior); }
}
#endregion
#region Override Methods
protected override object CreateBehavior()
{
return new SilverlightFaultBehavior();
}
#endregion
#region IEndpointBehavior Members
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
var inspector = new SilverlightFaultMessageInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
#endregion
#region Nested type: SilverlightFaultMessageInspector
public class SilverlightFaultMessageInspector : IDispatchMessageInspector
{
#region IDispatchMessageInspector Members
public void BeforeSendReply(ref Message reply, object correlationState)
{
if (reply.IsFault)
{
var property = new HttpResponseMessageProperty();
// Here the response code is changed to 200.
property.StatusCode = HttpStatusCode.OK;
reply.Properties[HttpResponseMessageProperty.Name] = property;
}
}
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
// Do nothing to the incoming message.
return null;
}
#endregion
}
#endregion
}
Ensuite, il faut enregister ce behavior dans le fichier web.config, puis indiquer à notre service qu’il doit l’utiliser:
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="silverlightFaults"
type="DemoErreursWCF.Web.SilverlightFaultBehavior, DemoErreursWCF.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior name="SilverlightFaultBehavior">
<silverlightFaults />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="DemoErreursWCF.Web.ServiceWithGoodErrorBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="customBinding1">
<binaryMessageEncoding/>
<httpTransport/>
</binding>
</customBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<services>
<service behaviorConfiguration="DemoErreursWCF.Web.ServiceWithGoodErrorBehavior" name="DemoErreursWCF.Web.ServiceWithGoodError">
<endpoint address=""
binding="customBinding"
bindingConfiguration="customBinding1"
contract="DemoErreursWCF.Web.ServiceWithGoodError"
behaviorConfiguration="SilverlightFaultBehavior"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
</system.serviceModel>
A présent, il ne reste plus qu’à écrire une méthode dans notre service WCF et lui faire déclencher une exception:
public class ServiceWithGoodError
{
[OperationContract]
[FaultContract(typeof(ArithmeticFault))]
public double Divide(int a, int b)
{
try
{
return Convert.ToDouble(a / b);
}
catch(DivideByZeroException)
{
var fault = new ArithmeticFault
{
Description = "Cannot divide by zero !"
};
throw new FaultException<ArithmeticFault>(fault, new FaultReason(fault.Description));
}
}
}
public class ArithmeticFault
{
public string Description { get; set; }
}
Notez au passage l’utilisation de l’attribut FaultContract, qui permet d’indiquer que la méthode va, potentiellement, retournée une exception du type indiqué.
A présent, il ne reste plus, coté client, qu’à utiliser notre service et sa méthode:
private void btnCallGoodError_OnClick(object sender, RoutedEventArgs e)
{
var client = new ServiceWithGoodErrorClient();
client.DivideCompleted += this.ClientGoodErrorDivideCompleted;
client.DivideAsync(5, 0);
}
private void ClientGoodErrorDivideCompleted(object sender, DivideCompletedEventArgs e)
{
if (e.Error == null)
{
this.tbResults.Text = e.Result.ToString();
}
else if (e.Error is FaultException<ArithmeticFault>)
{
var fault = e.Error as FaultException<ArithmeticFault>;
this.tbResults.Text = Environment.NewLine + fault.Detail.Description;
}
}
Et voici ce que l’on obtient en cas d’erreur:
Inversement, voici ce que l’on obtient dans le cas où l’on utilise pas cette technique:
Comme vous pouvez le constater, aucunes informations n’est passée/indiquée quant à la nateure de l’exception déclenchée coté serveur !
Voila qui s’avère tout de même bien pratique! 
Un lien dans lequel vous pourrez retrouver tout cela, est plus encore: http://msdn.microsoft.com/en-us/library/dd470096(VS.95).aspx
A+
Si comme moi vous êtes assez maniaque et vous aimez bien avoir un code structuré et bien organisé, alors Narrange est fait pour vous !
Ce petit utilitaire, utilisable en ligne de commande (donc depuis les outils externes de Visual Studio ou, pourquoi pas, durant le processus de build sur votre serveur) , vous permet de formatter/mettre en forme votre code en utilsant des régions, etc.
Parce qu'une image vaut plus que des mots, regardez ceci pour comprendre de quoi je parle:

En ce qui concerne la configuration, elle passe par un fichier XML ou alors, c'est plus agréable, par un petit utilitaire:

En voila un petit outil fort sympathique !
http://www.narrange.net
A+
Voila une fonctionnalité que je viens de voir en travaillant sur un projet Silverlight 3 
Lorsque vous avez un projet Silverlight 3 ouvert dans Expression Blend, vous pouvez activer/désactiver les fonctionnalités de "Out Of Browser" et de "Mise en cache" avec le menu "Project" => "Silverlight Project Options":
Si vous sélectionnez “Enable Application Outside Browser”, cela aura pour effet de créer le fichier OutOfBrowserSettings.xml, qui contient les paramètres nécessaires au mode offline de votre application Silverlight:
Comme quoi, ce produit peut nous réserver encore bien des surprises 
A+
Les 10 derniers blogs postés
-
TechDays Paris 2010 : La BI dans SharePoint 2010 par
Blog Technique de Romelard Fabrice le il y a 1 heure et 32 minutes
-
TechDays Paris 2010 : Déploiement de nouvelles technologies – Retour d’expérience par l’informatique de Microsoft par
Blog Technique de Romelard Fabrice le il y a 2 heures et 59 minutes
-
TechDays Paris 2010 : Plan de migration vers SharePoint 2010 par
Blog Technique de Romelard Fabrice le il y a 6 heures et 41 minutes
-
TechDays Paris 2010 : La pleinière du second jour par
Blog Technique de Romelard Fabrice le il y a 7 heures et 46 minutes
-
Visual Studio 2010 and .NET Framework 4 Release Candidate now available par
Matthieu MEZIL le il y a 10 heures et 52 minutes
-
Création d’une base de donnée sous SQL Azure par
Le Blog (Vert) d'Arnaud JUND le il y a 11 heures et 49 minutes
-
TechDays Paris 2010 : Les Services d’applications dans SharePoint 2010 par
Blog Technique de Romelard Fabrice le il y a 21 heures et 48 minutes
-
TechDays Paris 2010 : La GED et SharePoint 2010 par
Blog Technique de Romelard Fabrice le 02-08-2010, 16:54
-
TechDays Paris 2010 : SharePoint 2010 et Les réseaux sociaux par
Blog Technique de Romelard Fabrice le 02-08-2010, 15:40
-
TechDays Paris 2010 : SharePoint 2010 – Description et nouveautés par
Blog Technique de Romelard Fabrice le 02-08-2010, 14:33