Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Training KIT .NEt 4.0 déjà dispo !

au hazard des mes lectures..., j'ai découvert via ce blog, et qu'il était possible de télécharger le training kit pour Visual Studio 2010.

et oui on en oublierai presque que le Framework 3.5 sp1 viens de sortir il y a 3 mois...

Posté le par pierrick | 1 commentaire(s)

Pacman Silverlight 2 RTW (enfin !)

je n'avais pas encore eu le temps de migrer ce petit jeu pour la version RTW de Silverlight 2.0. C'est dorénavant chose faite :

Amusez vous bien !

pour ceux qui ont encore le client Silverlight Béta 2, l'ancien fonctionne toujours mais à cette adresse : ici

Posté le par pierrick | 4 commentaire(s)

Comment faire un récepteur de messages à la Erlang en C#

Un autre langage utilise lui aussi le pattern matching pour la reception des "messages" dans la communication inter-process, c'est Erlang. En effet en Erlang pour recevoir des messages on utilise ce type de syntaxe :

receive
    Pattern1 ->
      Expressions1;
    Pattern2 ->
      Expressions2;
end

un exemple :

receive
    {rectangle, Width, Ht} ->
        io:format("Aera of rectangle is ~p~n", [Width * Ht]);
    {circle, R} ->
        io:format("Aera of circle is ~p~n", [3.14159 * R * R]);
end

On remarque aisément que cela ressemble à un switch. tiens, tiens, ... ni aurait-il pas une ressemblance avec ce post(comment faire un pattern matching en C# comme celui de F#) ?

Mais comme on parle de messages, on peut imaginer un système de "publish-subscribe" basé sur le Type du message.

on pourrait ainsi écrire en C# :

    class Program
    {
       
class MyRectangle
        {
           
public int Width { get; set; }
           
public int Ht { get; set; }
        }

       
class MyCircle
        {
           
public int R { get; set; }
        }


       
static void Main(string[] args)
        {
           
PubSub.Subscribe<MyRectangle>(r =>
            {
               
Console.WriteLine("Area of Rectangle is {0}", r.Width * r.Ht);
            });
           
PubSub.Subscribe<MyCircle>(c =>
            {
               
Console.WriteLine("Area of Circle is {0}", c.R * c.R * 3.14159);
            });

           
//publication 
            new MyRectangle() { Width = 6, Ht = 10 }.Publish();
           
new MyCircle() { R = 23 }.Publish();

           
Console.ReadLine();
           
return;
        }
    }

à l' exécution

image

Le principe  ?

Associer un Type (i.e MyRectangle) avec une déléguée (i.e r => ...).

public static Guid Subscribe<T>(Action<T> caseAction)
{
   
return Subscribe(string.Empty, caseAction);
}

public static Guid Subscribe<T>(string topic, Action<T> onMessageReceived)
{
   
Guid result = Guid.NewGuid();
   
lock ((_subscriptions.Keys as ICollection).SyncRoot)
    {
       
Action<object> current;
       
if (_subscriptions.TryGetValue(topic, out current))
        {
           
//add the new delegate to current subscribers list
            var currentCase = current.Target as CaseActionHolder<object>;
           
var newCase = current.Case(result, onMessageReceived);
            currentCase.PreviousID = result;
            ((
CaseActionHolder<object>)newCase.Target).NextAction = current;
            _subscriptions[topic] = newCase;
        }
       
else
        {
           
//creates case
            current = current.Case(result, onMessageReceived);
            _subscriptions.Add(topic, current);
        }
        _subscriptionsById.Add(result, topic);
    }
   
return result;            
}

Dans mon implémentation, j'ai ajouté une notion (topic), le sujet qui permet d'avoir à l'utilisation un découpage logique des abonnements. De plus il est possible de se désabonner grâçe au guid renvoyé lors de l'abonnement.

Le "switch-case" pour dispatcher le message ressemble beaucoup à celui de mon post sur le pattern matching F#:

static Action<object> Case<TArg>(this Action<object> fn, Guid id, Action<TArg> caseAction)
{
   
var thisCase = new CaseActionHolder<object> { ID = id };
    thisCase.Action = (arg) =>
    {
       
if (typeof(TArg).IsAssignableFrom(arg.GetType()))
        {
           
var convertedArg = (TArg)arg;
            caseAction(convertedArg);
        }
        thisCase.NextAction(arg);
    };
   
//no exception by default 
    thisCase.NextAction = (arg) => { };
   
return new Action<object>(thisCase.DoAction);
}

une souscription tel que "Subscribe<MyRectangle>(r => ...), reçoit les messages de Type MyRectangle, mais aussi pour tous les types qui dérivent de MyRectangle.

ainsi si on dérive de MySquare : MyRectangle

class MySquare : MyRectangle
{
}

...
new MySquare() { Width = 4, Ht = 4 }.Publish();
...

   donne comme résultat :
image

avec cette technique il possible de faire des récepteur à messages fortement "typées", certainement moins puissante qu'avec Erlang, mais l'idée est là.

vous pouvez télécharger le code source ici :

 

Posté le par pierrick | 0 commentaire(s)

PDC 08 : Keynote

Le ton est donné ! les prochaines années seront résolument "services" !

un mot à retenir "Azure", un mot oui, mais aussi une plateforme, et un système d'exploitation

à l'occasion du keynote, Microsoft à annoncé sa nouvelle plateforme "Windows Azure", cette plateforme est un système d'exploitation permettant de hoster des applications comme des services, mais en fournissant un abstraction complète vis à vis du système sous-jacent.

Cette plateforme simplifie le déploiement, l'administration et même le développement de vos applications (as services), en s' intégrant dans vos outils tel que Visual Studio.

Au niveau du développement, une nouvelle brique fait son apparition ".NET services". c'est le coeur du système qui permet de connecter les applications entre elles.

The Cloud Computing and Services Platform Diagram

au passage on remarque, les nouveaux logos associés à cette plateforme

pour en savoir plus rendez vous sur http://www.microsoft.com/azure/whatisazure.mspx#Whatis

 

bon je vais suivre la suite sur : "Dublin" and  .Net Services

 

PS : Ray Ozzie à annoncé qu' une première CTP du SDK devrait être bientôt disponible (quelques semaines)

Posté le par pierrick | 0 commentaire(s)
Classé sous :

PDC08, un inscrit de plus...

c' est fait, je me suis inscrit, afin d' éviter la bousculade de demain :

image

et vu le temps, un petite balade s' imposait...

image

plage de santa monica, début de "Venice beach"

 

image

demain devrait-être un peu plus climatisé...

 

Mots clés Technorati :
Posté le par pierrick | 0 commentaire(s)
Classé sous :

F# nouvelle CTP 1.9.6.2 (update)

Don Syme vient d'annoncer la sortie d' une nouvelle CTP de F#. C'est en réalité une mise à jour, corrections sur les unités de mesure. Cette version est téléchargeable  ici.

Le détails des corrections sont décrites ici.

Posté le par pierrick | 0 commentaire(s)

F# nouvelle CTP (1.9.6)

Que dire de cette CTP, si ce n' est qu' elle est mieux intégrée dans Visual Studio.

image

intellisense

image

de plus intégrable dans une usine de dev, puisque le projet est un projet MSBuild.

 

Mais LA fonctionnalité de cette CTP, c'est les unités de mesures.

#light

//heure
[<Measure>] type h
//km
[<Measure>] type km

j'ai défini un type unité 'h' pour les heures, et un type unité km pour les kilomètres,  je peux maintenant écrire ceci :

let Paris_Marseille = 780.0<km>
let VMax_autorise = 130.0<km/h>

ensuite il suffit d'utiliser ces unités de mesures

image

nbKm est de type <km>. ces unité de mesures sont très bien pour éviter de mélanger les choux et les carottes. Il est possible de définir des fonctions fortement typées, les appels seront contrôlés à la compilation.

let ToKm_h(x) = x * 1.0<km/h> 

let VFR_Max = ToKm_h(240.0)

let ParisMarseille (speed:float<km/h>) = 
  printfn
"Paris-Marseille à %.2f km/h se fait en %.2f heure(s)" 
    <| float(speed) 
    <| float(Paris_Marseille / speed) 

ParisMarseille VMax_autorise
ParisMarseille VFR_Max
ParisMarseille 150.0<km>

la dernière ligne empêche toute compilation

 image

on peut aussi s' amuser avec des unités un peu plus proche de nous......

[<Measure>] type annee
[<Measure>]
type homme
[<Measure>]
type ah = annee / homme 

let heure_par_mois = 169.0<h>
let heure_par_an = 11.0 * heure_par_mois

let ToYear(x:float<h>) = (x / heure_par_an) * 1.0<annee>

let me = 1.0<homme>
let SpentTime(x:float<h>) = ToYear(x) / me

printfn
""
printfn "cet exemple a pris %f annee/homme " <| float(SpentTime(1.0<h>))

le fait de spécifier des unités, cela rend le code plus compréhensible.

au fait avec tout ça j' ai perdu combien d'années ??

image

Mais comment est-ce traduit après compilation ? (que nous dit reflector ?)

image

en double tout simplement, ce qui implique que ces unités de mesures ne sont que du sucre syntaxique pour F#,  mais à mon avis très utile. Pour preuve Andrew Kennedy, relate un fait passé en 1999 (125 million de $, perdu par la NASA, pour une erreur d'unité).

 

1.0<homme> / xxxx<km/h>

Posté le par pierrick | 0 commentaire(s)

C# : Vérifications / Performances

Lorsque que l'on écrit une méthode, il est d' usage de vérifier les paramètres...

mais quelle méthode employez vous ?

la méthode simple, le strict minimum  ?

private static void MyMethod1(string a, string b, string c, string d)
{
   
if (a == null)
       
throw new ArgumentNullException(string.Format(Properties.Resources.EX_1, "a"), (Exception)null);
   
if (b == null)
       
throw new ArgumentNullException(string.Format(Properties.Resources.EX_1, "b"), (Exception)null);
   
if (c == null)
       
throw new ArgumentNullException(string.Format(Properties.Resources.EX_1, "c"), (Exception)null);
   
if (d == null)
       
throw new ArgumentNullException(string.Format(Properties.Resources.EX_1, "d"), (Exception)null);
}

Ou une méthode plus élégante  ? (il y a plus d' informations pour l' appelant lors d' une exception)

private static void MyMethod2(string a, string b, string c, string d)
{
   
ArgumentNotNull(a, Properties.Resources.EX_1, "a");
   
ArgumentNotNull(b, Properties.Resources.EX_1, "b");
   
ArgumentNotNull(c, Properties.Resources.EX_1, "c");
   
ArgumentNotNull(d, Properties.Resources.EX_1, "d");
}

Check.ArgumentNoNull vaut :

public static void ArgumentNotNull(object obj, string fmt, params object[] args)
{
   
if (obj == null)
       
throw new ArgumentNullException(string.Format(fmt, args), (Exception)null);
}

Certes plus élégante, mais elle est malheureusement plus lente à l' exécution. Au premier coup d' oeil, on s' aperçoit qu' à chaque appel, "Properties.Resources.EX_1" est évaluée !

Comparons tout de même :

int nb = 10000;
TimeSpan t1 = DoTest(MyMethod1, nb);
TimeSpan t2 = DoTest(MyMethod2, nb);
Console.WriteLine("t1 : {0}, t2:{1}, t2/t1:{2}", t1, t2, t2.TotalMilliseconds / t1.TotalMilliseconds);

Résultat :

image 

Les chiffres sont petits, mais le nombres d'appels n' est que de 10 000. Le rapport est accablant la deuxième méthode est 86 fois plus lente !!!!!

l' idée ici est gardé un code élégant, tout en se rapprochant des performances de  'MyMethod1'.

Comment évaluer "Properties.Resources.EX_1" uniquement lorsque l' argument est null ?

il suffit de déléguer....

private static void MyMethod2_1(string a, string b, string c, string d)
{
    ArgumentNotNull(a, () => ThrowNull(Properties.
Resources.EX_1, "a"));
    ArgumentNotNull(b, () => ThrowNull(Properties.
Resources.EX_1, "b"));
    ArgumentNotNull(c, () => ThrowNull(Properties.
Resources.EX_1, "c"));
    ArgumentNotNull(d, () => ThrowNull(Properties.
Resources.EX_1, "d"));
}

public static void ThrowNull(string fmt, params object[] args)
{
   
throw new ArgumentNullException(string.Format(fmt, args), (Exception)null);
}

public static void ArgumentNotNull(object obj, Action OnNullAction)
{
   
if (obj == null)
        OnNullAction();
}

et en utilisant les méthodes d' extensions on arrive à quelque chose du genre

private static void MyMethod3(string a, string b, string c, string d)
{
    a.IsNull(() => ThrowNull(Properties.
Resources.EX_1, "a"));
    b.IsNull(() => ThrowNull(Properties.
Resources.EX_1, "b"));
    c.IsNull(() => ThrowNull(Properties.
Resources.EX_1, "c"));
    d.IsNull(() => ThrowNull(Properties.
Resources.EX_1, "d"));
}

et IsNull ressemble beaucoup à ArgumentNotNull

public static void IsNull(this object value, Action OnNullAction)
{
   
if (value == null)
        OnNullAction();
}

on pourrait encore enlever ThrowNull

private static void MyMethod4(string a, string b, string c, string d)
{
    a.IsNull(() => Properties.
Resources.EX_1, "a");
    b.IsNull(() => Properties.
Resources.EX_1, "b");
    c.IsNull(() => Properties.
Resources.EX_1, "c");
    d.IsNull(() => Properties.
Resources.EX_1, "d");
}

 

et les performances ???

image 

en conclusion pour 1 000 000 d' appels, la méthode la moins coûteuse dans les plus élégantes, est la méthode 3

private static void MyMethod3(string a, string b, string c, string d)
{
    a.IsNull(() => ThrowNull(Properties.
Resources.EX_1, "a"));
    b.IsNull(() => ThrowNull(Properties.
Resources.EX_1, "b"));
    c.IsNull(() => ThrowNull(Properties.
Resources.EX_1, "c"));
    d.IsNull(() => ThrowNull(Properties.
Resources.EX_1, "d"));
}

1 000 000 d'appels  () :

  1. Methode 1 : 17.7 ms
  2. Méthode 3 : 44.2 ms

Contexte du Test :

  • Portable Core 2 Duo, 2Ghz, 2Go de RAM
  • .Net 3.5 (sans le sp1)
  • Windows Vista sp1
Posté le par pierrick | 5 commentaire(s)

Comment faire un pattern matching en C# comme celui de F#

il y a une fonctionnalité intéressante dans F#, c' est le pattern matching

Exemple:

let rec fib x = 
 
match x with 
    | 1
->
    | 2
->
    | x
-> fib(x - 1) + fib(x - 2)

en C#

static int Fibonnaci(int x)
{
   
switch (x)
    {
       
case 1 :
           
return 1;
       
case 2:
           
return 1;
       
default :
           
return Fibonnaci(x - 1) + Fibonnaci(x - 2);
    }
}

Dans cas c'est relativement simple, il suffit de remplacer "match x", par "switch(x)". Mais prenons un exemple un peu plus "dynamique" :

let (|ParseInt|_|) s =
 
let i = ref 0
 
if Int32.TryParse(s, i) then Some !i
  
else None

let (|ParseFloat|_|) s =
 
let i = ref 0.0
 
if Double.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, i) then Some !i
  
else None

let TryParse v =
 
match v with
    | ParseInt i -> printfn " it's an int : %d" i
    | ParseFloat f
-> printfn " it's an double : %f" f
    | _
-> printfn "unrecognized data"

image

ce qui est intérressant ici, c'est la possibilité de passer des paramètres entre la règle ("case") et le traitement de cette règle. Ce qui n'est plus possible avec un switch...

 

Revisitons le switch...

let rec fib x = 
 
match x with 
    | 1
->
    | 2
->
    | x
-> fib(x - 1) + fib(x - 2)

1,2,x sont des prédicats, et l'on pourrait écrire :

Predicate<int> one = x => x == 1;
Predicate<int> two = x => x == 2;

et le traitement associé est :

Func<int, int> onetwoAction = x1 => 1; 

il faut maintenant relier les règles à l'action, et en tant que développeur de la fonction de fibonnaci, j'ai envie d'écrire :

Func<int, int> Case1 = NewCase(one,  onetwoAction );

Func<int, int> Case2 = NewCase(two,  onetwoAction );

Func<int, int> defaultCase = x => Fib(x-1) + Fib(x-2);

Fib étant la fonction englobant Case1, Case2, defaultCase qui ressemble à :

int Fib(int arg)
{
   
if (one(arg))
       
return onetwoAction(arg);
   
else if (two(arg))
       
return onetwoAction(arg);
   
else
        return defaultCase(arg);
}

mais evidemment tout cela c' est de la plomberie.... En regardant de plus près cela ressemble à une chaine de responsabilité (Chain-of-responsibility pattern).

il faut donc une classe qui possède l'action courante, et l'action suivante

class CaseHolderChain<T>
{
   
public T NextAction { get; set; }
    public T Action { get; set; }
}

La fonction 'NewCase' est donc :

public static Func<TArg, TResult> NewCase<TArg, TResult>(Predicate<TArg> test, Func<TArg, TResult> caseAction)
{
   
if (test == null)
       
throw new ArgumentNullException("test");
   
if (caseAction == null)
       
throw new ArgumentNullException("caseAction");

   
var thisCase = new CaseHolderChain<Func<TArg, TResult>>();

    thisCase.Action = arg =>
    {
       
if (test(arg))
           
return caseAction(arg);
       
return thisCase.NextAction(arg);
    };
    thisCase.NextAction = arg =>
    {
       
return CaseException<TResult>(arg);
    };

   
return thisCase.Action;
}

Ainsi la fonction retournée est une sorte de 'switch' avec une seule possibilité, en effet la fonction 'NextAction' est par défaut 'connectée' sur une méthode static soulevant une exception.

Il faut maintenant lier les 'cases' ensemble, c'est à dire remplacer NextAction du premier 'case' par le suivant, et ainsi de suite...

Mais pour cela il faut faire évoluer notre fonction 'NewCase', car il faut pouvoir changer la valeur de la propriété 'NextAction'.

class CaseHolderChainFun<TArg, TResult> : CaseHolderChain<Func<TArg, TResult>>
{
   
public TResult DoAction(TArg arg)
    {
       
return Action(arg);
    }
}
        
public static Func<TArg, TResult> NewCase<TArg, TResult>(Predicate<TArg> test, Func<TArg, TResult> caseAction)
{
   
if (test == null)
       
throw new ArgumentNullException("test");
   
if (caseAction == null)
       
throw new ArgumentNullException("caseAction");

   
var thisCase = new CaseHolderChainFun<TArg, TResult>();

    thisCase.Action = arg =>
    {
       
if (test(arg))
           
return caseAction(arg);
       
return thisCase.NextAction(arg);
    };
    thisCase.NextAction = arg =>
    {
       
return CaseException<TResult>(arg);
    };
   
return new Func<TArg, TResult>(thisCase.DoAction);
}

plutôt que de renvoyer une fonction pointant directement sur 'Action' (qui est une méthode statique), je renvoie une fonction pointant sur une méthode d'instance. Cela permet de retouver le type 'CaseHolderChainFun<>' facilement.

En effet 'Func<TArg, TResult>' est un type Delegate, qui possède une propriété 'Target', qui est différent de null si la fonction pointe sur une méthode d'instance, bingo !

relier plusieurs 'cases' devient un jeu d'enfant, c'est le rôle de la fonction MakeMatch :

static Func<TArg, TResult> MakeMatch<TArg, TResult>(Func<TArg, TResult> defaultCase, params Func<TArg, TResult>[] cases)
{
   
Func<TArg, TResult> Result;
   
if (defaultCase != null)
        Result = arg => defaultCase(arg);
   
else
        Result = arg => CaseException<TResult>(arg);
   
int i = -1;
    cases.Reverse().ForEach((elem) =>
    {
        i++;
       
CaseHolderChainFun<TArg, TResult> holder = elem.Target as CaseHolderChainFun<TArg, TResult>;
       
if (holder == null)
           
throw new Exception(string.Format("{0}eme case is not supported, use NewCase function ", i));
       
if (Result != null)
        {
            holder.NextAction = Result;
        }
        Result = elem;
    });
   
return Result;
}

Ici MakeMatch, réalise l'union de plusieurs règles entre elle, et en ajoutant à la fin de la chaîne l'action par défaut. Ici l'action par défaut est le premier paramètre, ceci afin de pouvoir utiliser 'params' pour la liste des règles. Maintenant la fonction de Fibonnaci ressemble a :

Func<int, int> fibo = null;
fibo = MakeMatch((
int x) => fibo(x-1) + fibo(x-2),
            NewCase((
int x) => x == 1, x => 1),
            NewCase((
int x) => x == 2, x => 1));

Console.WriteLine(fibo(30));

Nous sommes bien loin du switch, mais celui-ci est 'dynamique'... 

après un petit refactoring et 2 méthodes d'extensions plus tard, la fonction de fibonnaci peut s'écrire :

fibo = fibo.Default(x => fibo(x - 1) + fibo(x - 2))
           .Case(x => x == 1, x => 1)
           .Case(x => x == 2, x => 1);

les méthodes d'extensions ressemble à :

private static TResult CaseException<TResult>(object value)
{
   
throw new Exception(string.Format("case not found for {0}", value));
}

public static Func<TArg, TResult> Case<TArg, TResult>(this Func<TArg, TResult> fn, Predicate<TArg> test, Func<TArg, TResult> caseAction)
{
   
var thisCase = new CaseHolderChainFun<TArg, TResult>();

    thisCase.Action = arg =>
    {
       
if (test(arg))
           
return caseAction(arg);
       
return thisCase.NextAction(arg);
    };
   
if (fn != null)
        thisCase.NextAction = fn;
   
else
        thisCase.NextAction = arg =>
        {
           
return CaseException<TResult>(arg);
        };
   
return new Func<TArg, TResult>(thisCase.DoAction);
}

public static Func<TArg, TResult> Default<TArg, TResult>(this Func<TArg, TResult> fn, Func<TArg, TResult> aDefault)
{
   
var thisCase = new CaseHolderChainFun<TArg, TResult>();

   
if (aDefault != null)
        thisCase.Action = aDefault;
   
else
        thisCase.NextAction = arg =>
        {
           
return CaseException<TResult>(arg);
        };
   
return new Func<TArg, TResult>(thisCase.DoAction);
}

avec cette implémentation, il est impératif que '.Default' soit en premier, car il sera exécuté en dernier.

 

Maintenant que nous avons le principe de base, le 'TryParse' F# devrait ressembler à :

Action<object> TryParse = null;

TryParse = TryParse.Case((
string str, ref int v) => Int32.TryParse(str, out v),
                         (str, v) =>
Console.WriteLine(string.Format("it 's an int -> {0}, {1}", str, v)))
                   .Case((
string str, ref double v) => double.TryParse(str, NumberStyles.Any, CultureInfo.InvariantCulture, out v),
                         (str, v) =>
Console.WriteLine(string.Format("it 's an double -> {0}, {1}", str, v)));
TryParse(
"32");
TryParse(
"32.56");
TryParse(
new OverflowException());
TryParse(
new Exception());

et après execution
image

il faut remarquer ici, que le paramètre d'entrée est object, ce qui dans certains cas provoquera du boxing/unboxing.

l'implémentation de la méthode d'extension 'Case' est un peu différente.

public static Action<object> Case<TArg, TRef>(this Action<object> fn, Predicate<TArg, TRef> test, Action<TArg, TRef> caseAction)
{
   
var thisCase = new CaseActionHolder<object>();
    thisCase.Action = (arg) =>
    {
       
if (typeof(TArg).IsAssignableFrom(arg.GetType()))
        {
           
var convertedArg = (TArg)arg;
           
var r = default(TRef);
           
if (test(convertedArg, ref r))
            {
                caseAction(convertedArg, r);
               
return;
            }
        }
        thisCase.NextAction(arg);
    };
   
//no exception by default
    thisCase.NextAction = (arg) => { };
   
return new Action<object>(thisCase.DoAction);
}
public static Action<object> Default(this Action<object> fn, Action<object> aDefault)
{
   
var thisCase = new CaseActionHolder<object>();

   
if (aDefault != null)
        thisCase.Action = aDefault;
   
else
        thisCase.Action = arg => { };
   
return new Action<object>(thisCase.DoAction);
}

Conclusion :

Les expressions lambda  et les méthodes d'extension nous autorise à toucher du doigt la programmation fonctionnelle. Mais dans le cas présent, F# vérifie les règles qui ne "match" pas à la compilation, ce qui n'est pas le cas ici. De plus l'écriture est ici encore plus verbeuse que celle de F#.

 

Matthew Podwysocki à implémenté d'autres aspects fonctionnel que l'on retrouve dans F# (ou d'autre langage fonctionnel), tel Fold/ unfold, Map, Map2, ... , son projet se touve sur : http://code.msdn.microsoft.com/FunctionalCSharp

Posté le par pierrick | 0 commentaire(s)

WPF : la gestion des dates (Label, TextBlock)

Le Label et le TextBlock affichent les dates de manières différentes.

Le label utilise la Culture, et pas le Textblock (du moins pas la culture courante)

Exemple :

<TextBlock Text="binding with TextBlock"></TextBlock>
<
TextBlock Margin="10,0,0,0">
    <TextBlock.Text>
        <Binding Source="{x:Static s:DateTime.Now}">
        </Binding>
    </TextBlock.Text>
</
TextBlock>
<
TextBlock Text="Binding with Label"></TextBlock>
<
Label Margin="10,0,0,0" Padding="0">
    <Label.Content>
        <Binding Source="{x:Static s:DateTime.Now}">
        </Binding>
    </Label.Content>
</
Label>
donne :

image

et pourtant ma cullture est :

image 

mais comment fait donc le "TextBlock" pour m' afficher la date dans ce format ?

et bien tout simplement du binding....

en effet la propriété "Text" du TextBlock étant de type "string", le Binding effectue une conversion, alors que pour le Label, la propriété Content étant de type object, le binding n' effectue aucune conversion.

il reste une question, quelle est la culture utilisée pour la conversion ?

1) si la propriété "ConverterCulture" du Binding est affectée c' est cette culture qui est utilisée.

<Binding Source="{x:Static s:DateTime.Now}"
ConverterCulture="{x:Static sg:CultureInfo.CurrentUICulture}">
</
Binding>

2) Sinon c' est la propriété "Language" du l' élément (FrameworkElement.Language) qui est utilisée.

<TextBlock Margin="10,0,0,0" x:Name="tb1" Language="fr-FR">
    <TextBlock.Text>
        <Binding Source="{x:Static s:DateTime.Now}" x:Name="tbbinding">
        </Binding>
    </TextBlock.Text>
</
TextBlock>

image
très bien mais alors que vaut la propriété "Language", lorsque celle-ci n' est pas spécifiée ?

image

et oui "en-us", mon ami Reflector me le confirme...

 image

Oui mais !

il y a encore un truc qui me chiffonne..., le Label n' affiche pas les secondes !!!

Après un essai "DateTime.Now.ToString()" affiche bien les secondes et utilise la culture.

De plus le Label possède un ContentPresenter pour afficher son contenu, qui lui même à comme template par défaut un "TextBlock"

... dans les deux cas j' ai un TextBlock... mais alors pourqoi l' affichage est différent ?

hum hum, le binding ???

Oui encore lui !

le binding utilisé entre le ContentPresenter et son TextBlock interne est un "TemplateBindingExtension", qui lui par défaut cherche un TypeConverter en faisant quelque chose du style :

TypeConverter tc = TypeDescriptor.GetConverter(typeof(DateTime));
if (tc.CanConvertTo(typeof(string)))
{
   
return (string)tc.ConvertTo(DateTime.Now, typeof(string));
}

(graçe au symboles, j'ai pu parcourir le contenu des sources du ContentPresenter....)

et par défaut le DateTimeConverter effectue un .ToString(format.ShortDatePattern + " " format.ShortTimePattern)

 

à suivre...

Posté le par pierrick | 2 commentaire(s)

Liste de jeux pour Silverlight

dans les commentaires de mon post précédent, silverlight girl m'a signalé la présence du pacman dans sa liste de jeux que je vous invite à visiter (http://www.mashooo.com/).

à l'heure actuelle cette liste est constituée de 33 jeux, à noté que c'est aussi une application Silverlight.

Posté le par pierrick | 0 commentaire(s)

Et je mets le son....

un pacman avec du son c'est plus sympa, non ?

j'ai ajouté quelques fonctionnalités

- le son
- les bonus
- les scores flottants
- le mode plein écran

 

amusez vous bien !

Posté le par pierrick | 3 commentaire(s)