Archive

Posts Tagged ‘Binding’

WP7 – Faîtes attention à la méthode utilisée pour formater votre DataBinding !

Je me suis mis au développement sous la plateforme Windows Phone 7 en codant une petite application que je mettrai bientôt sur le Marketplace donc comme on dit en anglais « stay tuned! ».

Au cours du développement, j’ai énormément utilisé le Databinding (normal vu que j’utilise aussi le pattern MVVM) et si vous ne l’avez pas remarquée, le DataBinding propose une propriété StringFormat qui permet de formater le résultat issu du binding. Je peux citer comme exemple le fait de formater une date. C’est au sujet du formatage du binding que j’ai fait ce billet parce qu’à ma grande surprise une méthode que j’utilisais pour spécifier le format d’une date et qui marchait sous WPF et Silverlight (Application Web RIA) ne marche pas sous Windows Phone alors qu’on utilise Silverlight pour développer sous cette plateforme.
En WPF et Silverlight pour formater une date pour avoir seuls le jour, le mois et l’année sans l’heure dans l’affichage on a les trois méthodes suivantes :

1ère méthode :

<!-- Les deux premiers accolades {} avant le format sont là pour spécifier au moteur XAML 
de ne pas prendre en compte les accolades qui suivront juste après. --> 
<TextBlock Foreground="Red"
   FontSize="50"
   Text="{Binding Path=Date, StringFormat={}{0:dd/MM/yyyy}}" />

2ème méthode :

<!-- On utilise le '\' pour échapper les accolades qui sont dans le format --> 
<TextBlock Foreground="Red"
   FontSize="50"
   Text="{Binding Path=Date, StringFormat=\{0:dd/MM/yyyy\}}" />

3ème méthode :

<!-- On met juste le format pour en prenant soin de l'entourer avec des quotes simples --> 
<TextBlock Foreground="Red"
   FontSize="50"
   Text="{Binding Path=Date, StringFormat='dd/MM/yyyy'}" />

Cool ! Nous avons 3 méthodes qui nous permettent de faire ce qu’on veut. La méthode que je préfère c’est la première (les goûts ne se discutent pas !). Donc c’est normal que je l’ai utilisée dans mon application Windows Phone 7. En design mode tout est correct, la date s’affiche dans le format voulu mais lorsqu’on compile l’application le compilateur nous renvoie l’erreur suivante :

Erreur binding lors de la compilation

Pensant avoir affaire à un format mal effectué mais il se trouve que non. La première méthode, qui elle marche avec WPF et Sivleright RIA, ne marche pas sous Windows Phone 7 ou ne marche qu’en Design Mode. Pour corriger cela il faudra passer par l’une des deux dernières méthodes citées précédemment.

j’espère que ce billet vous a appris quelque chose et vous fera gagner du temps vu que moi j’en ai perdu pas moins de 30mn avant de le savoir parce que j’étais sûr à 100% que mon format était correct SOUS WINDOWS PHONE 7 et surtout qu’en design mode l’affichage correspondait à ce que j’attendais 🙂 .

Nota Béné : Mon application a été codée avec la version RC du SDK Windows Phone 7 – Mango donc il se peut ce petit bug soit corrigé dans les versions futures.

Publicités
Catégories :Windows Phone 7 Étiquettes : , ,

Faire du MutliBinding sans utiliser la classe MutliValueConverter, c’est possible !

J’ai longtemps cru qu’il était impossible de faire du MultiBinding sans disposer au préalable d’un converter c’est à dire d’une instance d’une classe dérivant de la classe de base MultiValueConverter.
Il n’y a qu’à voir cette discussion où je mettais à défi les membres du forum pour me sortir un exemple de cas d’utilisation où l’instance d’un MutliValueConverter ne serait pas indispensable.
Le fait que j’ai lancé ce défi était dû à deux choses :

  1. La première est liée au fonctionnement même du MultiBinding. Ce dernier recevant plusieurs bindings en paramètre alors il doit savoir comment les afficher donc on avait besoin d’une classe dérivant de la classe de base MutliValueConverter pour combiner ces différents bindings et fournir un résultat final.
  2. Quand on oublie de spécifier un converter dans le MutliBinding, nous remarquons le message « Impossible de définir MutliBinding parce que MutliValueConverter doit être spécifié » nous est renvoyé pas Visual Studio.

Bon ! Après des recherches sur le net, j’en suis arrivé à la conclusion suivante : il est bien possible de faire du MultiBinding sans utiliser une classe dérivant de la classe MutliValueConverter. Il suffit d’utiliser la propriété StringFormat de l’instancce de notre MultiBinding..

Comme on le dit souvent du code vaut mieux qu’un long discours alors voici un exemple de cas d’utilisation très simple :

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
 
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
 
        <ComboBox x:Name="cb1" Grid.Column="0" Margin="2">
            <ListBoxItem Content="Item 0 - 1" />
            <ListBoxItem Content="Item 0 - 2" />
            <ListBoxItem Content="Item 0 - 3" />
            <ListBoxItem Content="Item 0 - 4" />
            <ListBoxItem Content="Item 0 - 5" />
        </ComboBox>
 
        <ComboBox x:Name="cb2" Grid.Column="1" Margin="2">
            <ListBoxItem Content="Item 1 - 1" />
            <ListBoxItem Content="Item 1 - 2" />
            <ListBoxItem Content="Item 1 - 3" />
            <ListBoxItem Content="Item 1 - 4" />
            <ListBoxItem Content="Item 1 - 5" />
        </ComboBox>
 
        <TextBlock Grid.ColumnSpan="2" Grid.Row="1">
            <TextBlock.Text>
                <MultiBinding StringFormat="cbOne : {0} ### cbTwo : {1}" FallbackValue="Deux items doivent être sélectionnés">
                    <Binding Path="SelectedItem.Content" ElementName="cb1" />
                    <Binding Path="SelectedItem.Content" ElementName="cb2" />
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
    </Grid>

La propriété StringFormat du MultiBinding fonctionne comme la méthode statique Format de la classe String. Cette propriéte reçoit en paramètre le format à utiliser et les paramètres qui lui sont passés sont les valeurs des différents bindings

Avec le code XAML ci-dessus, vous verrez que Visual Studio devient muet et nous n’affiche plus le message d’erreur précédent. Je pense d’ailleurs que ce message devait plutôt être « Impossible de définir MutliBinding parce que MutliValueConverter ou StringFormat doit être spécifié ».

Catégories :WPF Étiquettes : , ,

Utiliser un ancêtre comme source du binding est possible en Silverlight 5

La version Beta 1 de Silverlight 5 sortie il y a quelques jours nous permet enfin de spécifier comme source du binding un des ancêtres d’un élément. Dans les versions de Silverlight 3 et 4, seuls les modes Self et TemplateParent étaient supportés alors qu’en WPF nous avons en plus de ces deux modes deux autres qui sont PreviousData et FindAncestor (qui nous permet de spécifier comme source du binding un ancêtre du contrôle). Au fil des développements le besoin de spécifier un ancêtre comme source se faisait de plus en plus sentir et différentes méthodes de controunement avaient déjà été mises en place par des développeurs. Maintenant plus besoin de ces méthodes, SL5 permet de faire cela comme dans WPF.
L’exemple de code suivant utilise comme source du binding le contrôle StackPanel qui représente un des ancêtres du bouton sur lequel s’effectue le binding :

<UserControl x:Class="SilverlightApplication11.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <StackPanel x:Name="LayoutRoot" Background="White" Tag="Tag from StackPanel">
        <Rectangle Height="50" Fill="Green" x:Name="myRectangle" />
        <Button Content="{Binding Path=Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType=StackPanel}}" />
    </StackPanel>
</UserControl>

Bien que le mode FindAncestor soit maintenant présent, le mode PreviousData (très rarement utilisé dans WPF d’ailleurs) n’est pas encore présent dans cette béta de Silvelright 5.

Catégories :Silverlight Étiquettes : , ,

Comment synchroniser le contenu de deux ScrollViewer ?

J’ai eu à travailler à mes débuts en WPF 😉 sur un projet où je devais faire la synchronisation du contenu de deux ScrollViewer. Pour y arriver j’ai dû passer par les propriétés de dépendances attachées et ainsi bénéficier du binding entre les propriétés VerticalOffset des deux contrôles. Pour infos la proprieté VerticalOffset du contrôle ScrollViewer est en lecture .

Le code que j’ai mis en place et qui m’a permis d’arriver à mes fins est le suivant :

public class ScrollViewerBehaviors
{
	public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.RegisterAttached("VerticalOffset", typeof(double), typeof(ScrollViewerBehaviors), new PropertyMetadata(0.0, ScrollViewerBehaviors.offsetChanged));
	public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.RegisterAttached("HorizontalOffset", typeof(double), typeof(ScrollViewerBehaviors), new PropertyMetadata(0.0, ScrollViewerBehaviors.offsetChanged));

	public static double GetVerticalOffset(UIElement scrollViewer)
	{
		return (Double)scrollViewer.GetValue(ScrollViewerBehaviors.VerticalOffsetProperty);
	}
	public static void SetVerticalOffset(UIElement scrollViewer, object value)
	{
		scrollViewer.SetValue(ScrollViewerBehaviors.HorizontalOffsetProperty, value);
	}

	public static double GetHorizontalOffset(UIElement scrollViewer)
	{
		return (Double)scrollViewer.GetValue(ScrollViewerBehaviors.HorizontalOffsetProperty);
	}
	public static void SetHorizontalOffset(UIElement scrollViewer, object value)
	{
		scrollViewer.SetValue(ScrollViewerBehaviors.HorizontalOffsetProperty, value);
	}

	private static void offsetChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
	{
		ScrollViewer scrollViewer = depObj as ScrollViewer;
		if (scrollViewer == null) return;

		double offset = e.NewValue == null ? 0 : (double)e.NewValue;
		switch (e.Property.Name)
		{
			case "VerticalOffset":
				scrollViewer.ScrollToVerticalOffset(offset);
				break;

			case "HorizontalOffset":
				scrollViewer.ScrollToHorizontalOffset(offset);
				break;
		}
	}
}

Côté interface rien de plus simple tout se fait dans le xaml :

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
         
        <ScrollViewer x:Name="scrollViewerOne" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" 
                      local:ScrollViewerBehaviors.VerticalOffset="{Binding ElementName=scrollViewerTwo, Path=VerticalOffset, Mode=OneWay}"
                      local:ScrollViewerBehaviors.HorizontalOffset="{Binding ElementName=scrollViewerTwo, Path=HorizontalOffset, Mode=OneWay}">
            <Image Source="/Chrysanthemum.jpg" Width="1000" />
        </ScrollViewer>

        <ScrollViewer Grid.Column="1" x:Name="scrollViewerTwo" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" 
                      local:ScrollViewerBehaviors.VerticalOffset="{Binding ElementName=scrollViewerOne, Path=VerticalOffset, Mode=OneWay}"
                      local:ScrollViewerBehaviors.HorizontalOffset="{Binding ElementName=scrollViewerOne, Path=HorizontalOffset, Mode=OneWay}">
            <Image Source="/Chrysanthemum.jpg" Width="1000" />
        </ScrollViewer>
    </Grid>
Catégories :Silverlight, WPF Étiquettes : , ,
%d blogueurs aiment cette page :