Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide
Je dois avouer que ça fait longtemps que je n'avais pas fait touché à ASP.NET. Un peu comme Richard, j'avais commencé à m'intéresser à ASP.NET MVC il y a à peine 2 mois (lui aussi, très récemment!). Je dois toujours avouer qu'après avoir joué avec pendant quelques temps, je suis un peu déstabilisé quand j'essaie de revenir vers ASP.NET 3.5...
Dans le bon sens du terme Big Smile ! Le développement Web est, il faut l'avouer, plus facile avec et tout aussi puissant (pour ce que j'ai pu en faire). Pour un projet perso, je dois utiliser de l'ASP.NET ... J'ai eu tellement de mal que je me suis créé des classes pour faciliter mon développement.

Un petit exemple :

/// <summary>
///
/// </summary>
public static class HtmlHelper
{
/// <summary>
/// Permet de créer un champs de type input text Html à la façon de ASP.NET MVC
/// </summary>
/// <param name="fieldName">Nom du champs</param>
/// <returns></returns>
public static String TextBox(String fieldName)
{
if (String.IsNullOrEmpty(fieldName))
throw new ArgumentException("You must specified a value to create a textbox field");

return String.Format(@"<input type=""text"" name=""{0}"" value=""""/>", fieldName);
}

/// <summary>
/// Permet de créer un champs de type input password Html à la façon de ASP.NET MVC
/// </summary>
/// <param name="fieldName">Nom du champs</param>
/// <returns></returns>
public static String Password(String fieldName)
{
if (String.IsNullOrEmpty(fieldName))
throw new ArgumentException("You must specified a value to create a password field");

return String.Format(@"<input type=""password"" name=""{0}""/>", fieldName);
}

/// <summary>
/// Permet d'encoder une chaine (pour éviter les injections :) à la façon de ASP.NET MVC
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public static String Encode(String text)
{
if (text == null)
throw new ArgumentException("You can not encode a null field");

return HttpContext.Current.Server.HtmlEncode(text);
}

/// <summary>
///
/// </summary>
/// <param name="LinkText"></param>
/// <param name="LinkUrl"></param>
/// <returns></returns>
public static String ActionLink(String LinkText, String LinkUrl)
{
if (String.IsNullOrEmpty(LinkText) || String.IsNullOrEmpty(LinkUrl))
throw new ArgumentException("You can not create an action link with a blank/null argument");

return String.Format(@"<a href=""{0}"">{1}</a>", LinkUrl, LinkText);
}
}


Pour mes besoins, je n'ai pas besoin de l'ensemble des méthodes disponibles dans le classe HtmlHelper de MVC. Pratique en tout cas! Cela dit, je ne suis pas un Cyril, et je ne connais pas suffisamment la techno pour pouvoir les comparer ! Mais, c'est vrai que ça aide pas mal (^_^) !

Bien, allez, au boulot !

A +
8 commentaire(s)
Classé sous :
Toujours dans le même thème que mes précédents posts ( et ), je continuais mes utilisations des templates avec Silverlight. L'idée est de pouvoir créer un template modèle pour plusieurs contrôles de même type (En résumé, créer un thème).
Dans mon projet, je dispose de 5 boutons (voici un extrait de 2 boutons).

<Button Grid.Column="0"
x:Name="btnFirst"
Style="{StaticResource BtnStyle}"
Width="30"
HorizontalAlignment="Left"
Margin="0 2 0 2">
<Image Source="../Images/Controls/btnFirst.png" Height="15" Width="15" />
</Button>

<Button Grid.Column="1"
x:Name="btnFastRewind"
Style="{StaticResource BtnStyle}"
Width="30"
HorizontalAlignment="Left"
Margin="0 2 0 2">
<Image Source="../Images/Controls/btnFastRewind.png" Height="15" Width="15" />
</Button>



Voici le style que j'utilise (un peu similaire que ceux de mes précédents billets) :

<UserControl.Resources>
<vsm:Style x:Key="BtnStyle" TargetType="Button">
<vsm:Setter Property="Cursor" Value="Arrow"/>
<vsm:Setter Property="Background" Value="Transparent"/>
<vsm:Setter Property="Template">
<vsm:Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Grid.Resources>
<SolidColorBrush x:Key="BorderBrush" Color="#FFFFFF"/>
</Grid.Resources>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="CommonStates">
<vsm:VisualStateGroup.Transitions>
<vsm:VisualTransition Duration="0:0:0.3" To="MouseOver"/>
</vsm:VisualStateGroup.Transitions>
<vsm:VisualState x:Name="Normal"/>
<vsm:VisualState x:Name="MouseOver">
<Storyboard x:Name="MouseOverAnimation" >
<ColorAnimation
BeginTime="00:00:00"
Duration="0"
RepeatBehavior="Forever" AutoReverse="True"
Storyboard.TargetName="Background"
Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)"
To="#444444" />
</Storyboard>
</vsm:VisualState>
<vsm:VisualState x:Name="Pressed"/>
<vsm:VisualState x:Name="Disabled"/>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>

<Rectangle x:Name="Background"
Fill="{TemplateBinding Background}"
RadiusX="4" RadiusY="4"/>
<Rectangle x:Name="BackgroundGradient"
Stroke="{StaticResource BorderBrush}"
StrokeThickness="1" RadiusX="4" RadiusY="4"/>

<ContentPresenter
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"/>
</Grid>
</ControlTemplate>
</vsm:Setter.Value>
</vsm:Setter>
</vsm:Style>
</UserControl.Resources>


Tout compile correctement, mais, le menu n'a pas le comportement que j'attends. En effet, avec ce code, quand on survole mes 2 premiers boutons, le changement d'état n'opère pas, puis (sous Firefox en tout cas), la couleur de Background reste active après avoir effectué un premier clic !

Après avoir posé la question sur les forums Silverlight, j'ai été éclairé sur les raisons de ce mauvais fonctionnement... Je cite :

[...] you need to set Background in your Button xaml because you rely on the TemplateBinding for the Rectangle.Fill property which can be any kind of Brush. So you'd better initialize it with Solid color Brush. Otherwise, the animation does not find the target. [...]

La solution se trouve donc dans le forum. ça me laisse cependant un peu perplexe, car j'étais pourtant sûr qu'en initialisant la propriété Fill du Rectangle (bindé à la propriété Background au début de mon style), au moins un type de Brush était initialisé... Je reviendrai cependant là dessus... (Sauf si vous avez une réponse supplémentaire :-) ).

Voilà!

A +



0 commentaire(s)
Classé sous :
Dans mon billet précédent,je rappelais un peu comment avec Silverlight on pouvait créer un bouton (Texte et Image) avec un effet de MouseOver. Ici, je vais faire juste rappeler comment créer un Contrôle qui sera facilement réutilisable (là aussi, rien de compliqué :-) ).

Pour ce faire, je créé un nouveau UserControl (en incluant son CodeBehind) TopMenuButton.xaml par exemple.

<UserControl
  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"
  x:Class="MonProjet.TopMenuButton"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">
  
  <UserControl.Resources>
    <vsm:Style x:Key="BtnTopMenuStyle" TargetType="Button">
     <vsm:Setter Property="Foreground" Value="#FFFFFF"/>
     <vsm:Setter Property="Cursor" Value="Arrow"/>
     <vsm:Setter Property="TextAlignment" Value="Left"/>
     <vsm:Setter Property="TextWrapping" Value="NoWrap"/>
     <vsm:Setter Property="FontSize" Value="10"/>
     <vsm:Setter Property="Template">
        <vsm:Setter.Value>
          <ControlTemplate TargetType="Button">
            <Grid>
              <Grid.Resources>
              <!-- Grid.Resources Here -->
              </Grid.Resources>
              <vsm:VisualStateManager.VisualStateGroups>
                <vsm:VisualStateGroup x:Name="CommonStates">
                  <vsm:VisualStateGroup.Transitions>
                    <vsm:VisualTransition Duration="0:0:0.3" To="MouseOver"/>
                  </vsm:VisualStateGroup.Transitions>
                  <vsm:VisualState x:Name="Normal"/>
                  <vsm:VisualState x:Name="MouseOver">
                    <Storyboard>
                    <ColorAnimation Duration="0"
Storyboard.TargetName="Background"
Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)"
To="Black" />
                    </Storyboard>
                  </vsm:VisualState>
                                      
                </vsm:VisualStateGroup>
                  
              </vsm:VisualStateManager.VisualStateGroups>
              <Rectangle x:Name="Background" RadiusX="4" RadiusY="4" Fill="{TemplateBinding Background}"/>
              <ContentPresenter
                HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                Padding="{TemplateBinding Padding}"
                VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                Margin="4,5,4,4"
                Content="{TemplateBinding Content}"
                ContentTemplate="{TemplateBinding ContentTemplate}"
                TextAlignment="{TemplateBinding TextAlignment}"
                TextDecorations="{TemplateBinding TextDecorations}"
                TextWrapping="{TemplateBinding TextWrapping}"/>
            </Grid>
          </ControlTemplate>
        </vsm:Setter.Value>
      </vsm:Setter>
    </vsm:Style>
</UserControl.Resources>

<Button Background="Transparent"
x:Name="btnTopMenu"
Style="{StaticResource BtnTopMenuStyle}"
Loaded="btnTopMenu_Loaded">
   <StackPanel Orientation="Horizontal">
     <Image x:Name="imgTopMenu" Margin="0, 0, 5, 0" />
     <TextBlock x:Name="tblTopMenu" VerticalAlignment="Center" Margin="0" />
   </StackPanel>
</Button>

</UserControl>



Le bouton est rendu ici (par rapport au billet précédent) beaucoup plus générique, j'ai aussi rajouté l'évènement Loaded (j'en parlerai plus bas), et j'identifie chacun des éléments enfants de mon bouton.

Je vais créer 2 propriétés maintenant pour mon bouton. Une relative à l'Url de mon image (ImageSource), et l'autre relative au texte que je veux afficher pour le bouton (MenuText).


public String ImageSource
{
   get { return (String)GetValue(ImageSourceProperty); }
   set { SetValue(ImageSourceProperty, value); }
}

public String MenuText
{
   get { return (String)GetValue(MenuTextProperty); }
   set { SetValue(MenuTextProperty, value); }
}

public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register(
"ImageSource", typeof(String), typeof(TopMenuButton), new PropertyMetadata(OnImageSourceChanged));

public static readonly DependencyProperty MenuTextProperty = DependencyProperty.Register(
"MenuText", typeof(String), typeof(TopMenuButton), new PropertyMetadata(OnMenuTextChanged));


private static void OnImageSourceChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) {
   if (e.NewValue != null)
   {
     // Your code here
   }
}

private static void OnMenuTextChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) {
   if (e.NewValue != null)
   {
     // Your code here
   }
}


L'utilisation des propriétés simples / DependencyProperty, y compris la création de propriétés, Thomas en parlait dans un de ses billets, il y a déjà bien longtemps. Nous n'y reviendrons donc pas :-).

Bien, notre gestionnaire d'évènement Loaded. Quand nos propriétés seront initialisées sur notre contrôle réutilisable, il faudra les initialiser aussi sur les contrôles enfants (le TextBlock et l'Image). C'est à dire que quand je vais mettre à jour la propriété ImageSource de mon TopMenuButton, il faudra mettre à jour la propriété Source de mon Image et etc... (Vous l'aviez déjà compris :-) ).

C'est lors de l'évènement Loaded qu'il faut donc le faire (et pas dans le constructeur de notre contrôle, car ce dernier doit d'abord être initialisé avant de pouvoir accéder aux propriétés des contrôles enfants qui le compose).

private void btnTopMenu_Loaded(object sender, RoutedEventArgs e)
{
   this.imgTopMenu.Source = ResourceHelper.GetBitmap(ImageSource);
   this.tblTopMenu.Text = MenuText;
}


ResourceHelper est une petite classe simple que j'ai trouvé et qui permet de charger à partir d'un chemin (et éventuellement du nom d'une assembly), une ressource (BitmapImage, String, Xaml, ou FontSource, etc...).

Voilà, notre contrôle est prêt. Dans ma page principale (.xaml), je rajoute à l'élement UserControl

xmlns:MonProjet="clr-namespace:MonProjet"

afin de pouvoir référencer puis utiliser mon nouveau contrôle de cette façon :

<MonProjet:TopMenuButton
x:Name="btnAddContent"
        Grid.Column="0"
        MenuText="Menu 01"
        ImageSource="Images/top_menu_01.png" />
      
      <MonProjet:TopMenuButton
x:Name="btnCreatePublicPage"
            Grid.Column="1"
            MenuText="Menu 02"
            ImageSource="Images/top_menu_02.png" />



Fin du rappel :-).

Bonne journée, et A bientôt.

0 commentaire(s)
Classé sous : ,
Un petit rappel concernant les templates et les "états" des contrôles.  J’ai voulu donc créer un bouton très simple. Il s'agit d'un contrôle Button très personnalisé (Une image à gauche, du texte à droite, pas d’arrière plan, ni de bordures sur le bouton, et un rollover changeant l'arrière-plan de notre nouveau contrôle).
Pas encore très à l’aise avec Blend, j’utilise donc son éditeur XAML donc pour écrire mes templates. Voici le code de mon bouton:

<Button Background="Transparent"
        x:Name="btnAddContent"
        Grid.Column="0"
        Style="{StaticResource BtnAddContentStyle}">
     <StackPanel Orientation="Horizontal">
         <Image Source="Images/menu_icon_01.png"
                Margin="0, 0, 5, 0" />
         <TextBlock Text="Add Content"
                    VerticalAlignment
="Center"
                    Margin="0" />
    </StackPanel>
</Button>

Mon premier réflexe (pas toujours les meilleurs) est de créer mon template comme celui ci (fonctionnel sur la Beta 1 ) :

<Style TargetType="Button" x:Key="Btn3Style4444">
  <Setter Property="FontSize" Value="10" />
  <Setter Property="Foreground" Value="White" />
  <Setter Property="Cursor" Value="Hand" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="Button">
        <Grid x:Name="RootElement">
          <Rectangle x:Name="Background"
                     RadiusY="5"
                     RadiusX="5" Background>
            <Rectangle.Fill>
              <SolidColorBrush x:Name="BackgroundBrush"
                               Color
="Transparent" />
            </Rectangle.Fill>
          </Rectangle>
          <ContentPresenter
            Content="{TemplateBinding Content}"
            ContentTemplate="{TemplateBinding ContentTemplate}"
            FontSize="{TemplateBinding FontSize}"
            Foreground="{TemplateBinding Foreground}"
            HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
            TextAlignment="{TemplateBinding TextAlignment}"
            TextDecorations="{TemplateBinding TextDecorations}"
            TextWrapping="{TemplateBinding TextWrapping}"
            VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
          />
          <Grid.Resources>
            <Storyboard x:Key="MouseOver State">
              <ColorAnimation
                Duration="0"
                Storyboard.TargetName="BackgroundBrush"
                Storyboard.TargetProperty="Color"
                To="Black"
              />
            </Storyboard>
          </Grid.Resources>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>


Ce code qui pourtant compile sans problème ne me permettra pas de changer l’état de mon bouton. En effet, en générant un template à partir d’un contrôle existant, je me suis rappelé du Visual State Manager (je ne mets pas de lien sinon, je devrais en mettre trop ;p). Une des nouvelles fonctionnalités de Silverlight 2 Beta 2 qui permet très facilement de skinner ses contrôles.

Mon code précédent deviendra ainsi:

<vsm:Style x:Key="BtnAddContentStyle"
           TargetType
="Button">
        <vsm:Setter Property="Foreground" Value="#FFFFFF"/>
        <vsm:Setter Property="Cursor" Value="Arrow"/>
        <vsm:Setter Property="FontSize" Value="10"/>
        <vsm:Setter Property="Template">
          <vsm:Setter.Value>
            <ControlTemplate TargetType="Button">
              <Grid>
                <Grid.Resources>
                <!-- Grid.Resources Here -->
                </Grid.Resources>
                <vsm:VisualStateManager.VisualStateGroups>
                  <vsm:VisualStateGroup x:Name="CommonStates">
                    <vsm:VisualStateGroup.Transitions>
                      <vsm:VisualTransition Duration="0:0:0.3" To="MouseOver"/>
                    </vsm:VisualStateGroup.Transitions>
                    <vsm:VisualState x:Name="Normal"/>
                    <vsm:VisualState x:Name="MouseOver">
                      <Storyboard>
                      <ColorAnimation
                            Duration="0"
                            Storyboard.TargetName="Background"
                            Storyboard.TargetProperty="(Rectangle.Fill).(SolidColorBrush.Color)"
                            To="Black" />
                      </Storyboard>
                    </vsm:VisualState>
                  </vsm:VisualStateGroup>
                </vsm:VisualStateManager.VisualStateGroups>
                <Rectangle x:Name="Background"
                           RadiusX
="4"
                           RadiusY="4"
                           Fill
="{TemplateBinding Background}"/>
                <ContentPresenter
                  HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                  Padding="{TemplateBinding Padding}"
                  VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                  Margin="4,5,4,4"
                  Content="{TemplateBinding Content}"
                  ContentTemplate="{TemplateBinding ContentTemplate}"
                  TextAlignment="{TemplateBinding TextAlignment}"
                  TextDecorations="{TemplateBinding TextDecorations}"
                  TextWrapping="{TemplateBinding TextWrapping}"/>
              </Grid>
            </ControlTemplate>
          </vsm:Setter.Value>
        </vsm:Setter>
      </vsm:Style>

Voilà pour le petit rappel.

Bonne soirée et bon skinning!


0 commentaire(s)
Classé sous :