Esporta (0) Stampa
Espandi tutto
Il presente articolo è stato tradotto automaticamente. Passare il puntatore sulle frasi nell'articolo per visualizzare il testo originale. Ulteriori informazioni.
Traduzione
Originale

Cenni preliminari sui modelli di dati

Il modello di creazione di modelli di dati WPF consente una notevole flessibilità per definire la presentazione dei dati. I controlli WPF dispongono di funzionalità incorporate per supportare la personalizzazione della presentazione dei dati. In questo argomento viene innanzitutto illustrato come definire un oggetto DataTemplate e vengono presentate altre funzionalità di creazione di modelli di dati, quali la selezione di modelli in base a logica personalizzata e il supporto per la visualizzazione di dati gerarchici.

Di seguito sono elencate le diverse sezioni di questo argomento.

In questo argomento vengono illustrate le funzionalità relative ai modelli di dati, non vengono presentati concetti di associazione dati. Per informazioni sui concetti di base relativi all'associazione dati, vedere Cenni preliminari sull'associazione dati.

DataTemplate concerne la presentazione dei dati e rappresenta una delle numerose funzionalità fornite dal modello di creazione di stili e modelli WPF. Per un'introduzione al modello di creazione di stili e modelli WPF, ad esempio per informazioni sull'utilizzo di un oggetto Style per l'impostazione di proprietà sui controlli, vedere l'argomento Applicazione di stili e modelli.

È inoltre importante comprendere il concetto di Resources, essenziale per rendere riutilizzabili oggetti quali Style e DataTemplate. Per ulteriori informazioni sulle risorse, vedere Risorse XAML.

Nella presente sezione sono contenute le seguenti sottosezioni.

Di seguito viene fornito un esempio di associazione dati con cui viene illustrata l'importanza di DataTemplate. In questo esempio, ListBox è associato a un elenco di oggetti Task. Ogni oggetto Task dispone di TaskName (stringa), Description (stringa), Priority (int) e una proprietà di tipo TaskType, costituita da Enum con valori Home e Work.


<Window x:Class="SDKSample.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:SDKSample"
  Title="Introduction to Data Templating Sample">
  <Window.Resources>
    <local:Tasks x:Key="myTodoList"/>


...



</Window.Resources>
  <StackPanel>
    <TextBlock Name="blah" FontSize="20" Text="My Task List:"/>
    <ListBox Width="400" Margin="10"
             ItemsSource="{Binding Source={StaticResource myTodoList}}"/>


...


  </StackPanel>
</Window>


ms742521.collapse_all(it-it,VS.110).gifSenza DataTemplate

Senza DataTemplate, l'oggetto ListBox attualmente si presenta come segue:

Schermata dell'esempio Introduction to Data Templating

In assenza di istruzioni specifiche, per impostazione predefinita ListBox chiama ToString quando tenta di visualizzare gli oggetti nella raccolta. Pertanto, se l'oggetto Task esegue l'override del metodo ToString, ListBox visualizza la rappresentazione di stringa di ogni oggetto di origine nella raccolta sottostante.

Ad esempio, se la classe Task esegue l'override del metodo ToString in questo modo, dove name è il campo per la proprietà TaskName:


public override string ToString()
{
    return name.ToString();
}


ListBox avrà l'aspetto seguente:

Schermata dell'esempio Introduction to Data Templating

Ciò è tuttavia limitante e poco flessibile. Inoltre, in caso di associazione a dati XML, non sarà possibile eseguire l'override di ToString.

ms742521.collapse_all(it-it,VS.110).gifDefinizione di DataTemplate semplice

La soluzione consiste nel definire un oggetto DataTemplate. A tale scopo è possibile impostare la proprietà ItemTemplate di ListBox su DataTemplate. Quanto viene specificato in DataTemplate diventa la struttura visiva dell'oggetto dati. L'oggetto DataTemplate seguente è abbastanza semplice. Vengono fornite istruzioni affinché ogni elemento venga visualizzato come tre elementi TextBlock in un oggetto StackPanel. Ogni elemento TextBlock è associato a una proprietà della classe Task.


<ListBox Width="400" Margin="10"
         ItemsSource="{Binding Source={StaticResource myTodoList}}">
   <ListBox.ItemTemplate>
     <DataTemplate>
       <StackPanel>
         <TextBlock Text="{Binding Path=TaskName}" />
         <TextBlock Text="{Binding Path=Description}"/>
         <TextBlock Text="{Binding Path=Priority}"/>
       </StackPanel>
     </DataTemplate>
   </ListBox.ItemTemplate>
 </ListBox>


I dati sottostanti per gli esempi riportati in questo argomento sono rappresentati da una raccolta di oggetti CLR. In caso di associazione a dati XML, i concetti fondamentali sono gli stessi, ma vi è una leggera differenza sintattica. Ad esempio, anziché avere Path=TaskName, è necessario impostare XPath su @TaskName (se TaskName è un attributo del nodo XML).

Ora ListBox avrà l'aspetto seguente:

Schermata dell'esempio Introduction to Data Templating

ms742521.collapse_all(it-it,VS.110).gifCreazione di DataTemplate come una risorsa

Nell'esempio precedente è stato definito l'oggetto DataTemplate inline. È più comune definire questo oggetto nella sezione risorse in modo che possa essere riutilizzabile, come nell'esempio seguente:


<Window.Resources>


...


<DataTemplate x:Key="myTaskTemplate">
  <StackPanel>
    <TextBlock Text="{Binding Path=TaskName}" />
    <TextBlock Text="{Binding Path=Description}"/>
    <TextBlock Text="{Binding Path=Priority}"/>
  </StackPanel>
</DataTemplate>


...


</Window.Resources>


È ora possibile utilizzare myTaskTemplate come risorsa, come nell'esempio seguente:


<ListBox Width="400" Margin="10"
         ItemsSource="{Binding Source={StaticResource myTodoList}}"
         ItemTemplate="{StaticResource myTaskTemplate}"/>


Poiché myTaskTemplate è una risorsa, è possibile utilizzarlo in altri controlli che dispongono di una proprietà che accetta un tipo DataTemplate. Come illustrato nell'esempio precedente, per gli oggetti ItemsControl quali ListBox, si tratta della proprietà ItemTemplate. Per gli oggetti ContentControl, si tratta della proprietà ContentTemplate.

ms742521.collapse_all(it-it,VS.110).gifProprietà DataType

La classe DataTemplate ha una proprietà DataType molto simile alla proprietà TargetType della classe Style. Pertanto, anziché specificare x:Key per l'oggetto DataTemplate nell'esempio precedente, è possibile eseguire le operazioni seguenti:


<DataTemplate DataType="{x:Type local:Task}">
  <StackPanel>
    <TextBlock Text="{Binding Path=TaskName}" />
    <TextBlock Text="{Binding Path=Description}"/>
    <TextBlock Text="{Binding Path=Priority}"/>
  </StackPanel>
</DataTemplate>


Questo oggetto DataTemplate viene automaticamente applicato a tutti gli oggetti Task. Si noti che in questo caso x:Key viene impostato implicitamente. Pertanto, se si assegna a questo oggetto DataTemplate un valore x:Key, viene eseguito l'override del valore x:Key implicito e DataTemplate non viene applicato automaticamente.

Se si associa un oggetto ContentControl a una raccolta di oggetti Task, ContentControl non utilizza automaticamente l'oggetto DataTemplate illustrato in precedenza. Questo comportamento è dovuto al fatto che l'associazione su un oggetto ContentControl richiede ulteriori informazioni per distinguere se si desidera effettuare l'associazione a una raccolta intera o a singoli oggetti. Se l'oggetto ContentControl sta rilevando la selezione di un tipo ItemsControl, è possibile impostare la proprietà Path dell'oggetto ContentControl associato a "/" in modo da indicare che si è interessati all'elemento corrente. Per un esempio, vedere Procedura: eseguire l'associazione di una raccolta e visualizzare informazioni in base alla selezione effettuata. In caso contrario, è necessario specificare in modo esplicito l'oggetto DataTemplate impostando la proprietà ContentTemplate.

La proprietà DataType è particolarmente utile quando si ha un oggetto CompositeCollection costituito da tipi diversi di oggetti dati. Per un esempio, vedere Procedura: implementare un oggetto CompositeCollection.

Attualmente i dati vengono visualizzati con le informazioni necessarie, ma sono possibili miglioramenti. Di seguito verrà migliorata la presentazione con l'aggiunta di Border, Grid e alcuni elementi TextBlock che descrivono i dati visualizzati.



<DataTemplate x:Key="myTaskTemplate">
  <Border Name="border" BorderBrush="Aqua" BorderThickness="1"
          Padding="5" Margin="5">
    <Grid>
      <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
        <RowDefinition/>
      </Grid.RowDefinitions>
      <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
      </Grid.ColumnDefinitions>
      <TextBlock Grid.Row="0" Grid.Column="0" Text="Task Name:"/>
      <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=TaskName}" />
      <TextBlock Grid.Row="1" Grid.Column="0" Text="Description:"/>
      <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=Description}"/>
      <TextBlock Grid.Row="2" Grid.Column="0" Text="Priority:"/>
      <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=Priority}"/>
    </Grid>
  </Border>


...


</DataTemplate>


Nella schermata riportato di seguito viene illustrato l'oggetto ListBox con l'oggetto DataTemplate modificato:

Schermata dell'esempio Introduction to Data Templating

È possibile impostare HorizontalContentAlignment su Stretch sull'oggetto ListBox per assicurarsi che la larghezza degli elementi occupi l'intero spazio:


<ListBox Width="400" Margin="10"
     ItemsSource="{Binding Source={StaticResource myTodoList}}"
     ItemTemplate="{StaticResource myTaskTemplate}" 
     HorizontalContentAlignment="Stretch"/>


Con la proprietà HorizontalContentAlignment impostata su Stretch, ListBox ha ora l'aspetto seguente:

Schermata dell'esempio Introduction to Data Templating

ms742521.collapse_all(it-it,VS.110).gifUtilizzo di DataTrigger per applicare i valori di proprietà

Nella presentazione corrente non viene indicato se Task è un'attività di tipo domestico o aziendale. Tenere presente che l'oggetto Task ha una proprietà TaskType di tipo TaskType che è un'enumerazione con valori Home e Work.

Nell'esempio riportato di seguito DataTrigger imposta l'oggetto BorderBrush dell'elemento denominato border su Yellow se la proprietà TaskType è TaskType.Home.


<DataTemplate x:Key="myTaskTemplate">


...


<DataTemplate.Triggers>
  <DataTrigger Binding="{Binding Path=TaskType}">
    <DataTrigger.Value>
      <local:TaskType>Home</local:TaskType>
    </DataTrigger.Value>
    <Setter TargetName="border" Property="BorderBrush" Value="Yellow"/>
  </DataTrigger>
</DataTemplate.Triggers>


...


</DataTemplate>


L'applicazione ha ora l'aspetto seguente. Le attività domestiche sono visualizzate con un bordo giallo, mentre quelle aziendali hanno un bordo azzurro:

Schermata dell'esempio Introduction to Data Templating

In questo esempio l'oggetto DataTrigger utilizza Setter per impostare un valore di proprietà. Anche le classi trigger dispongono di proprietà EnterActions e ExitActions che consentono di avviare un insieme di azioni, ad esempio le animazioni. È inoltre disponibile una classe MultiDataTrigger che consente di applicare modifiche basate su più valori di proprietà con associazione a dati.

In alternativa, per ottenere lo stesso effetto è possibile associare la proprietà BorderBrush alla proprietà TaskType e utilizzare un convertitore di valori per restituire il colore in base al valore TaskType. La creazione dell'effetto precedente utilizzando un convertitore offre una maggiore efficienza in termini di prestazioni. Inoltre, la creazione di un convertitore personalizzato garantisce maggiore flessibilità grazie alla possibilità di utilizzare logica personalizzata. La scelta ottimale dipende in ultima analisi dallo scenario e dalle preferenze. Per informazioni su come scrivere un convertitore, vedere IValueConverter.

ms742521.collapse_all(it-it,VS.110).gifElementi appartenenti a DataTemplate

Nell'esempio precedente, è stato inserito un trigger in DataTemplate utilizzando la proprietà DataTemplate.Triggers. L'oggetto Setter del trigger imposta il valore di una proprietà di un elemento (elemento Border) incluso in DataTemplate. Tuttavia, se le proprietà relative ai Setters non sono proprietà di elementi inclusi nell'oggetto DataTemplate corrente, può essere consigliabile impostare le proprietà utilizzando un oggetto Style per la classe ListBoxItem (se il controllo associato è un oggetto ListBox). Ad esempio, se si desidera che l'oggetto Trigger animi il valore Opacity dell'elemento quando si posiziona il mouse su un elemento, occorre definire trigger in uno stile ListBoxItem. Per un esempio, vedere Esempio di introduzione agli stili e ai modelli (la pagina potrebbe essere in inglese).

In genere, tenere presente che l'oggetto DataTemplate viene applicato a ogni oggetto ListBoxItem generato (per ulteriori informazioni sulle effettive modalità di applicazione, vedere la pagina relativa a ItemTemplate). L'oggetto DataTemplate riguarda esclusivamente la presentazione e l'aspetto degli oggetti dati. Nella maggior parte dei casi, tutti gli altri aspetti della presentazione, ad esempio l'aspetto di un elemento quando viene selezionato o il tipo di layout applicato dall'oggetto ListBox per gli elementi, non fanno parte della definizione di DataTemplate. Per un esempio, vedere la sezione Applicazione di stili e modelli di ItemsControl.

Nella sezione Proprietà DataType Property, è stato illustrato come definire modelli di dati diversi per diversi oggetti dati. Si tratta di una soluzione particolarmente utile quando è presente un oggetto CompositeCollection di diversi tipi o raccolte con elementi di diversi tipi. Nella sezione Utilizzo di DataTrigger per applicare valori di proprietà, è stato illustrato che se è presente una raccolta dello stesso tipo di oggetti dati è possibile creare DataTemplate e utilizzare trigger per applicare modifiche in base ai valori di proprietà di ogni oggetto dati. Tuttavia, i trigger consentono di applicare valori di proprietà o di avviare animazioni, ma non offrono la flessibilità necessaria per ricostruire la struttura degli oggetti dati. In alcuni scenari può essere necessario creare un oggetto DataTemplate diverso per gli oggetti dati dello stesso tipo, ma con proprietà diverse.

Ad esempio, può essere opportuno fornire un aspetto completamente diverso a un oggetto Task quando il relativo valore Priority è pari a 1, affinché funga da avviso. In tal caso, creare un oggetto DataTemplate per la visualizzazione di oggetti Task con priorità elevata. Verrà quindi aggiunto il seguente oggetto DataTemplate alla sezione risorse:


<DataTemplate x:Key="importantTaskTemplate">
  <DataTemplate.Resources>
    <Style TargetType="TextBlock">
      <Setter Property="FontSize" Value="20"/>
    </Style>
  </DataTemplate.Resources>
  <Border Name="border" BorderBrush="Red" BorderThickness="1"
          Padding="5" Margin="5">
    <DockPanel HorizontalAlignment="Center">
      <TextBlock Text="{Binding Path=Description}" />
      <TextBlock>!</TextBlock>
    </DockPanel>
  </Border>
</DataTemplate>


Si noti che in questo esempio viene utilizzata la proprietà DataTemplate.Resources. Le risorse definite in questa sezione sono condivise dagli elementi in DataTemplate.

Per fornire la logica per scegliere quale DataTemplate utilizzare in base al valore Priority dell'oggetto dati, creare una sottoclasse di DataTemplateSelector ed eseguire l'override del metodo SelectTemplate. Nell'esempio seguente, il metodo SelectTemplate fornisce la logica per restituire il modello adatto basato sul valore della proprietà Priority. Il modello da restituire viene cercato nelle risorse dell'elemento Window di protezione.


using System.Windows;
using System.Windows.Controls;

namespace SDKSample
{
    public class TaskListDataTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate
            SelectTemplate(object item, DependencyObject container)
        {
            FrameworkElement element = container as FrameworkElement;

            if (element != null && item != null && item is Task)
            {
                Task taskitem = item as Task;

                if (taskitem.Priority == 1)
                    return
                        element.FindResource("importantTaskTemplate") as DataTemplate;
                else
                    return
                        element.FindResource("myTaskTemplate") as DataTemplate;
            }

            return null;
        }
    }
}


È possibile quindi dichiarare l'oggetto TaskListDataTemplateSelector una risorsa:


<Window.Resources>


...


<local:TaskListDataTemplateSelector x:Key="myDataTemplateSelector"/>


...


</Window.Resources>


Per utilizzare la risorsa selettore di modello, assegnarlo alla proprietà ItemTemplateSelector del controllo ListBox. Il controllo ListBox chiama il metodo SelectTemplate del controllo TaskListDataTemplateSelector per ciascuno degli elementi della raccolta sottostante. La chiamata passa l'oggetto di dati come parametro dell'elemento. L'oggetto DataTemplate restituito dal metodo viene quindi applicato a tale oggetto dati.


<ListBox Width="400" Margin="10"
         ItemsSource="{Binding Source={StaticResource myTodoList}}"
         ItemTemplateSelector="{StaticResource myDataTemplateSelector}"
         HorizontalContentAlignment="Stretch"/>


Dopo aver posizionato il selettore di modelli, ListBox ha l'aspetto seguente:

Schermata dell'esempio Introduction to Data Templating

Con questo passaggio si conclude la discussione di questo esempio. Per l'esempio completo, vedere Esempio di introduzione ai modelli di dati (la pagina potrebbe essere in inglese).

Anche se ItemsControl non è l'unico tipo di controllo con cui è possibile utilizzare DataTemplate, costituisce uno scenario molto comune per l'associazione di ItemsControl a una raccolta. Nella sezione Elementi appartenenti a DataTemplate è stato illustrato che la definizione di DataTemplate deve riguardare solo la presentazione dei dati. Per sapere quando non è consigliabile utilizzare DataTemplate, è importante comprendere le diverse proprietà di stile e modello fornite da ItemsControl. Nell'esempio riportato di seguito viene illustrata la funzione di ciascuna di queste proprietà. L'oggetto ItemsControl di questo esempio è associato alla stessa raccolta Tasks dell'esempio precedente. A scopo dimostrativo, gli stili e i modelli di questo esempio sono tutti dichiarati inline.


<ItemsControl Margin="10"
              ItemsSource="{Binding Source={StaticResource myTodoList}}">
  <!--The ItemsControl has no default visual appearance.
      Use the Template property to specify a ControlTemplate to define
      the appearance of an ItemsControl. The ItemsPresenter uses the specified
      ItemsPanelTemplate (see below) to layout the items. If an
      ItemsPanelTemplate is not specified, the default is used. (For ItemsControl,
      the default is an ItemsPanelTemplate that specifies a StackPanel.-->
  <ItemsControl.Template>
    <ControlTemplate TargetType="ItemsControl">
      <Border BorderBrush="Aqua" BorderThickness="1" CornerRadius="15">
        <ItemsPresenter/>
      </Border>
    </ControlTemplate>
  </ItemsControl.Template>
  <!--Use the ItemsPanel property to specify an ItemsPanelTemplate
      that defines the panel that is used to hold the generated items.
      In other words, use this property if you want to affect
      how the items are laid out.-->
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <WrapPanel />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <!--Use the ItemTemplate to set a DataTemplate to define
      the visualization of the data objects. This DataTemplate
      specifies that each data object appears with the Proriity
      and TaskName on top of a silver ellipse.-->
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <DataTemplate.Resources>
        <Style TargetType="TextBlock">
          <Setter Property="FontSize" Value="18"/>
          <Setter Property="HorizontalAlignment" Value="Center"/>
        </Style>
      </DataTemplate.Resources>
      <Grid>
        <Ellipse Fill="Silver"/>
        <StackPanel>
          <TextBlock Margin="3,3,3,0"
                     Text="{Binding Path=Priority}"/>
          <TextBlock Margin="3,0,3,7"
                     Text="{Binding Path=TaskName}"/>
        </StackPanel>
      </Grid>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
  <!--Use the ItemContainerStyle property to specify the appearance
      of the element that contains the data. This ItemContainerStyle
      gives each item container a margin and a width. There is also
      a trigger that sets a tooltip that shows the description of
      the data object when the mouse hovers over the item container.-->
  <ItemsControl.ItemContainerStyle>
    <Style>
      <Setter Property="Control.Width" Value="100"/>
      <Setter Property="Control.Margin" Value="5"/>
      <Style.Triggers>
        <Trigger Property="Control.IsMouseOver" Value="True">
          <Setter Property="Control.ToolTip"
                  Value="{Binding RelativeSource={x:Static RelativeSource.Self},
                          Path=Content.Description}"/>
        </Trigger>
      </Style.Triggers>
    </Style>
  </ItemsControl.ItemContainerStyle>
</ItemsControl>


Nella figura riportata di seguito viene illustrato il risultato del rendering dell'esempio:

Schermata di esempio ItemsControl

Si noti che, anziché utilizzare ItemTemplate, è possibile utilizzare ItemTemplateSelector. Per un esempio, fare riferimento alla sezione precedente. Analogamente, anziché utilizzare ItemContainerStyle, è possibile utilizzare ItemContainerStyleSelector.

Vi sono altre due proprietà correlate allo stile di ItemsControl che non sono illustrate qui, ovvero GroupStyle e GroupStyleSelector.

Finora sono state analizzate unicamente l'associazione e la visualizzazione di una sola raccolta. Talvolta è presente una raccolta che contiene altre raccolte. La classe HierarchicalDataTemplate è progettata per essere utilizzata con tipi HeaderedItemsControl per visualizzare tali dati. Nell'esempio riportato di seguito ListLeagueList è un elenco di oggetti League. Ogni oggetto League ha un oggetto Name e una raccolta di oggetti Division. Ogni oggetto Division ha un oggetto Name e una raccolta di oggetti Team e ciascun oggetto Team ha un oggetto Name.


<Window x:Class="SDKSample.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="HierarchicalDataTemplate Sample"
  xmlns:src="clr-namespace:SDKSample">
  <DockPanel>
    <DockPanel.Resources>
      <src:ListLeagueList x:Key="MyList"/>

      <HierarchicalDataTemplate DataType    = "{x:Type src:League}"
                                ItemsSource = "{Binding Path=Divisions}">
        <TextBlock Text="{Binding Path=Name}"/>
      </HierarchicalDataTemplate>

      <HierarchicalDataTemplate DataType    = "{x:Type src:Division}"
                                ItemsSource = "{Binding Path=Teams}">
        <TextBlock Text="{Binding Path=Name}"/>
      </HierarchicalDataTemplate>

      <DataTemplate DataType="{x:Type src:Team}">
        <TextBlock Text="{Binding Path=Name}"/>
      </DataTemplate>
    </DockPanel.Resources>

    <Menu Name="menu1" DockPanel.Dock="Top" Margin="10,10,10,10">
        <MenuItem Header="My Soccer Leagues"
                  ItemsSource="{Binding Source={StaticResource MyList}}" />
    </Menu>

    <TreeView>
      <TreeViewItem ItemsSource="{Binding Source={StaticResource MyList}}" Header="My Soccer Leagues" />
    </TreeView>

  </DockPanel>
</Window>


Nell'esempio viene illustrata la possibilità di utilizzare HierarchicalDataTemplate per visualizzare in modo semplice dati elenco che contengono altri elenchi. Di seguito è disponibile una schermata dell'esempio.

Schermata di esempio HierarchicalDataTemplate

Aggiunte alla community

AGGIUNGI
Microsoft sta conducendo un sondaggio in linea per comprendere l'opinione degli utenti in merito al sito Web di MSDN. Se si sceglie di partecipare, quando si lascia il sito Web di MSDN verrà visualizzato il sondaggio in linea.

Si desidera partecipare?
Mostra:
© 2014 Microsoft