1

Je suis nouveau sur WPF et j'ai trouvé des questions similaires mais je n'arrive pas à comprendre la dernière partie. J'ai un ViewModel avec un ObservableCollection qui contient des messages d'erreur. Je veux les afficher sur le formulaire ET permettre à l'utilisateur de sélectionner et de copier tout ou partie des messages. (Dans le passé, dans les applications WinForm j'ai utilisé un RichTextBox pour cela, mais je n'arrive pas à comprendre comment lier un à la collection dans WPF.)Comment afficher ObservableCollection <string> dans un UserControl

J'ai eu le regard que j'avais après avec le xaml suivant, mais il n'y a pas de façon intégrée de sélectionner et de copier comme je le pourrais avec un RichTextBox. Est-ce que quelqu'un sait quel contrôle je devrais utiliser ou s'il y a moyen de permettre de sélectionner/copier le contenu de tous les TextBlocks, ou un moyen de lier cela à un RichTextBox?

<Grid Margin="6"> 
    <ScrollViewer VerticalScrollBarVisibility="Auto" Height="40" Grid.Column="0" Margin="6"> 
     <ItemsControl ItemsSource="{Binding ErrorMessages}" >    
      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <TextBlock Text="{Binding Mode=OneWay}" /> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
     </ItemsControl> 
    </ScrollViewer> 
</Grid> 

[Modifier] @Andrey Shvydky - Cela ne rentre pas dans un commentaire. Il m'a fallu un certain temps pour trouver la syntaxe appropriée (en particulier le /, chose) mais finalement je me suis retrouvé avec la syntaxe du document de flux ci-dessous. Il semble correct sur le formulaire et semble d'abord soutenir tout/copier. Mais quand je colle après un tout sélectionner/copier rien ne se montre jamais. Quelqu'un sait pourquoi?

<Grid Margin="6"> 
    <FlowDocumentScrollViewer> 
     <FlowDocument > 
      <Paragraph> 
       <ItemsControl ItemsSource="{Binding ErrorMessages, Mode=OneWay}" /> 
       <Run Text="{Binding /, Mode=OneWay}" /> 
      </Paragraph> 
     </FlowDocument> 
    </FlowDocumentScrollViewer> 
</Grid> 

Répondre

1

Peut être utile pour générer FlowDocument et montrer ce document FlowDocumentReader. Essayez de commencer à partir de cet article: Flow Document Overview.

Exemple de génération:

void ShowErrors(FlowDocumentReader reader, Exception[] errors) { 
     FlowDocument doc = new FlowDocument(); 
     foreach (var e in errors) { 
      doc.Blocks.Add(new Paragraph(new Run(e.GetType().Name)) { 
       Style = (Style)this.FindResource("header") 
      }); 
      doc.Blocks.Add(new Paragraph(new Run(e.Message)) { 
       Style = (Style)this.FindResource("text") 
      }); 
     } 
     reader.Document = doc; 
    } 

Dans cet exemple, j'ai ajouté quelques styles pour le texte dans FlowDocument. REGARDEZ XAML:

<Window x:Class="WpfApplication1.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525"> 
<Window.Resources> 
    <Style x:Key="header" TargetType="{x:Type Paragraph}"> 
     <Setter Property="FontWeight" Value="Bold"/> 
    </Style> 
    <Style x:Key="text" TargetType="{x:Type Paragraph}"> 
     <Setter Property="Margin" Value="30, 0, 0, 0"/> 
    </Style> 
</Window.Resources> 
<FlowDocumentReader Name="reader"> 
</FlowDocumentReader> 

Résultat:

enter image description here

+0

Il m'a fallu un certain temps pour comprendre la syntaxe correcte (en particulier le /, mais finalement je suis venu avec Tod

+0

FlowDocument ne supporte pas la liaison. dans ce cas, vous devez générer le document dans le code et l'affecter au document Cela est très similaire à l'approche de RichTextBox dans WinForms Bien sûr, vous pouvez utiliser ItemControl aussi, mais FlowDocumentReader est le moyen simple d'obtenir Selive. ect/Copier la fonctionnalité. –

+0

Je voulais supprimer mon commentaire ici. C'était trop difficile à lire et tout ne cadrait pas alors j'ai ajouté une modification à mon message original. Je ne me suis pas rendu compte que FlowDocument ne prenait pas directement en charge la liaison directement, ce que je trouve un peu étrange car l'élément prend en charge la liaison. Basé sur votre suggestion je l'ai l'air très bien, je ne peux pas coller les résultats et je ne sais pas pourquoi. Je peux * tout sélectionner *, et * copier * et il semble fonctionner, mais quand je * coller * rien ne s'affiche. – Tod

0
<Grid Margin="6"> 
    <ScrollViewer VerticalScrollBarVisibility="Auto" Height="40" Grid.Column="0" Margin="6"> 
     <ItemsControl ItemsSource="{Binding ErrorMessages}" >    
      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <TextBox Text="{Binding ViewModelMemberRepresentingYourErrorMessage}" /> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
     </ItemsControl> 
    </ScrollViewer> 
</Grid> 
+0

Je ne sais pas comment cela aiderait. Tous mes messages d'erreur s'affichent correctement dans mon code (je ne peux pas les copier et les dépasser). Je n'ai pas un membre qui représente un message d'erreur individuel, juste la collection. Je ne comprends pas assez bien WPF pour comprendre votre point de vue. – Tod

+0

@Tod: Il n'y a pas d'explication et je ne vois aucun point là-dedans non plus. –

1

manière la plus simple:

En supposant que votre viewmodel implémente INotifyPropertyChange, créez un gestionnaire d'événements pour l'événement ObservableCollection PropertyChanged. Créez une propriété qui agrège tous les éléments de la collection observable en une seule chaîne. Chaque fois que la collection observable change, déclenchez un événement de notification pour votre nouvelle propriété. Se lier à cette propriété

public class ViewModel : INotifyPropertyChange 
{ 
    public ViewModel() 
    { 
     MyStrings.CollectionChanged += ChangedCollection; 
    } 
    public ObservableCollection<string> MyStrings{get;set;} 

    public void ChangedCollection(args,args) 
    { 
     base.PropertyChanged("MyAllerts"); 
    } 

    public string MyAllerts 
    { 
     get 
     { 
      string collated = ""; 
      foreach(var allert in MyStrings) 
      { 
       collated += allert; 
        collated += "\n"; 
      } 
     } 
    } 

} 

Je sais que ce code est semé d'erreurs (je l'ai écrit dans Au lieu de VS), mais il devrait vous donner une idée.

+0

Merci, je pense que je pensais qu'il me manquait quelque chose d'évident, mais cela semble être une solution de rechange raisonnable. Puisque j'apprends toujours, je prends probablement la suggestion semblable ci-dessous et essaye d'apprendre plus au sujet de créer un convertisseur. – Tod

+1

La concaténation brute de chaîne 'foreach' n'est pas quelque chose que vous devriez faire, utilisez un [' StringBuilder'] (http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.aspx) sinon une nouvelle chaîne sera créé à chaque itération. (Ou utilisez simplement ['String.Join'] (http://msdn.microsoft.com/fr-fr/library/system.string.join.aspx) qui fait tout cela pour vous en interne) –

+0

Merci HB. N'a pas connu à propos de string.join, utilise généralement un constructeur de chaîne. Utilisait juste un exemple rapide et sale. est-ce que string.join est réellement efficace ou est-ce juste un foreach masqué? – TerrorAustralis

1

Sauf si vous avez une grande quantité de messages qu'un converter simple pourrait être viable:

<TextBox IsReadOnly="True"> 
    <TextBox.Text> 
     <Binding Path="Messages" Mode="OneWay"> 
      <Binding.Converter> 
       <vc:JoinStringsConverter /> 
      </Binding.Converter> 
     </Binding> 
    </TextBox.Text> 
</TextBox> 
public class JoinStringsConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     var strings = value as IEnumerable<string>; 
     return string.Join(Environment.NewLine, strings); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotSupportedException(); 
    } 
} 
+0

Depuis que j'apprends, cela ressemble à un bon moyen d'apprendre et d'écrire mon premier convertisseur. Merci pour la suggestion et le code. – Tod

Questions connexes