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:
Daca nu s-ar recurge la extensia markup Binding, codul de mai sus s-ar scrie astfel:
<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 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:
...
< 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.
<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:
iar definitia constructorului astfel:
{
Source = source;
}
Expression Blend abunda de astfel de extensii markup, care vin in ajutorul dezvoltatorilor si designerilor.
Niciun comentariu:
Trimiteți un comentariu