Nano Hash - криптовалюты, майнинг, программирование

WPF RichTextBox - выбор нескольких блоков

Привет, я сейчас работаю над проектом WPF (с / C #), который включает использование RichTextBox. В настоящее время я выполнил большую часть своей работы, но мне нужна помощь в получении более одного блока с помощью выбора мыши, например, для установки TextAlignment или Margin. Для справки: следующий код выберет один блок, установив TextPointer для курсора RichTextBox, а затем перебрав Document.Blocks, чтобы получить индивидуальный блок. Но мне нужен подход, который позволит мне получить больше, чем один блок. Может ли кто-нибудь дать больше информации о том, как выбрать несколько блоков (каждый блок в отдельной строке)?

// XAML

<RichTextBox Name="rtb" HorizontalAlignment="Left">
   <FlowDocument>
      <Paragraph TextAlignment="Left" Margin="0.0">
         <Run Text="Hello"/>
      </Paragraph>
      <Paragraph TextAlignment="Right" Margin="0.0">
         <Run Text="World"/>
      </Paragraph>
      <Paragraph TextAlignment="Left" Margin="1.0">
         <Run Text="Hello"/>
      </Paragraph>
      <Paragraph TextAlignment="Right" Margin="1.0">
         <Run Text="World"/>
      </Paragraph>
   </FlowDocument>
</RichTextBox>


// Code Behind

var curCaret = rtb.CaretPosition;
Block curBlock = rtb.Document.Blocks.Where(x => x.ContentStart.CompareTo(curCaret) ==    -1 && x.ContentEnd.CompareTo(curCaret) == 1).FirstOrDefault();
05.08.2014

  • Непонятно, чего ты хочешь. Пожалуйста, отредактируйте свой вопрос, чтобы прояснить следующие вопросы: (A) Вы хотите выделить все абзацы или только определенные абзацы? Если требуются только определенные абзацы, как бы вы решили, какие абзацы выбрать? Будет ли это какой-либо абзац, который уже полностью или частично выбран? (B) Что вы имеете в виду «выбирать»? Выбор соответствующих частей документа в RichTextBox или, как подсказывает пример кода, получение объектов Block, представляющих интересующие вас абзацы? 06.08.2014
  • (A) Я хочу выделить определенные абзацы. Пользователь мог решить, какой абзац выбрать, щелкнув и перетащив текст (т.е. текст внутри RichTextBox). (B) Под выбором я подразумеваю получение объектов Block, представляющих абзацы. По сути, я хочу делать именно то, что делает мой текущий код, но получать более одного объекта Block, представляющего абзацы. В настоящее время приведенный выше код получает только один объект Block (то есть по позиции курсора). 06.08.2014
  • @elgonzo - почти наверняка OP хочет реализовать возможность для пользователя выбирать несколько непрерывных диапазонов текста одновременно. Например. в Word пользователь может выбрать диапазон текста с помощью щелчка и перетаскивания, затем, удерживая нажатой клавишу управления, щелкнуть и перетащить в другое место и добавить еще один непересекающийся диапазон в набор выбора. 06.08.2014
  • @ user3803929 - у меня такое впечатление, что это не поддерживается. 06.08.2014
  • То, что я пытаюсь достичь, почти идентично сообщению из WPF RichTextBox - Selected Block? . Однако, хотя выбирается только один блок, я хочу выбрать все блоки в rtb.Selection.Text (не весь текст внутри rtb), если это имеет смысл. Я все еще изучаю WPF RichTextBox. 06.08.2014

Ответы:


1

Если вы просто хотите найти верхний уровень _ 1_, перекрывающие текущий selection range, вы можете сделать это:

public static class FlowDocumentHelper
{
    public static bool Overlaps(this TextElement element, TextPointer start, TextPointer end)
    {
        return element.ContentEnd.CompareTo(start) > 0 && element.ContentStart.CompareTo(end) < 0;
    }
}

а потом

var blocks = richTextBox.Document.Blocks.Where(block => block.Overlaps(richTextBox.Selection.Start, richTextBox.Selection.End));

Однако, если вы ищете абзацы, которые перекрывают текущий диапазон выбора, это не сработает, потому что они могут быть скрыты глубоко внутри иерархии текстовых элементов, например, внутри рисунок внутри список внутри таблица внутри раздел. Чтобы действительно обнаружить абзацы, перекрывающие текущий диапазон выбора, вы должны рекурсивно пройтись по иерархии блоков, а WPF не предоставляет прямого способа сделать это (хотя у них определенно есть эта информация внутри!).

Таким образом, можно было либо вручную создать рекурсивные итераторы для всех возможных _ 4_ классы, которые могут содержать дочерние элементы, или перебирать все _ 5_ в документе и использовать их для обнаружения иерархии. Следующее использует последнюю стратегию:

public static class FlowDocumentHelper
{
    public static IEnumerable<TTextElement> WalkTextRange<TTextElement>(this FlowDocument doc, TextPointer start, TextPointer end) where TTextElement : TextElement
    {
        var lastVisited = new Dictionary<int, TTextElement>();
        foreach (var stack in doc.WalkTextHierarchy())
        {
            var element = stack.Peek() as TTextElement;
            if (element != null)
            {
                TTextElement previous;
                if (!lastVisited.TryGetValue(stack.Count - 1, out previous) || previous != element)
                {
                    if (element.Overlaps(start, end))
                        yield return element;
                    lastVisited[stack.Count - 1] = element;
                }
            }
        }
    }

    public static bool Overlaps(this TextElement element, TextPointer start, TextPointer end)
    {
        return element.ContentEnd.CompareTo(start) > 0 && element.ContentStart.CompareTo(end) < 0;
    }

    public static IEnumerable<Stack<DependencyObject>> WalkTextHierarchy(this FlowDocument doc)
    {
        if (doc == null)
            throw new ArgumentNullException();

        var stack = new Stack<DependencyObject>();

        // Keep a TextPointer for FlowDocument.ContentEnd handy, so we know when we're done.
        TextPointer docEnd = doc.ContentEnd;

        // Keep going until the TextPointer is equal to or greater than ContentEnd.
        for (var iterator = doc.ContentStart; 
            (iterator != null) && (iterator.CompareTo(docEnd) < 0);
            iterator = iterator.GetNextContextPosition(LogicalDirection.Forward))
        {
            var parent = iterator.Parent;

            // Identify the type of content immediately adjacent to the text pointer.
            TextPointerContext context = iterator.GetPointerContext(LogicalDirection.Forward);

            switch (context)
            {
                case TextPointerContext.ElementStart:
                case TextPointerContext.EmbeddedElement:
                case TextPointerContext.Text:
                    PushElement(stack, parent);
                    yield return stack;
                    break;

                case TextPointerContext.ElementEnd:
                    break;

                default:
                    throw new System.Exception("Unhandled TextPointerContext " + context.ToString());
            }

            switch (context)
            {
                case TextPointerContext.ElementEnd:
                case TextPointerContext.EmbeddedElement:
                case TextPointerContext.Text:
                    PopToElement(stack, parent);
                    break;

                case TextPointerContext.ElementStart:
                    break;

                default:
                    throw new System.Exception("Unhandled TextPointerContext " + context.ToString());
            }
        }
    }

    static int IndexOf<T>(Stack<T> source, T value)
    {
        int index = 0;
        var comparer = EqualityComparer<T>.Default;
        foreach (T item in source)
        {
            if (comparer.Equals(item, value))
                return index;
            index++;
        }
        return -1;
    }

    static void PopToElement<T>(Stack<T> stack, T item)
    {
        for (int index = IndexOf(stack, item); index >= 0; index--)
            stack.Pop();
    }

    static void PushElement<T>(Stack<T> stack, T item)
    {
        PopToElement(stack, item);
        stack.Push(item);
    }
}

А потом

var paragraphs = richTextBox.Document.WalkTextRange<Paragraph>(richTextBox.Selection.Start, richTextBox.Selection.End);

(Примечание. Непроизводственный код прошел среднюю проверку.)

Наконец, если вы хотите разрешить пользователям использовать Ctrl-Select несколько диапазонов текста, которые не расположены рядом друг с другом, как это можно сделать в Word, как описано здесь: Выберите элементы, которые не являются ' t рядом друг с другом, то я думаю, вам не повезло. RichTextBox не поддерживает такое взаимодействие с пользователем.

06.08.2014
  • @ user3803929 - если на ваш вопрос дан ответ, отметьте его как такие. Спасибо! 06.08.2014
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..