Создать событие клика на каждое слово в TextBox WPF

возникла потребность при выводе текста в TextBox. К каждому слову прикреплять событие клика на него. Проблема в том что количество текста и слов может быть разное. Но по каждому слову должно быть событие по которому происходят какие-либо действия.

Основные вопросы такие:

  1. Как отслеживать на какое слово нажал пользователь в TextBox?
  2. Как к каждому слову прикрепить доп. данные. Которые потом можно использовать в событии.

Ответы (1 шт):

Автор решения: Bulson

Небольшой пример без MVVM.

пример работы Используем событие двойного клика внутри текстбокса PreviewMouseDoubleClick.

public partial class MainWindow : Window
{
    private readonly WordsService _wordsService;
    private readonly YandexServices _yandexServices;

    public MainWindow()
    {
        InitializeComponent();

        _wordsService = new WordsService();
        _yandexServices = new YandexServices();

        _textBox.PreviewMouseDoubleClick += TextBox_PreviewMouseDoubleClick;
    }

    private async void TextBox_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        if (String.IsNullOrWhiteSpace(_textBox.Text))
            return;

        //находим слово по которому был двойной клик
        var word = _wordsService.GetWordByPosition(_textBox.Text, _textBox.SelectionStart);

        //находим перевод слова
        var result = await _yandexServices.GetDictionaryAnswerAsync(word.Value,
            YandexServices.TranslationDirection.RuEng);
        word.Translation = result.Text;

        //показываем слово и его перевод
        var message = $"Слово: {word.Value}"
            + Environment.NewLine
            + $"Перевод: {word.Translation}";
        MessageBox.Show(message);
    }
}

Идея достаточно простая. Разбиваем текст на слова

public class Word
{
    //порядковый номер в тексте
    public int OrderNumber { get; }
    //номер позиции первой буквы в тексте
    public int StartPosition { get; }
    //номер позиции последней буквы в тексте
    public int EndPosition => StartPosition + Value.Length - 1;
    //значение слова
    public string Value { get; }
    //перевод значения слова
    public string Translation { get; set; }

    public Word(int orderNumber, int startPosition, string value)
    {
        if (string.IsNullOrWhiteSpace(value))
            throw new ArgumentException(nameof(value));

        OrderNumber = orderNumber;
        StartPosition = startPosition;
        Value = value;
    }

    /// <summary>
    /// Относится ли данная позиция в тексте к этому слову
    /// </summary>
    /// <param name="position">позиция в тексте</param>
    /// <returns>true если позиция соответствует данному слову</returns>
    public bool IsThisItByPosition(int position)
    {
        return position >= StartPosition
            && position <= EndPosition;
    }
}

А потом в этой коллекции слов ищем нужное слово по значению SelectionStart, для этого напишем такой класс

public class WordsService
{
    private string _currentText = String.Empty;
    private List<Word> _words;

    /// <summary>
    /// Получение коллекции слов из текста
    /// </summary>
    /// <param name="text">текст для разбора</param>
    /// <returns>коллекция слов</returns>
    public List<Word> GetWords(string text)
    {
        if (string.IsNullOrEmpty(text))
            throw new ArgumentException(nameof(text));

        //готовим результат
        var words = new List<Word>();

        //нумерация слов в тексте
        int wordOrderNumber = 0;
        //позиция первой буквы слова
        int wordStartPosition = 0;
        //для посимвольного набора слова
        List<char> wordChars = new List<char>();

        var chars = text.ToCharArray();
        for (int i = 0; i < chars.Length; i++)
        {
            //извлекаем текущий символ
            var current = chars[i];

            if (Char.IsLetter(current))
            {
                //если это первая буква слова
                if (wordChars.Count == 0)
                {
                    wordStartPosition = i;
                }

                //вносим букву в массив слова
                wordChars.Add(current);

                //если это последний символ в тексте, т.е. текст заканчивается на слове
                //нужно добавить слово
                if (i + 1 == chars.Length)
                {
                    AddWord(words, ++wordOrderNumber, wordChars, wordStartPosition);
                }
            }
            else
            {
                //т.е. текущий символ не относится к слову
                //и до этого у нас возможно собиралось слово
                //и его нужно закрывать и создавать слово
                if (wordChars.Count > 0)
                {
                    AddWord(words, ++wordOrderNumber, wordChars, wordStartPosition);
                    //очищаем для следующего слова
                    wordChars.Clear();
                }
            }
        }

        return words;
    }

    /// <summary>
    /// Получить слово по позиции в тексте
    /// </summary>
    /// <param name="text">текст содержащий искомое слово</param>
    /// <param name="position">позиция искомого слова</param>
    /// <returns>слово</returns>
    public Word GetWordByPosition(string text, int position)
    {
        if (string.IsNullOrWhiteSpace(text))
            throw new ArgumentException(nameof(text));

        if (String.IsNullOrEmpty(_currentText)
            || _currentText.Equals(text) == false)
        {
            _currentText = text;
            _words = GetWords(text);
        }

        var word = _words.First(w => w.IsThisItByPosition(position));
        return word;
    }

    private void AddWord(List<Word> words, int orderNumber,
        List<char> wordChars, int startPosition)
    {
        var value = new String(wordChars.ToArray());
        words.Add(new Word(orderNumber, startPosition, value));
    }
}

Получение перевода к вопросу не относится. Весь пример можно глянуть здесь.

→ Ссылка