Markup Extensions

Extensiile markup (markup extensions) sunt elemente importante ale XAML, foarte des folosite, care simplifica mult sintaxa XAML. Ele sunt identificate intre acoladele din XAML. Printre cele mai folosite extensii sunt Binding, StaticResource si DynamicResource. Spre exemplu, extensia Binding poate fi folosita in XAML astfel:

<TextBlock Text="{Binding Message}" />

Daca nu s-ar recurge la extensia markup Binding, codul de mai sus s-ar scrie astfel:

< TextBlock>
    <TextBlock.Text>
        <Binding Path="Message" />
    </TextBlock.Text>
< /TextBlock.Text>

Se observa o sintaxa mult mai stufoasa decat cea in care se foloseste extensia markup Binding.

Microsoft pune la dispozitia dezvoltatorilor o clasa abstracta, MarkupExtension, cu ajutorul careia dezvoltatorii pot sa-si creeze propriile extensii markup. Aceasta clasa pune la dispozitie o metoda abstracta, ProvideValue, care returneaza un obiect care reprezinta valoarea proprietatii tinta pentru aceasta extensie markup.

Sa vedem acum cum putem folosi aceasta clasa abstracta, ca sa ne definim propria extensie markup. Dorim sa scriem o extensie care se ne usureze citirea unui fisier XML, care contine mesaje, si sa folosim aceste mesaje ca sursa a unui control de tip ListBox. Textul mesajelor continute de elementul ListBox va fi albastru. Conventia este ca orice clasa care deriva din clasa abstracta MarkupExtension sa aiba sufixul Extension. In codul XAML, sufixul este ignorat. Astfel, vom crea o noua clasa, MessagesExtension, care mosteneste clasa MarkupExtension. Implementarea clasei arata ca mai jos.

public class  MessagesExtension  :  MarkupExtension
{
    public string  Source   {  get;   set;   }

    public override object  ProvideValue(IServiceProvider  provider)
    {
        // Obtine elementul tinta si-i seteaza culoarea textului
        var  target = provider.GetService(typeof(IProvideValueTarget))  as  IProvideValueTarget;
        if  (target != null  &&   target.TargetObject  is  Control)
            ((Control)target.TargetObject).Foreground = Brushes.Blue;

        // Creaza si returneaza sursa de tip IList< string>
        IList< string> result   =   new  List< string>();
        try
        {
            var  doc  =   XDocument.Load(Source);
            if  (doc != null  &&   doc.Root  != null)
            {
                foreach  (XElement  node   in  doc.Root.Nodes())
                    result.Add(node.Value);
            }
        }
        catch  (Exception  e)
        {
            Debug.WriteLine(e.Message);
        }
        return  result;
    }
}

Clasa abstracta MarkupExtension si interfata IProvideValueTarget necesita namespace-ul System.Windows.Markup, clasa Control namespace-ul System.Windows.Controls, interfata IList si clasa List namespace-ul System.Collections.Generic, clasa Brushes namespace-ul System.Windows.Media iar clasa XDocument namespace-ul System.Xml.Linq.

Clasa tocmai definita poate fi folosita din XAML astfel:

< Window  xmlns:ext="clr-namespace:namespace_definitie_clasa_markup" ... >
    ...
    < ListBox  ... ItemsSource="{ext:Messages  Source=Messages.xml}" ... />
    ...
< /Window>

Atributul Source contine calea spre fisierul de mesaje messages.xml. Continutul fisierului messages.xml poate fi vizualizat mai jos.

<Messages>
    <Message>Test message 1< /Message>
    <Message>Test message 2< /Message>
    <Message>Test message 3< /Message>
    <Message>Test message 4< /Message>
    <Message>Test message 5< /Message>
< /Messages>

Sintaxa XAML poate fi simplificata prin renuntarea la atributul Source, daca se defineste un constructor cu un parametru de tip string, care sa seteze proprietatea Source. Atunci, codul XAML va arata astfel:

< ListBox  ... ItemsSource="{ext:Messages  Messages.xml}" ... />

iar definitia constructorului astfel:

public  MessagesExtension(string  source)
{
    Source = source;
}

Expression Blend abunda de astfel de extensii markup, care vin in ajutorul dezvoltatorilor si designerilor.

Niciun comentariu:

Trimiteți un comentariu