Blaise Braye, IT Edition

Aller au contenu | Aller au menu | Aller à la recherche

mardi, 21 février 2012

Attention à éviter de copier de fichier depuis un projet silverlight vers une librairie dédiée à du desktop

Je travaille aujourd'hui en environnement visual studio 2010, avec une solution qui contient des projets destinés à différent framework (silverlight 4 et .net 4 essentiellement).

Je viens d'obtenir le message suivant, inopinément après une compilation: "Projet file must include the .NET Framework assembly 'WindowsBase, PresentationCore, PresentationFramework' in the reference list."

Dix minutes plus tôt la compilation fonctionnait. Il m'en a fallut dix de plus pour comprendre que cela venait d'une copie de fichier, dans visual studio, depuis un projet silverlight vers un projet desktop. En l'occurence, c'était une ressource et elle a été copiée avec ces attributs. L'attribut problématique était "Build Action" qui était fixé à "Page" or je le voulais en tant que ressource. De ce fait, le compilateur se plaignait que les librairies de présentation ne soient pas référencées par ma librairie desktop.

Mon intuition me dit que ce problème peut survenir systématiquement pour ce scénario quand on déplace le fichier depuis projet destiné à une target alpha vers un projet destiné à une target beta.

vendredi, 10 février 2012

Positionner et redimmensionner une image en silverlight

En développant un module de visualisation de photos (silverlight 4), Il me fallait un outil capable de redimmensioner une image avec la roulette de la souris et de la repositionner sur une surface via un "drag and drop". J'ai pu obtenir le résultat escompté en lisant le contenu de ce lien , moyennant quelques adaptations propres à mes besoins.

  • la solution proposée utilise certaines fonctions propres à wpf, heureusement elle ne sont pas très complexes à réécrire (substraction de vecteur...)
  • La grande différence entre mon implémentation et celle proposée par l'utilisateur est que j'ai préféré une gestion des événements au niveau de la bordure qui contient l'image. De cette façon, le contrôle sur l'image est possible partout à l'intérieur de la bordure (c'est le comportement d'un calque dans Photoshop). Notons que pour permettre une gestion des événements à un conteneur quelqu'il soit (une bordure ici), il faut impérativement lui imposer une couleur d'arrière plan si son contenu ne prend pas toute la surface disponible. Raison intuitive de cette obligation : les évènements ne se produisent que s'ils sont propagés via un contenu (--> conteneur != contenu).
  • Outre cette différence, j'ai souhaité que le resizing lors de l'événement "MouseWheel" (roulette de la souris) préserve la position de la souris sur l'image. Par exemple, si je zoome avec la souris sur le volant d'une voiture, mon objectif est de préserver le volant de cette voiture sous ma souris.
  • Une dernière fonctionnalité intéressante, retrouvée sur ce lien, permet de s'assurer que le moteur de rendu silverlight n'affiche pas le contenu de la bordure qui se retrouverait en dehors de sa zone d'affichage. Cette fonctionnalité est présente nativement dans WPF et est activée par la propriété "ClipToBound"

Code Xaml

<Border Grid.Row="1" Layout:Clip.ToBounds="True" Background="WhiteSmoke"
        MouseWheel="OnBorderMouseWheel"
        MouseLeftButtonDown="OnBorderMouseLeftButtonDown"
        MouseLeftButtonUp="OnBorderMouseLeftButtonUp"
        MouseMove="OnBorderMouseMove"
        >
    <Image x:Name="imgLarge" RenderTransformOrigin="0.5,0.5"      
        HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None" Source="{Binding Value.FileWebUrl}">
    <Image.RenderTransform>
        <TransformGroup>
            <ScaleTransform />
            <TranslateTransform/>
        </TransformGroup>
    </Image.RenderTransform>
</Image>
</Border>

Code C# associé

/// <summary>
/// Called when [border mouse wheel].
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.Windows.Input.MouseWheelEventArgs"/> instance containing the event data.</param>
private void OnBorderMouseWheel(object sender, MouseWheelEventArgs e)
{
    var border = (Border)sender;
    var image = (Image)border.Child;

    var st = ((TransformGroup)image.RenderTransform).Children.OfType<ScaleTransform>().First();
    var tt = ((TransformGroup)image.RenderTransform).Children.OfType<TranslateTransform>().First();

    var start = e.GetPosition(image);
    var origin = new Point(tt.X, tt.Y);

            
    double zoom = e.Delta > 0 ? .2 : -.2;
    st.ScaleX += zoom;
    st.ScaleY += zoom;

    var target = e.GetPosition(image);

    var v = st.Transform(Substract(start,target));
    tt.X = origin.X - v.X;
    tt.Y = origin.Y - v.Y;

}

Point _start;
Point _origin;
bool _isMouseCaptured;

/// <summary>
/// Called when [border mouse left button down].
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
private void OnBorderMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var border = (Border)sender;
    var image = (Image)border.Child;
            
    var tt = ((TransformGroup)image.RenderTransform).Children.OfType<TranslateTransform>().Single();
    _start = e.GetPosition(border);
    _origin = new Point(tt.X, tt.Y);

    _isMouseCaptured = true;
    image.CaptureMouse();
}

/// <summary>
/// Called when [border mouse left button up].
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
private void OnBorderMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    var border = (Border)sender;
    var image = (Image)border.Child;
    _isMouseCaptured = false;
    image.ReleaseMouseCapture();
}

/// <summary>
/// Called when [border mouse move].
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> instance containing the event data.</param>
private void OnBorderMouseMove(object sender, MouseEventArgs e)
{
    var border = (Border)sender;
    var image = (Image)border.Child;

    if (_isMouseCaptured)
    {
        var tt = (TranslateTransform)((TransformGroup)image.RenderTransform)
            .Children.First(tr => tr is TranslateTransform);

        var v = Substract(_start, e.GetPosition(border));
        tt.X = _origin.X - v.X;
        tt.Y = _origin.Y - v.Y;
    }
}

/// <summary>
/// Substracts the specified PT1.
/// </summary>
/// <param name="pt1">The PT1.</param>
/// <param name="pt2">The PT2.</param>
/// <returns></returns>
public static Point Substract(Point pt1, Point pt2)
{
    return new Point(pt1.X - pt2.X, pt1.Y - pt2.Y);
}

mardi, 20 décembre 2011

Optimiser les temps de compilation des projets WCF RIA Services

J'ai enfin trouvé ce qui prend temps de temps au processus de compilation des projets wcf ria dans visual studio 2010: la fonctionalité LiveIntelliSense Après désactivation de cette fonctionnalité, le debug passe de pénible à appréciable, pas moins que ça. Cet article explique le problème et propose la solution: LiveIntelliSenseDeprecated Au cas où le lien mourrait voici la manipulation à effectuer pour désactiver cette source de problèmes:
1. ouvrir regedit et suivre le chemin ci-dessous:
On a 32-bit machine:

HKEY_LOCAL_MACHINE\SOFTWARE \Microsoft\WCFRIAServices\v1.0\

On a 64-bit machine:

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\WCFRIAServices\v1.0\

2. Dans cette entrée, ajouter (ou éditer) l'entrée de type DWORD : "DisableLiveIntelliSense"; la valeur '1' désactivera la fonctionnalité

jeudi, 8 décembre 2011

Debug Tools pour travailler avec WCF

Je viens de passer deux jours sur un problème qui aurait pu être découvert instantanément si j'avais utilisé les bons outils tout de suite. (silverlight vs wcf ria services)

Généralement, les erreurs sont assez simple à obtenir via des points d'entrées standard tels qu'une récupération systématique des exceptions non gérées au niveau de l'application. Néanmoins, quand le problème vient d'une couche inférieure (data, transport), cela peut se corser sévèrement. il est possible de diagnostiquer rapidement les symptomes à l'aide de l'outil Fiddler. Une fois chargé, ce dernier écoute tous les allers-retours partant de votre client web. Mais certaines erreurs sont très sourdes : erreur 504, le serveur ne retourne pas de réponses...??? comment est-ce possible? a-t-on déjà vu une requête web sans réponse? à moins d'un problème sur la bande, ce devrait être impossible... Mais voilà, Microsoft a réussi à faire ça dans son conception des services wcf --> si une exception se produit à ce niveau, on en entend pas parler, on n'est même pas au courant qu'il y a un soucis à ce niveau. BRAVO.

Bref, une fois ce fait acquis, on cherche dans cette direction et on trouve rapidement ce type de post: wcf-ria-services-not-found-error-message.aspx et là, on se sent très bête... Cet outil devrait être l'un des premiers à prendre en main lorsque l'on développe avec des services WCF, c'est indispensable!

MS n'est certainement pas à blâmer dans cette histoire, alors Blaise, si tu développes des services WCF, il faut utiliser "Microsoft Trace Viewer" dès que Fiddler te parle d'une erreur 504!

jeudi, 30 décembre 2010

Sélection d'un template contextuel

Aujourd'hui, je cherchais à pouvoir sélectionner un contenu pour un contrôle lié à des données en fonction d'un contexte d'utilisation. En l'occurence, mon objectif est d'afficher les données d'une gridview dans un format différent selon que l'utilisateur veut un affichage détaillé ou non.
C'est finalement la solution trouvée sur le blog de luisabreu qui a fonctionné. Lors de la liaison de la grille au données, je fais une vérification de mode d'affichage pour sélectionner le contenu adéquat:

var tplf = (TemplateField) dgvCatalogue.Columns[0];
switch (pf1.DisplayMode)
{
  case PaginationFeatures.ModeGrid:
    tplf.ItemTemplate = templates.Templates["grid"];
    break;
  case PaginationFeatures.ModeDetails:
    tplf.ItemTemplate = templates.Templates["details"];
    break;
}

- page 1 de 7