Создание пользовательского элемента управления текстовым блоком в WPF

#wpf #render #textblock

#wpf #визуализация #текстовый блок

Вопрос:

Я создал пользовательский элемент управления WPF, уникальной функцией которого является отображение текста.
Я пытался использовать TextBlock из System.Windows.Controls пространства имен, но у меня это не работает (у меня ~ 10000 строк с разной позицией и слишком большой потерей памяти).
Итак, я попытался создать свой собственный элемент управления, унаследовав FrameworkElement, переопределяющий OnRender метод, который теперь содержит одну строку:

 drawingContext.DrawText(...);
  

Но…
Я получаю немного запутанный результат.
После сравнения производительности для 10000 объектов я понял, что время, необходимое для создания и добавления в Canvas, по-прежнему составляет ~ 10 секунд, а использование памяти для моего приложения увеличивается с ~ 32 МБ до ~ 60 МБ!!!
Так что никаких преимуществ вообще.

Кто-нибудь может объяснить, почему это происходит, и каков другой способ создать простой (простой = выделять меньше памяти, создавать меньше времени) визуальный с двумя функциями:

  1. отображение текста
  2. установите положение (используя толщину или TranslateTransform )

Спасибо.

Комментарии:

1. Не могли бы вы опубликовать код того, что вы именно делаете? Также не совсем понятно, почему TextBlock это вам не помогает? Вы изучали только для чтения RichTextBox ? FlowDocument для сложных текстов макета? Я согласен с @John о StringBuilder.

2. TextBlock помогает мне, но занимает слишком много памяти из-за почти 10000 текстовых блоков, и мне нужно так много, потому что у каждого из них разное положение.

3. Не поймите меня неправильно, возможно, внешний вид всего элемента управления можно изменить с помощью стилей, но я никогда не пробовал. Итак, я хочу задать еще один вопрос: могу ли я получить этот внешний вид, если применю стиль к кнопке? Элементы управления медиаплеером ps. кнопки на картинке сделаны путем объединения нескольких эллипсов и контуров.

Ответ №1:

Проверьте AvalonEdit

Также не уверен, как вы храните строки, но использовали ли вы StringBuilder раньше?

Комментарии:

1. Проверьте код, который я опубликовал. Я не уверен, как поможет StringBuilder?

Ответ №2:

Вот мой код (немного измененный):

 public class SimpleTextBlock : FrameworkElement
{
    #region Static

    private const double _fontSize = 12;
    private static Point _emptyPoint;
    private static Typeface _typeface;
    private static LinearGradientBrush _textBrush;

    public readonly static DependencyProperty TextWidthProperty;

    static SimpleTextBlock()
    {
        _emptyPoint = new Point();
        _typeface = new Typeface(new FontFamily("Sergoe UI"), FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);

        GradientStopCollection GSC = new GradientStopCollection(2);
        GSC.Add(new GradientStop(Color.FromArgb(160, 255, 255, 255), 0.0));
        GSC.Add(new GradientStop(Color.FromArgb(160, 180, 200, 255), 0.7));
        _textBrush = new LinearGradientBrush(GSC, 90);
        _textBrush.Freeze();


        SimpleTextBlock.TextWidthProperty = DependencyProperty.Register(
            "TextWidth",
            typeof(double),
            typeof(SimpleTextBlock),
            new FrameworkPropertyMetadata(0.0d, FrameworkPropertyMetadataOptions.AffectsRender));
    }

    #endregion

    FormattedText _formattedText;

    public SimpleTextBlock(string text)
    {
        _formattedText = new FormattedText(text, System.Globalization.CultureInfo.InvariantCulture, FlowDirection.LeftToRight, _typeface, _fontSize, _textBrush);
    }

    public SimpleTextBlock(string text, FlowDirection FlowDirection)
    {
        _formattedText = new FormattedText(text, System.Globalization.CultureInfo.InvariantCulture, FlowDirection, _typeface, _fontSize, _textBrush);
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        _formattedText.MaxTextWidth = (double)GetValue(TextWidthProperty);
        drawingContext.DrawText(_formattedText, _emptyPoint);
    }

    public double TextWidth
    {
        get { return (double)base.GetValue(TextWidthProperty); }
        set { base.SetValue(TextWidthProperty, value); }
    }

    public double ActualTextWidth
    {
        get { return _formattedText.Width; }
    }

    public double ActualTextHeight
    {
        get { return _formattedText.Height; }
    }
}
  

Комментарии:

1. Хотя этот код хорош, я думаю, что люди (включая меня) задавались вопросом, зачем вам нужно 10 000 текстовых блоков в одном представлении. Похоже, что существует фундаментальная проблема с тем, как выкладывается страница. Вы смотрели FlowDocuments ? Не могли бы вы приложить снимок экрана или рисунок того, как выглядит программа, чтобы мы могли помочь вам определить наилучший курс действий

2. У меня еще нет SS, но я хочу создать медиа-библиотеку с поиском, что-то вроде библиотеки в WindowsMediaPlayer. Я ничего не знаю о FlowDocuments, но я намерен посмотреть на это.

3. Почему бы не использовать стилизованный ListBox или DataGrid ?

4. Я использовал ListBox, но он выглядит так плохо, и я не знаком со стилизацией какого-либо компонента, поэтому я создаю свой собственный. Я думаю, что проще создать свой собственный элемент управления, который я могу изменить в любое время, чем научиться использовать тот, который уже существует. Можете ли вы опубликовать мне какой-либо код, объясняющий, как использовать стили? Стилизованный ListBox будет хорош, как и любой другой.

Ответ №3:

Поскольку, похоже, мы решили, что вам следует стилизовать элемент управления, подобный listbox, вот несколько примеров различных действий, которые вы можете сделать:

Используйте изображения в качестве элементов

Стилизованный и обязательный

Честно говоря, все зависит от того, как вы хотите, чтобы это выглядело. WPF хорош тем, насколько он контролирует, как что-то выглядит.

Безумный пример использования listbox для создания орбит планеты