Un modo per rendere selezionabile un blocco di testo WPF?


224

Voglio rendere selezionabile il testo visualizzato in Witty , un client Twitter open source. Attualmente è visualizzato utilizzando un blocco di testo personalizzato. Devo usare un TextBlock perché sto lavorando con gli inline del textblock per visualizzare e formattare @nomeutente e collegamenti come collegamenti ipertestuali. Una richiesta frequente è quella di poter copiare e incollare il testo. Per fare ciò devo rendere selezionabile TextBlock.

Ho provato a farlo funzionare visualizzando il testo usando un TextBox di sola lettura in stile simile a un blocco di testo, ma questo non funzionerà nel mio caso perché un TextBox non ha inline. In altre parole, non posso modellare o formattare il testo all'interno di una TextBox singolarmente come posso fare con un TextBlock.

Qualche idea?


1
Proverò a utilizzare il controllo RichTextBox per vedere se funzionerà. Ma dalla precedente esperienza di lavoro con richtextbox è molto più coinvolto.
Alan Le,

Hai pensato di utilizzare un FlowDocumentScrollViewer, con un FlowDocument contenente paragrafi ed esecuzioni? - Funziona abbastanza bene per me quando ho bisogno di testo selezionabile e ogni paragrafo ed esecuzione possono essere disegnati separatamente.
BrainSlugs83

Dopo aver provato alcune delle soluzioni alternative di seguito, FlowDocumentScrollViewer è stato il modo di procedere. Sembra occupare un'utile via di mezzo tra RichTextBox e TextBlock.
Tom Makin,

vota verso il basso per aver accettato una risposta che non soddisfa i tuoi requisiti.
Blechdose

Risposte:


218
<TextBox Background="Transparent"
         BorderThickness="0"
         Text="{Binding Text, Mode=OneWay}"
         IsReadOnly="True"
         TextWrapping="Wrap" />

6
Ho un progetto che contiene molti TextBlock / etichette, non riesco davvero a trasformarli in TextBox. Quello che voglio fare è aggiungere un magico stile di applicazione a tutti alla risorsa a livello di app in modo che dovrebbe interessare tutta l'etichetta / TextBlock e rendere il loro presentatore di testo interno come un TextBox di sola lettura, sai in qualche modo per farlo?
Shimmy Weitzhandler,

5
Potresti voler aggiungere IsTabStop = "False" a seconda della tua situazione
Karsten,

1
+1 Soluzione molto bella! Ho aggiunto un Padding = "0", poiché nel mio progetto la parte inferiore del testo è stata tagliata ... Forse a causa di uno stile altrove.
REVISIONATO il

123
-1 La domanda chiede specificamente come rendere selezionabile un blocco di testo. Perché non vuole perdere la proprietà "Inlines" (che textBox non ha). Questa "risposta" suggerisce solo di far apparire una casella di testo come un blocco di testo.
00jt

19
@AlanLe Perché hai accettato questa risposta quando è quello che hai detto esplicitamente di non voler? E perché 147 persone all'oscuro lo hanno votato?
Jim Balter,

66

Tutte le risposte qui stanno semplicemente usando TextBoxo cercando di implementare la selezione del testo manualmente, il che porta a scarse prestazioni o comportamenti non nativi (lampeggio del cursore TextBox, nessun supporto da tastiera nelle implementazioni manuali ecc.)

Dopo ore di scavare e leggere il codice sorgente WPF , ho invece scoperto un modo per abilitare la selezione del testo WPF nativo per i TextBlockcontrolli (o davvero qualsiasi altro controllo). La maggior parte delle funzionalità relative alla selezione del testo è implementata nella System.Windows.Documents.TextEditorclasse di sistema.

Per abilitare la selezione del testo per il tuo controllo devi fare due cose:

  1. Chiamare TextEditor.RegisterCommandHandlers()una volta per registrare i gestori di eventi di classe

  2. Creare un'istanza di TextEditorper ogni istanza della classe e passare l'istanza di fondo del vostro System.Windows.Documents.ITextContainerad esso

C'è anche un requisito su cui Focusableè impostata la proprietà del controllo True.

Questo è! Sembra facile, ma purtroppo la TextEditorclasse è contrassegnata come interna. Quindi ho dovuto scrivere un involucro di riflessione attorno ad esso:

class TextEditorWrapper
{
    private static readonly Type TextEditorType = Type.GetType("System.Windows.Documents.TextEditor, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
    private static readonly PropertyInfo IsReadOnlyProp = TextEditorType.GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
    private static readonly PropertyInfo TextViewProp = TextEditorType.GetProperty("TextView", BindingFlags.Instance | BindingFlags.NonPublic);
    private static readonly MethodInfo RegisterMethod = TextEditorType.GetMethod("RegisterCommandHandlers", 
        BindingFlags.Static | BindingFlags.NonPublic, null, new[] { typeof(Type), typeof(bool), typeof(bool), typeof(bool) }, null);

    private static readonly Type TextContainerType = Type.GetType("System.Windows.Documents.ITextContainer, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
    private static readonly PropertyInfo TextContainerTextViewProp = TextContainerType.GetProperty("TextView");

    private static readonly PropertyInfo TextContainerProp = typeof(TextBlock).GetProperty("TextContainer", BindingFlags.Instance | BindingFlags.NonPublic);

    public static void RegisterCommandHandlers(Type controlType, bool acceptsRichContent, bool readOnly, bool registerEventListeners)
    {
        RegisterMethod.Invoke(null, new object[] { controlType, acceptsRichContent, readOnly, registerEventListeners });
    }

    public static TextEditorWrapper CreateFor(TextBlock tb)
    {
        var textContainer = TextContainerProp.GetValue(tb);

        var editor = new TextEditorWrapper(textContainer, tb, false);
        IsReadOnlyProp.SetValue(editor._editor, true);
        TextViewProp.SetValue(editor._editor, TextContainerTextViewProp.GetValue(textContainer));

        return editor;
    }

    private readonly object _editor;

    public TextEditorWrapper(object textContainer, FrameworkElement uiScope, bool isUndoEnabled)
    {
        _editor = Activator.CreateInstance(TextEditorType, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance, 
            null, new[] { textContainer, uiScope, isUndoEnabled }, null);
    }
}

Ho anche creato un SelectableTextBlockderivato TextBlockche prende i passaggi sopra indicati:

public class SelectableTextBlock : TextBlock
{
    static SelectableTextBlock()
    {
        FocusableProperty.OverrideMetadata(typeof(SelectableTextBlock), new FrameworkPropertyMetadata(true));
        TextEditorWrapper.RegisterCommandHandlers(typeof(SelectableTextBlock), true, true, true);

        // remove the focus rectangle around the control
        FocusVisualStyleProperty.OverrideMetadata(typeof(SelectableTextBlock), new FrameworkPropertyMetadata((object)null));
    }

    private readonly TextEditorWrapper _editor;

    public SelectableTextBlock()
    {
        _editor = TextEditorWrapper.CreateFor(this);
    }
}

Un'altra opzione sarebbe quella di creare una proprietà collegata per TextBlockconsentire la selezione del testo su richiesta. In questo caso, per disabilitare nuovamente la selezione, è necessario scollegare un TextEditorusando l'equivalente di riflessione di questo codice:

_editor.TextContainer.TextView = null;
_editor.OnDetach();
_editor = null;

1
come useresti la classe SelectableTextBlock in un altro xaml che dovrebbe contenerlo?
Yoav Feuerstein,

1
allo stesso modo in cui useresti qualsiasi altro controllo personalizzato. vedi stackoverflow.com/a/3768178/332528 per esempio
torvin

3
@BillyWilloughby la tua soluzione emula solo la selezione. Manca molte funzionalità di selezione native: supporto tastiera, menu contestuale ecc. La mia soluzione abilita la funzione di selezione nativa
torvin

3
Sembra che questa soluzione non lavoro quando l' TextBlockha incorporato Hyperlinks fino a quando il Hyperlinknon è l'ultima linea in esso. L'aggiunta di un finale vuoto Runal contenuto consente di correggere qualsiasi problema sottostante che provochi il ExecutionEngineExceptionlancio.
Anton Tykhyy,

2
Questo è fantastico! A meno che non si dispone TextTrimming="CharacterEllipsis"sul TextBlocke la larghezza disponibile è insufficiente, se si sposta il puntatore del mouse sul ..., si blocca con System.ArgumentException "distanza richiesto è al di fuori del contenuto del documento associato." su System.Windows.Documents.TextPointer.InitializeOffset (posizione TextPointer, distanza Int32, direzione LogicalDirection) :( Non so se esiste una soluzione alternativa se non quella di lasciare TextTrimming impostato su Nessuno.
Dave Huang,

32

Non sono stato in grado di trovare alcun esempio di come rispondere realmente alla domanda. Tutte le risposte hanno utilizzato una casella di testo o RichTextbox. Avevo bisogno di una soluzione che mi permettesse di utilizzare un TextBlock e questa è la soluzione che ho creato.

Credo che il modo corretto per farlo sia estendere la classe TextBlock. Questo è il codice che ho usato per estendere la classe TextBlock per permettermi di selezionare il testo e copiarlo negli appunti. "sdo" è il riferimento allo spazio dei nomi che ho usato nel WPF.

WPF utilizzando la classe estesa:

xmlns:sdo="clr-namespace:iFaceCaseMain"

<sdo:TextBlockMoo x:Name="txtResults" Background="Black" Margin="5,5,5,5" 
      Foreground="GreenYellow" FontSize="14" FontFamily="Courier New"></TextBlockMoo>

Codice dietro per la classe estesa:

public partial class TextBlockMoo : TextBlock 
{
    TextPointer StartSelectPosition;
    TextPointer EndSelectPosition;
    public String SelectedText = "";

    public delegate void TextSelectedHandler(string SelectedText);
    public event TextSelectedHandler TextSelected;

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);
        Point mouseDownPoint = e.GetPosition(this);
        StartSelectPosition = this.GetPositionFromPoint(mouseDownPoint, true);            
    }

    protected override void OnMouseUp(MouseButtonEventArgs e)
    {
        base.OnMouseUp(e);
        Point mouseUpPoint = e.GetPosition(this);
        EndSelectPosition = this.GetPositionFromPoint(mouseUpPoint, true);

        TextRange otr = new TextRange(this.ContentStart, this.ContentEnd);
        otr.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.GreenYellow));

        TextRange ntr = new TextRange(StartSelectPosition, EndSelectPosition);
        ntr.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.White));

        SelectedText = ntr.Text;
        if (!(TextSelected == null))
        {
            TextSelected(SelectedText);
        }
    }
}

Codice finestra di esempio:

    public ucExample(IInstanceHost host, ref String WindowTitle, String ApplicationID, String Parameters)
    {
        InitializeComponent();
        /*Used to add selected text to clipboard*/
        this.txtResults.TextSelected += txtResults_TextSelected;
    }

    void txtResults_TextSelected(string SelectedText)
    {
        Clipboard.SetText(SelectedText);
    }

1
Questa dovrebbe essere la risposta accettata! Nessun hack di riflessione, non usando un TextBox ... E può essere facilmente trasformato in un comportamento riutilizzabile. Molto bello, grazie!
Thomas Levesque,

19

Applica questo stile al tuo TextBox e il gioco è fatto (ispirato a questo articolo ):

<Style x:Key="SelectableTextBlockLikeStyle" TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
    <Setter Property="IsReadOnly" Value="True"/>
    <Setter Property="IsTabStop" Value="False"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Padding" Value="-2,0,0,0"/>
    <!-- The Padding -2,0,0,0 is required because the TextBox
        seems to have an inherent "Padding" of about 2 pixels.
        Without the Padding property,
        the text seems to be 2 pixels to the left
        compared to a TextBlock
    -->
    <Style.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsMouseOver" Value="False" />
                <Condition Property="IsFocused" Value="False" />
            </MultiTrigger.Conditions>
            <Setter Property="Template">
                <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBox}">
                    <TextBlock Text="{TemplateBinding Text}" 
                             FontSize="{TemplateBinding FontSize}"
                             FontStyle="{TemplateBinding FontStyle}"
                             FontFamily="{TemplateBinding FontFamily}"
                             FontWeight="{TemplateBinding FontWeight}"
                             TextWrapping="{TemplateBinding TextWrapping}"
                             Foreground="{DynamicResource NormalText}"
                             Padding="0,0,0,0"
                                       />
                </ControlTemplate>
                </Setter.Value>
            </Setter>
        </MultiTrigger>
    </Style.Triggers>
</Style>

1
A proposito di oggi, il link all'articolo sembra morto
superjos

2
Un'altra aggiunta: l'imbottitura dovrebbe essere -2,0, -2,0. All'interno di TextBox, viene creato un controllo TextBoxView con un margine predefinito di 2,0,2,0. Sfortunatamente, non è possibile ridefinire il suo stile perché è contrassegnato come interno.
fdub,

11
Nessuno sembra in grado di leggere. L'OP ha bisogno di un TextBlock, non di un TextBox in stile TextBlock.
Jim Balter,

18

Crea ControlTemplate per TextBlock e inserisci una TextBox all'interno con il set di proprietà readonly. O semplicemente usa TextBox e rendilo di sola lettura, quindi puoi modificare TextBox.Style per renderlo simile a TextBlock.


11
Come si imposta ControlTemplate per un TextBlock? Non riesco a trovare la proprietà?
HaxElit

18
Questo approccio non funzionerà se TextBlock ha elementi incorporati al suo interno. Che cosa succede se hai collegamenti ipertestuali o sequenze di testo in grassetto o corsivo? TextBox non supporta questi.
Dthrasher,

1
Non funziona se si utilizzano corse in linea e, come richiesto da HaxElit, non sono sicuro di cosa si intenda per modello di controllo.
Ritch Melton,

7
-1 TextBlock non ha un ControlTemplate perché è una sottoclasse diretta di FrameworkElement. TextBox d'altra parte è una sottoclasse di Control.
REVISIONATO il

5
Perché nessuno può leggere? L'OP ha detto esplicitamente che è necessario un TextBlock, non un TextBox, perché TextBlock supporta la formattazione in linea e TextBox no. Perché risposte immondizie completamente errate come questa ottengono numerosi voti positivi?
Jim Balter,

10

Non sono sicuro se puoi rendere selezionabile un TextBlock, ma un'altra opzione sarebbe quella di utilizzare un RichTextBox: è come un TextBox come hai suggerito, ma supporta la formattazione che desideri.


1
Ho provato a farlo e nel processo ho dovuto rendere associabile RichTextBox con una proprietà di dipendenza. Purtroppo i vecchi documenti di flusso non vengono scartati correttamente e la memoria perde come un matto. Alan, mi chiedo se hai trovato un modo per aggirare questo?
John Noonan,

@AlanLe Di tutte le risposte qui, questa è solo una delle due che in realtà risponde alla domanda posta ... tutte le altre parlano di designare un TextBox per assomigliare a un TextBlock, ignorando la necessità di formattazione. È strano e sfortunato che l'OP abbia accettato una di quelle non-risposte, invece della risposta corretta per usare RichTextBox piuttosto che TextBox.
Jim Balter,

9

Secondo Windows Dev Center :

Proprietà TextBlock.IsTextSelectionEnabled

[Aggiornato per le app UWP su Windows 10. Per gli articoli di Windows 8.x, vedere l' archivio ]

Ottiene o imposta un valore che indica se la selezione di testo è abilitata in TextBlock , tramite l'azione dell'utente o chiamando l'API relativa alla selezione.


5
Sfortunatamente, non compatibile con Win7 (a volte è un must)
Yury Schkatula

24
Amswer appare errato. IsTextSelectionEnabled è solo per UWP, non WPF - la domanda originale specificava WPF.
Puffin,

6

Mentre la domanda dice "Selezionabile", credo che i risultati intenzionali siano di portare il testo negli appunti. Ciò può essere ottenuto facilmente ed elegantemente aggiungendo un menu contestuale e una voce di menu chiamata copia che inserisce il valore della proprietà Text TextBlock negli Appunti. Solo un'idea comunque.


4

TextBlock non ha un modello. Quindi, per raggiungere questo obiettivo, dobbiamo usare una TextBox il cui stile è cambiato per comportarsi come textBlock.

<Style x:Key="TextBlockUsingTextBoxStyle" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="Padding" Value="1"/>
    <Setter Property="AllowDrop" Value="true"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
    <Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBox}">
                <TextBox BorderThickness="{TemplateBinding BorderThickness}" IsReadOnly="True" Text="{TemplateBinding Text}" Background="{x:Null}" BorderBrush="{x:Null}" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Quali vantaggi offre questo approccio rispetto ad altre risposte? Non ne vedo nessuno.
surfen il

Ho provato questo stile: TextBoxBorder non è definito. Se lo commenti, funziona benissimo
sthiers

Questo codice di esempio è eccellente, mostra come ottenere il colore predefinito per un TextBlock.
Contango,

1
Questo è abbastanza confuso. Innanzitutto, la chiave x: "TextBlockUsingTextBoxStyle" è all'indietro; dovrebbe essere "TextBoxUsingTextBlockStyle". In secondo luogo, l'OP ha già saputo modellare un TextBox come un TextBlock, ma ha ripetutamente affermato che non poteva usarlo perché aveva bisogno di linee per la formattazione.
Jim Balter,

2

Esiste una soluzione alternativa che potrebbe essere adattabile a RichTextBox descritta in questo post del blog - ha usato un trigger per scambiare il modello di controllo quando l'uso passa sopra il controllo - dovrebbe aiutare con le prestazioni


1
Il tuo link è morto. Includere tutte le informazioni pertinenti in una risposta e utilizzare i collegamenti solo come citazioni.
Jim Balter,

1

new TextBox
{
   Text = text,
   TextAlignment = TextAlignment.Center,
   TextWrapping = TextWrapping.Wrap,
   IsReadOnly = true,
   Background = Brushes.Transparent,
   BorderThickness = new Thickness()
         {
             Top = 0,
             Bottom = 0,
             Left = 0,
             Right = 0
         }
};


1
Questo non è utile Leggi la domanda per vedere cosa voleva effettivamente l'OP.
Jim Balter,

1

Aggiungendo alla risposta di @ torvin e come ha menzionato @Dave Huang nei commenti se si è TextTrimming="CharacterEllipsis"abilitato il crash dell'applicazione quando si passa con il puntatore del mouse sui puntini di sospensione.

Ho provato altre opzioni menzionate nel thread sull'utilizzo di un TextBox ma in realtà non sembra essere la soluzione, in quanto non mostra i "puntini di sospensione" e anche se il testo è troppo lungo per adattarsi al contenitore selezionando il contenuto di la casella di testo "scorre" internamente, il che non è un comportamento TextBlock.

Penso che la soluzione migliore sia la risposta di @ torvin, ma ha il brutto incidente quando si passa sopra i puntini di sospensione.

So che non è carino, ma iscriversi / annullare l'iscrizione internamente alle eccezioni non gestite e gestire l'eccezione è stato l'unico modo che ho trovato per risolvere questo problema, per favore condividi se qualcuno ha una soluzione migliore :)

public class SelectableTextBlock : TextBlock
{
    static SelectableTextBlock()
    {
        FocusableProperty.OverrideMetadata(typeof(SelectableTextBlock), new FrameworkPropertyMetadata(true));
        TextEditorWrapper.RegisterCommandHandlers(typeof(SelectableTextBlock), true, true, true);

        // remove the focus rectangle around the control
        FocusVisualStyleProperty.OverrideMetadata(typeof(SelectableTextBlock), new FrameworkPropertyMetadata((object)null));
    }

    private readonly TextEditorWrapper _editor;

    public SelectableTextBlock()
    {
        _editor = TextEditorWrapper.CreateFor(this);

        this.Loaded += (sender, args) => {
            this.Dispatcher.UnhandledException -= Dispatcher_UnhandledException;
            this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
        };
        this.Unloaded += (sender, args) => {
            this.Dispatcher.UnhandledException -= Dispatcher_UnhandledException;
        };
    }

    private void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        if (!string.IsNullOrEmpty(e?.Exception?.StackTrace))
        {
            if (e.Exception.StackTrace.Contains("System.Windows.Controls.TextBlock.GetTextPositionFromDistance"))
            {
                e.Handled = true;
            }
        }
    }
}

0

Ho implementato SelectableTextBlock nella mia libreria di controlli opensource. Puoi usarlo in questo modo:

<jc:SelectableTextBlock Text="Some text" />

4
Questo utilizza solo una TextBox, come tante altre risposte di molti anni prima.
Chris,

0
public MainPage()
{
    this.InitializeComponent();
    ...
    ...
    ...
    //Make Start result text copiable
    TextBlockStatusStart.IsTextSelectionEnabled = true;
}

-1
Really nice and easy solution, exactly what I wanted !

Apporto alcune piccole modifiche

public class TextBlockMoo : TextBlock 
{
    public String SelectedText = "";

    public delegate void TextSelectedHandler(string SelectedText);
    public event TextSelectedHandler OnTextSelected;
    protected void RaiseEvent()
    {
        if (OnTextSelected != null){OnTextSelected(SelectedText);}
    }

    TextPointer StartSelectPosition;
    TextPointer EndSelectPosition;
    Brush _saveForeGroundBrush;
    Brush _saveBackGroundBrush;

    TextRange _ntr = null;

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);

        if (_ntr!=null) {
            _ntr.ApplyPropertyValue(TextElement.ForegroundProperty, _saveForeGroundBrush);
            _ntr.ApplyPropertyValue(TextElement.BackgroundProperty, _saveBackGroundBrush);
        }

        Point mouseDownPoint = e.GetPosition(this);
        StartSelectPosition = this.GetPositionFromPoint(mouseDownPoint, true);            
    }

    protected override void OnMouseUp(MouseButtonEventArgs e)
    {
        base.OnMouseUp(e);
        Point mouseUpPoint = e.GetPosition(this);
        EndSelectPosition = this.GetPositionFromPoint(mouseUpPoint, true);

        _ntr = new TextRange(StartSelectPosition, EndSelectPosition);

        // keep saved
        _saveForeGroundBrush = (Brush)_ntr.GetPropertyValue(TextElement.ForegroundProperty);
        _saveBackGroundBrush = (Brush)_ntr.GetPropertyValue(TextElement.BackgroundProperty);
        // change style
        _ntr.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(Colors.Yellow));
        _ntr.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.DarkBlue));

        SelectedText = _ntr.Text;
    }
}

1
Devi spiegare cosa hai cambiato dalla risposta qui sotto per favore. -1
Alex Hope O'Connor

La riga 51 fornisce: System.ArgumentNullException: 'Il valore non può essere nullo. Nome del parametro: position1 '
lancia
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.