2010-03-13 7 views
4

J'essaie d'implémenter (comme prototype au départ) un contrôle richtextbox qui peut être analysé en temps réel pour y appliquer certaines options de formatage. Cela se fait dans WPF, donc je pensais que la meilleure façon d'y arriver serait d'étendre le contrôle de la boîte de texte enrichi existant.Meilleure façon d'implémenter une zone Richtext modifiable/modifiable dans WPF

J'ai rencontré le problème où il n'est pas bien documenté et les exemples sont assez lents (ceux que j'ai trouvés ont analysé le document entier à chaque frappe).

La façon dont j'ai décidé de le faire est de créer un élément Inline personnalisé pouvant contenir les balises de mise en forme et le contenu. Par conséquent, je n'ai qu'à analyser le paragraphe en cours et les exécutions dans ce paragraphe pour le formatage des balises.

Existe-t-il un meilleur moyen d'y parvenir? Notez que ce n'est pas pour les documents basés sur le code/la syntaxe (donc AvalonEdit n'est pas approprié).

Vive

Répondre

4

Si vous pouvez cibler NET Framework 3.5 et supérieur, vous n'avez pas besoin de scanner le document à chaque modification: Abonnez-vous à l'événement TextChanged et utilisez la propriété TextChangedEventArgs.Changes pour obtenir la liste des modifications. Chaque fois que vous recevez un événement TextChanged, parcourez la collection Changes et créez une TextRange à partir de Offset, AddedLength et RemovedLength. Ensuite, développez cette TextRange pour recalculer la mise en forme, puis effectuez le calcul de la mise en forme et effectuez une mise à jour en tant qu'étape séparée (dans un rappel Dispatcher.BeginInvoke) afin de ne pas avoir d'événements TextChanged récursifs.

richTextBox.TextChanged += (obj, e) 
{ 
    var document = richTextBox.Document; 
    var length = document.ContentStart.GetOffsetToPosition(document.ContentEnd); 
    int totalAdd = 0; 
    int totalRemove = 0; 
    foreach(var change in e.Changes) 
    { 
    var expandBy = Math.Max(totalAdd,totalRemove); 

    var startIndex = change.Offset - expandBy; 
    var endIndex = changed.Offset + expandBy + Math.Max(totalAdd, totalRemove); 

    startIndex = Math.Max(startIndex, 0); 
    endIndex = Math.Min(endIndex, length); 

    var startPointer = document.ContentStart.GetPositionAtOffset(startIndex); 
    var endPointer = startPointer.GetPositionAtOffset(endIndex - startIndex); 

    var range = new TextRange(startPointer, endPointer); 
    Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => 
    { 
     DoParsingAndFormatting(ExpandRangeToUnitOfParsing(range)); 
    }); 
    totalAdd += change.AddedLength; 
    totalRemove += change.RemovedLength; 
    } 
}; 

Si vous voulez trouver le paragraphe où un changement commence ou se termine, vous pouvez utiliser range.Start.Paragraph et range.End.Paragraph.

De même, pour de nombreuses situations, il sera utile de stocker une copie de tout le texte du document séparément du FlowDocument lui-même. Ensuite, lorsque vous appliquez des modifications à ce document, vous pouvez mettre à jour le formatage au fur et à mesure sans avoir à relire le document. Notez que le texte ne doit pas être stocké dans un seul grand tableau, mais plutôt découpé en petits morceaux (peut-être autour de 1000 caractères) et accessible via un arbre qui organise les pièces par index. La raison en est que l'insertion d'un personnage au début d'un énorme tableau est très coûteuse.

+0

Est-ce que ce code s'applique encore pour la dernière version de RichTextBox? Je demande parce que je vois quelques changements nécessaires pour faire fonctionner le code correctement, comme startindex, endindex ne lit pas le texte a changé les valeurs correctement, besoin d'un recalcul ..? –

+0

JP Je pense que vous trouverez que c'est juste un cas de bugs. Le principe est solide, mais la logique actuelle pour déterminer les bonnes valeurs d'index n'est pas tout à fait juste. – donovan

-3

Jetez un coup d'oeil ici sur ce sur CodeProject. Voici un article qui pourrait vous intéresser par rapport au contrôle RichTextBox qui est étendu par sous-classe ... Regardez celui-ci - un contrôle Extended RichTextBox qui a plus de fonctionnalités

+3

C'est l'une des pires réponses que j'ai jamais vues. Ces trois liens ont gaspillé mon temps: l'analyseur RTF décrit est bien inférieur à celui de WPF, et les deux autres liens sont des choses WinForms obsolètes qui n'ont aucun rapport avec la question. Ce qui est pire, vous devez télécharger le code avant de découvrir qu'il n'est même pas WPF! –

+0

@Ray: Je suis désolé si j'ai perdu votre temps, Il y a NRTFTree Parser qui peut analyser RTF, j'espérais juste que vous glaner sur le code pour vous donner une idée ... – t0mm13b