Dec 06

Le but de cet exemple est de montrer comment séparer la logique métier de l’interface utilisateur. Pour cela j’utilise un control qui publie un évènement spécifique (logique métier) et utilise un template (interface utilisateur) pour le rendu. Le template implément alors la convertion vers l’évènement du control. Vous pouvez étendre cet exemple avec l’utilisation d’un template différent suivant le thème choisi par l’utilisateur…cela fera peut-être l’objet d’un autre article.

Vous pouvez trouver le code source ici.

Pour implétenter cet example il faut:

  • implémenter le control qui charge le template
  • ajouter l’évènement spécific
  • remonter les évènement a partir du template
  • implémenter le template

Control chargeant un template

L’érreur la plus classique est d’oublié de dériver de INamingContainer qui permet de faire remonter les évènements venant du template.
[csharp]namespace BubbleEvent
{
[System.Web.UI.ToolboxData(”<{0}:TemplateControl runat=server />“)]
public class TemplateControl : System.Web.UI.WebControls.WebControl, System.Web.UI.INamingContainer
{
protected override void CreateChildControls()
{
Controls.Clear();
System.Web.UI.ITemplate template = Page.LoadTemplate(”mytemplate.ascx”);
template.InstantiateIn(this);
}
}
}[/csharp]
Ajout de l’évènement métier

Afin de simplifier, on pourrait utiliser System.Web.UI.WebControls.CommandEventArgs et System.Web.UI.WebControls.CommandEventHandler, mais je voulais montrer un exemple complet.
[csharp]namespace BubbleEvent
{

public class TemplateControl : System.Web.UI.WebControls.WebControl, System.Web.UI.INamingContainer
{

public event TemplateControlTextSelectedEventHandler TextSelected;

public delegate void TemplateControlTextSelectedEventHandler(object source, TemplateControlTextSelectedEventArgs e);

public class TemplateControlTextSelectedEventArgs : System.EventArgs
{
private System.String fText;
public System.String Text { get { return fText; } }
public TemplateControlTextSelectedEventArgs(System.String text)
{
fText = text;
}
}
}
}[/csharp]
Remonter l’évènement avec OnBubbleEvent

A noter: l’appel à base.OnBubbleEvent(sender, args). C’est utile dans le cas ou le control dériverai d’un autre custom control.
[csharp]namespace BubbleEvent
{

public class TemplateControl : System.Web.UI.WebControls.WebControl, System.Web.UI.INamingContainer
{
… protected override bool OnBubbleEvent(System.Object sender, System.EventArgs args)
{
if (base.OnBubbleEvent(sender, args))
return true;
if (args is TemplateControlTextSelectedEventArgs)
{
TemplateControlTextSelectedEventArgs textArgs = args as TemplateControlTextSelectedEventArgs;
if (TextSelected != null)
TextSelected(this, textArgs);
return true;
}
return false;
} …
}
}[/csharp]
Implémenter le template

Afin de montrer clairement la convertion entre un évènement lié à l’interface graphique (le template) et l’évènement métier, j’ai utilisé des évènements basé sur des boutons…ce qui est très différent par rapport a faire remonter du text. Le bouton fButtonHello doit fait remonter la chaine ‘Hello !’, alors que le bouton fButtonHelloAndName va faire remonter la chaine ‘Hello ‘avec le nom tapé dans le TextBox fName. Voici le template.

[asp]
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="mytemplate.ascx.cs" Inherits="mytemplate" %>
Name :


[/asp]

Il reste donc a implémenter la convertion.

[csharp]public partial class mytemplate : System.Web.UI.UserControl
{
void ButtonHelloClicked(object sender, System.EventArgs e)
{
RaiseBubbleEvent(this, new BubbleEvent.TemplateControl.TemplateControlTextSelectedEventArgs(”hello !”));
}
void ButtonHelloAndNameClicked(object sender, System.EventArgs e)
{
RaiseBubbleEvent(this, new BubbleEvent.TemplateControl.TemplateControlTextSelectedEventArgs(”hello ” + fName.Text + ” !”));
}
protected void Page_Load(object sender, System.EventArgs e)
{
fButtonHello.Click += new System.EventHandler(ButtonHelloClicked);
fButtonHelloAndName.Click += new System.EventHandler(ButtonHelloAndNameClicked);
}
}[/csharp]

Voila, l’essentiel est fait, il ne reste plus qu’a utiliser ce control dans une page.
[asp]
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register TagPrefix="custom" Namespace="BubbleEvent" %>




Result:



[/asp]
Et le code associé:
[csharp]public partial class _Default : System.Web.UI.Page
{
private void TextSelected(object sender, BubbleEvent.TemplateControl.TemplateControlTextSelectedEventArgs args)
{
fResult.Text = args.Text;
}

protected void Page_Load(object sender, System.EventArgs e)
{
fTemplate.TextSelected += new BubbleEvent.TemplateControl.TemplateControlTextSelectedEventHandler(TextSelected);
}
}
[/csharp]

Conclusion

On peut donc séparer la logique métier de l’interface utilisateur en utilsant un template pout l’interface et une classe métier implémentant des évènements métier. Cette technique est très bien adaptée pour faire une intégration AJAX: le template ait les appels AJAX qui relèbent de l’interface et ne remonent que les évènements métier pertinents.