Динамическое форматирование текстовых элементов в ListBox в XAML - PullRequest
0 голосов
/ 28 апреля 2020

Я использую Caliburn Micro, и у меня есть ListBox, который работает для отображения списка элементов, которые я привязал к нему из моей ViewModel.

Однако сейчас я изучаю, как динамически форматировать каждый ListItem, т.е. в моем случае каждая строка может иметь до N значений, которые находятся между двумя токенами, и мне нужно, чтобы они были отформатированы в полужирном.

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

Мой XAML на данный момент для списка выглядит так - это работало, когда было только одно ключевое слово, которое мне нужно было формат, но с тех пор выяснилось, что в одной строке может быть несколько вхождений, поэтому я больше не могу предсказать структуру.

<ListBox ItemsSource="{Binding HighlightList}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock>
                <Run Text="{Binding Path=mStartText}"/>
                <Run Text="{Binding Path=mBoldText}"/>
                <Run Text="{Binding Path=mEndText}"/>
            </TextBlock>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Кто-нибудь еще смог достичь чего-то подобного? Заранее благодарим за любые подсказки!

РЕДАКТИРОВАТЬ:

Итак, для большей ясности скажем, у меня есть две строки:

Строка 1 - "Это тест string "

String 2 -" This is также является Test string

Что мне нужно сделать, это отобразить вышеупомянутые строки в ListBox со строками, обернутыми в тэги EM (курсивом в приведенном выше примере), чтобы они были выделены жирным шрифтом и красным цветом.

Теперь я создал список объектов, каждый из которых будет иметь две переменные - содержимое строки и тип строки (выделено или не выделено), разбирают каждую строку и разбивают ее так, чтобы я пометил, какие части можно распечатать как есть, а какие нужно печатать в выделенном формате.

ViewModel:

    public ObservableCollection<HighlightItem> HighlightList
    {
        get
        {
            return _highlightList;
        }
        set
        {
            _highlightList = value;
            NotifyOfPropertyChange(() => HighlightList);
        }
    }

public void ParseHighlights()
        {
            ObservableCollection<HighlightItem> hlList = new ObservableCollection<HighlightItem>();

            string START_HL_TOKEN = "<em>";
            string END_HL_TOKEN = "</em>";

            if (_documentSnippets.Count > 0)
            {
                foreach (var hlItem in _documentSnippets.Snippets["text"])
                {
                    // Remove tab characters
                    string temp = hlItem.Replace("\t", "");

                    // Remove multiple newline characters and replace with a single one
                    Regex regex = new Regex("(\\n){2,}");

                    string clean_temp = regex.Replace(temp, "\n");
                    string startText = "", hlText = "", endText = "";
                    int start_idx = 0;
                    int end_idx = 0;
                    List<string> stringTokenized = new List<string>();

// THIS BELOW IS PART OF MY NEW APPROACH
                    while(start_idx != clean_temp.Length)
                    {
                        end_idx = clean_temp.IndexOf(START_HL_TOKEN, start_idx);

                        // Highlight token is at the start
                        if(end_idx == 0)
                        {
                            start_idx = end_idx;
                            end_idx = clean_temp.IndexOf(END_HL_TOKEN, start_idx);
                            stringTokenized.Add(clean_temp.Substring(start_idx + 4, end_idx - start_idx));

                            // Move pointer to start of next section, keeping in mind the length of the END token
                            start_idx = end_idx + 4;
                        }
                        else if(end_idx == -1)
                        {
                            end_idx = clean_temp.Length;
                            stringTokenized.Add(clean_temp.Substring(start_idx, end_idx - start_idx));
                            start_idx = end_idx;
                        }
                        else
                        {
                            stringTokenized.Add(clean_temp.Substring(start_idx, end_idx - start_idx));

                            start_idx = end_idx;
                            end_idx = clean_temp.IndexOf(END_HL_TOKEN, start_idx);
                            stringTokenized.Add(clean_temp.Substring(start_idx + 4, end_idx - start_idx));

                            // Move pointer to start of next section
                            start_idx = end_idx + 4;
                        }
                    }
// END OF MY NEW APPROACH

                    // Token is at the beginning of the snippet
                    if (hlItem.IndexOf(START_HL_TOKEN) == 0)
                    {
                        hlText = clean_temp.Substring(clean_temp.IndexOf(START_HL_TOKEN) + START_HL_TOKEN.Length,
                                                   clean_temp.IndexOf(END_HL_TOKEN) - START_HL_TOKEN.Length);

                        endText = clean_temp.Substring(clean_temp.IndexOf(END_HL_TOKEN) + END_HL_TOKEN.Length,
                                                   clean_temp.Length - (clean_temp.IndexOf(END_HL_TOKEN) + END_HL_TOKEN.Length));
                    }
                    // Token is at the end of the snippet
                    else if (clean_temp.IndexOf(END_HL_TOKEN) + END_HL_TOKEN.Length == clean_temp.Length)
                    {
                        startText = clean_temp.Substring(0,
                                                     clean_temp.Length - clean_temp.IndexOf(START_HL_TOKEN));
                        hlText = clean_temp.Substring(clean_temp.IndexOf(START_HL_TOKEN),
                                                  clean_temp.Length - clean_temp.IndexOf(START_HL_TOKEN));
                    }
                    // Token is in the middle of the snippet
                    else
                    {
                        startText = clean_temp.Substring(0,
                                                     clean_temp.IndexOf(START_HL_TOKEN));

                        hlText = clean_temp.Substring(clean_temp.IndexOf(START_HL_TOKEN) + START_HL_TOKEN.Length,
                                                  clean_temp.IndexOf(END_HL_TOKEN) - clean_temp.IndexOf(START_HL_TOKEN) - (END_HL_TOKEN.Length - 1));

                        endText = clean_temp.Substring(clean_temp.IndexOf(END_HL_TOKEN) + END_HL_TOKEN.Length,
                                                   clean_temp.Length - clean_temp.IndexOf(END_HL_TOKEN) - END_HL_TOKEN.Length);
                    }

                    HighlightItem snippet = new HighlightItem(startText, hlText, endText);
                    hlList.Add(snippet);
                }

                HighlightList = hlList;
            }

        }

Итак, в приведенной выше модели у меня есть мой старый подход, в котором я предполагал, что в строке будет только один тег, но когда я понял, что иногда их больше 1, я начал новый подход построения списка представлений обозначение строки, отмечая, какие части должны быть напечатаны нормально, а какие должны быть напечатаны выделенными.

Кроме того, в соответствии с моими стандартами именования, только запускается WPF и C# в месяц или около того go, поэтому изрядно знакомы со всеми соглашениями об именах, извините!

1 Ответ

0 голосов
/ 29 апреля 2020

Использование пользовательского присоединенного свойства помогло мне, следуя подсказке Sinatr, я нашел следующую статью: Форматирование WPF TextBlock выделено жирным шрифтом из строкового свойства

После этого я смог чтобы обеспечить строки со встроенной в них разметкой, и они будут напечатаны соответствующим образом! Спасибо за помощь!

...