Форматирование текста в WinForm Label

Можно ли отформатировать определенный текст в метке WinForm вместо того, чтобы разбивать текст на несколько меток? Не обращайте внимания на теги HTML в тексте метки; это используется только для того, чтобы получить мою точку зрения.

Например:

Dim myLabel As New Label
myLabel.Text = "This is <b>bold</b> text.  This is <i>italicized</i> text."

Что будет отображать текст на этикетке как:

Это полужирный текст. Это выделенный курсивом текст.


person Bryan Roth    schedule 14.08.2008    source источник
comment
Брайан, если вы использовали № 2 или № 3 ответа Дэнни, не могли бы вы поделиться кодом или ссылкой на то, что вы использовали? Спасибо.   -  person FastAl    schedule 27.02.2012
comment
@FastAl Кажется, я только что использовал №1, но, возможно, использовал №3. У меня больше нет доступа к кодовой базе, поэтому я не могу привести пример. Прости.   -  person Bryan Roth    schedule 09.03.2012


Ответы (12)


Это невозможно с меткой WinForms как таковой. На этикетке должен быть ровно один шрифт, ровно один размер и одно начертание. У вас есть несколько вариантов:

  1. Используйте отдельные ярлыки
  2. Создайте новый класс, производный от Control, который делает свое собственное рисование через GDI+, и используйте его вместо Label; это, вероятно, ваш лучший вариант, так как он дает вам полный контроль над тем, как указать элементу управления форматировать его текст.
  3. Используйте сторонний элемент управления label, который позволит вам вставлять фрагменты HTML (есть куча — проверьте CodeProject); это будет чья-то реализация № 2.
person TheSmurf    schedule 14.08.2008

Не совсем, но вы можете подделать это с помощью RichTextBox только для чтения без границ. RichTextBox поддерживает формат Rich Text Format (rtf).

person ageektrapped    schedule 14.08.2008

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

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

Хитрость заключается в том, чтобы добавить отключенные ссылки к частям вашего текста, которые вы хотите подчеркнуть, а затем глобально установить цвета ссылок, чтобы они соответствовали остальной части метки. Вы можете установить почти все необходимые свойства во время разработки, кроме части Links.Add(), но здесь они в коде:

linkLabel1.Text = "You are accessing a government system, and all activity " +
                  "will be logged.  If you do not wish to continue, log out now.";
linkLabel1.AutoSize = false;
linkLabel1.Size = new Size(365, 50);
linkLabel1.TextAlign = ContentAlignment.MiddleCenter;
linkLabel1.Links.Clear();
linkLabel1.Links.Add(20, 17).Enabled = false;   // "government system"
linkLabel1.Links.Add(105, 11).Enabled = false;  // "log out now"
linkLabel1.LinkColor = linkLabel1.ForeColor;
linkLabel1.DisabledLinkColor = linkLabel1.ForeColor;

Результат:

введите здесь описание изображения

person Geoff    schedule 13.06.2014
comment
О, замечательно. Я никогда не знал, что метки ссылок могут иметь определенные области в качестве ссылок. На самом деле это гораздо ближе к варианту использования, который я искал, чем фактический вопрос, заданный здесь; моя метка все равно была кликабельной. Намного лучше с одной кликабельной областью. - person Nyerguds; 31.03.2016

Работающее решение для меня - использование пользовательского RichEditBox. При правильных свойствах он будет выглядеть как простая метка с поддержкой жирного шрифта.

1) Сначала добавьте свой пользовательский класс RichTextLabel с отключенным символом вставки:

public class RichTextLabel : RichTextBox
{
    public RichTextLabel()
    {
        base.ReadOnly = true;
        base.BorderStyle = BorderStyle.None;
        base.TabStop = false;
        base.SetStyle(ControlStyles.Selectable, false);
        base.SetStyle(ControlStyles.UserMouse, true);
        base.SetStyle(ControlStyles.SupportsTransparentBackColor, true);

        base.MouseEnter += delegate(object sender, EventArgs e)
        {
            this.Cursor = Cursors.Default;
        };
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == 0x204) return; // WM_RBUTTONDOWN
        if (m.Msg == 0x205) return; // WM_RBUTTONUP
        base.WndProc(ref m);
    }
}

2) Разделите предложение на слова с флагом IsSelected, который определяет, должно ли это слово быть выделено жирным шрифтом или нет:

        private void AutocompleteItemControl_Load(object sender, EventArgs e)
    {
        RichTextLabel rtl = new RichTextLabel();
        rtl.Font = new Font("MS Reference Sans Serif", 15.57F);
        StringBuilder sb = new StringBuilder();
        sb.Append(@"{\rtf1\ansi ");
        foreach (var wordPart in wordParts)
        {
            if (wordPart.IsSelected)
            {
                sb.Append(@"\b ");
            }
            sb.Append(ConvertString2RTF(wordPart.WordPart));
            if (wordPart.IsSelected)
            {
                sb.Append(@"\b0 ");
            }
        }
        sb.Append(@"}");

        rtl.Rtf = sb.ToString();
        rtl.Width = this.Width;
        this.Controls.Add(rtl);
    }

3) Добавьте функцию для преобразования вашего текста в действительный rtf (с поддержкой Unicode!):

   private string ConvertString2RTF(string input)
    {
        //first take care of special RTF chars
        StringBuilder backslashed = new StringBuilder(input);
        backslashed.Replace(@"\", @"\\");
        backslashed.Replace(@"{", @"\{");
        backslashed.Replace(@"}", @"\}");

        //then convert the string char by char
        StringBuilder sb = new StringBuilder();
        foreach (char character in backslashed.ToString())
        {
            if (character <= 0x7f)
                sb.Append(character);
            else
                sb.Append("\\u" + Convert.ToUInt32(character) + "?");
        }
        return sb.ToString();
    }

Образец

Работает как шарм для меня! Решения собраны из:

Как преобразовать строку в RTF в C#?

Форматировать текст в текстовом поле Rich Text

Как скрыть курсор в RichTextBox?

person Nigrimmist    schedule 25.02.2015
comment
Это лучшее доступное решение, если вы хотите оставаться максимально легким и избегать сторонних зависимостей. Я протестировал несколько альтернатив, и этот метод работает лучше всего, а также правильно обрабатывает .AutoSize и .WordWrap, как обычный ярлык. Я также встроил простую функцию преобразования HTML в RTF, которая обрабатывает прямые замены с помощью основных тегов (жирный шрифт, курсив и т. д.), поэтому мне вообще не нужно запоминать формат RTF. Я просто загружаю строку в формате HTML. - person Special Sauce; 22.04.2017

  1. Создайте текст в виде файла RTF в wordpad
  2. Создать элемент управления Rich Text без границ и с возможностью редактирования = false
  3. Добавьте файл RTF в проект в качестве ресурса
  4. В Form1_load делаем

    myRtfControl.Rtf = Resource1.MyRtfControlText

person Phil    schedule 21.10.2009
comment
Хороший момент использования wordpad! Небольшая сложность: он генерирует много мусора, что немного усложняет понимание результирующего rtf (но может быть безопасно удалено) ... Лучше, чем чтение спецификации rtf. - person sharpener; 29.10.2014
comment
@sharpener Вы должны увидеть rtf, который создает MS Word ... простое открытие его в Wordpad и нажатие кнопки «Сохранить» значительно уменьшает его, иногда даже до 10% от исходного размера файла. И нет, я только хотел бы пошутить или преувеличить X_x - person Nyerguds; 31.03.2016

AutoRichLabel

AutoRichLabel с отформатированным содержимым RTF

Я решил эту проблему, создав UserControl, содержащий TransparentRichTextBox, доступный только для чтения. TransparentRichTextBox — это RichTextBox, который позволяет быть прозрачным:

ПрозрачныйRichTextBox.cs:

public class TransparentRichTextBox : RichTextBox
{
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    static extern IntPtr LoadLibrary(string lpFileName);

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams prams = base.CreateParams;
            if (TransparentRichTextBox.LoadLibrary("msftedit.dll") != IntPtr.Zero)
            {
                prams.ExStyle |= 0x020; // transparent 
                prams.ClassName = "RICHEDIT50W";
            }
            return prams;
        }
    }
}

Последний UserControl действует как оболочка TransparentRichTextBox. К сожалению, мне пришлось ограничиться AutoSize по-своему, потому что AutoSize из RichTextBox сломались.

AutoRichLabel.designer.cs:

partial class AutoRichLabel
{
    /// <summary> 
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary> 
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Component Designer generated code

    /// <summary> 
    /// Required method for Designer support - do not modify 
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.rtb = new TransparentRichTextBox();
        this.SuspendLayout();
        // 
        // rtb
        // 
        this.rtb.BorderStyle = System.Windows.Forms.BorderStyle.None;
        this.rtb.Dock = System.Windows.Forms.DockStyle.Fill;
        this.rtb.Location = new System.Drawing.Point(0, 0);
        this.rtb.Margin = new System.Windows.Forms.Padding(0);
        this.rtb.Name = "rtb";
        this.rtb.ReadOnly = true;
        this.rtb.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.None;
        this.rtb.Size = new System.Drawing.Size(46, 30);
        this.rtb.TabIndex = 0;
        this.rtb.Text = "";
        this.rtb.WordWrap = false;
        this.rtb.ContentsResized += new System.Windows.Forms.ContentsResizedEventHandler(this.rtb_ContentsResized);
        // 
        // AutoRichLabel
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
        this.BackColor = System.Drawing.Color.Transparent;
        this.Controls.Add(this.rtb);
        this.Name = "AutoRichLabel";
        this.Size = new System.Drawing.Size(46, 30);
        this.ResumeLayout(false);

    }

    #endregion

    private TransparentRichTextBox rtb;
}

AutoRichLabel.cs:

/// <summary>
/// <para>An auto sized label with the ability to display text with formattings by using the Rich Text Format.</para>
/// <para>­</para>
/// <para>Short RTF syntax examples: </para>
/// <para>­</para>
/// <para>Paragraph: </para>
/// <para>{\pard This is a paragraph!\par}</para>
/// <para>­</para>
/// <para>Bold / Italic / Underline: </para>
/// <para>\b bold text\b0</para>
/// <para>\i italic text\i0</para>
/// <para>\ul underline text\ul0</para>
/// <para>­</para>
/// <para>Alternate color using color table: </para>
/// <para>{\colortbl ;\red0\green77\blue187;}{\pard The word \cf1 fish\cf0  is blue.\par</para>
/// <para>­</para>
/// <para>Additional information: </para>
/// <para>Always wrap every text in a paragraph. </para>
/// <para>Different tags can be stacked (i.e. \pard\b\i Bold and Italic\i0\b0\par)</para>
/// <para>The space behind a tag is ignored. So if you need a space behind it, insert two spaces (i.e. \pard The word \bBOLD\0  is bold.\par)</para>
/// <para>Full specification: http://www.biblioscape.com/rtf15_spec.htm </para>
/// </summary>
public partial class AutoRichLabel : UserControl
{
    /// <summary>
    /// The rich text content. 
    /// <para>­</para>
    /// <para>Short RTF syntax examples: </para>
    /// <para>­</para>
    /// <para>Paragraph: </para>
    /// <para>{\pard This is a paragraph!\par}</para>
    /// <para>­</para>
    /// <para>Bold / Italic / Underline: </para>
    /// <para>\b bold text\b0</para>
    /// <para>\i italic text\i0</para>
    /// <para>\ul underline text\ul0</para>
    /// <para>­</para>
    /// <para>Alternate color using color table: </para>
    /// <para>{\colortbl ;\red0\green77\blue187;}{\pard The word \cf1 fish\cf0  is blue.\par</para>
    /// <para>­</para>
    /// <para>Additional information: </para>
    /// <para>Always wrap every text in a paragraph. </para>
    /// <para>Different tags can be stacked (i.e. \pard\b\i Bold and Italic\i0\b0\par)</para>
    /// <para>The space behind a tag is ignored. So if you need a space behind it, insert two spaces (i.e. \pard The word \bBOLD\0  is bold.\par)</para>
    /// <para>Full specification: http://www.biblioscape.com/rtf15_spec.htm </para>
    /// </summary>
    [Browsable(true)]
    public string RtfContent
    {
        get
        {
            return this.rtb.Rtf;
        }
        set
        {
            this.rtb.WordWrap = false; // to prevent any display bugs, word wrap must be off while changing the rich text content. 
            this.rtb.Rtf = value.StartsWith(@"{\rtf1") ? value : @"{\rtf1" + value + "}"; // Setting the rich text content will trigger the ContentsResized event. 
            this.Fit(); // Override width and height. 
            this.rtb.WordWrap = this.WordWrap; // Set the word wrap back. 
        }
    }

    /// <summary>
    /// Dynamic width of the control. 
    /// </summary>
    [Browsable(false)]
    public new int Width
    {
        get
        {
            return base.Width;
        } 
    }

    /// <summary>
    /// Dynamic height of the control. 
    /// </summary>
    [Browsable(false)]
    public new int Height
    {
        get
        {
            return base.Height;
        }
    }

    /// <summary>
    /// The measured width based on the content. 
    /// </summary>
    public int DesiredWidth { get; private set; }

    /// <summary>
    /// The measured height based on the content. 
    /// </summary>
    public int DesiredHeight { get; private set; }

    /// <summary>
    /// Determines the text will be word wrapped. This is true, when the maximum size has been set. 
    /// </summary>
    public bool WordWrap { get; private set; }

    /// <summary>
    /// Constructor. 
    /// </summary>
    public AutoRichLabel()
    {
        InitializeComponent();
    }

    /// <summary>
    /// Overrides the width and height with the measured width and height
    /// </summary>
    public void Fit()
    {
        base.Width = this.DesiredWidth;
        base.Height = this.DesiredHeight;
    }

    /// <summary>
    /// Will be called when the rich text content of the control changes. 
    /// </summary>
    private void rtb_ContentsResized(object sender, ContentsResizedEventArgs e)
    {
        this.AutoSize = false; // Disable auto size, else it will break everything
        this.WordWrap = this.MaximumSize.Width > 0; // Enable word wrap when the maximum width has been set. 
        this.DesiredWidth = this.rtb.WordWrap ? this.MaximumSize.Width : e.NewRectangle.Width; // Measure width. 
        this.DesiredHeight = this.MaximumSize.Height > 0 && this.MaximumSize.Height < e.NewRectangle.Height ? this.MaximumSize.Height : e.NewRectangle.Height; // Measure height. 
        this.Fit(); // Override width and height. 
    }
}

Синтаксис форматированного текста довольно прост:

Параграф:

{\pard This is a paragraph!\par}

Жирный / курсив / подчеркнутый текст:

\b bold text\b0
\i italic text\i0
\ul underline text\ul0

Альтернативный цвет с использованием таблицы цветов:

{\colortbl ;\red0\green77\blue187;}
{\pard The word \cf1 fish\cf0  is blue.\par

Но обратите внимание: всегда заключайте каждый текст в абзац. Кроме того, разные теги могут располагаться друг над другом (например, \pard\b\i Bold and Italic\i0\b0\par), а символ пробела после тега игнорируется. Поэтому, если вам нужен пробел после него, вставьте два пробела (например, \pard The word \bBOLD\0 is bold.\par). Чтобы избежать \, { или }, используйте \ в начале. Для получения дополнительной информации см. полную спецификацию форматированного текста в Интернете.

Используя этот довольно простой синтаксис, вы можете создать что-то вроде того, что вы видите на первом изображении. Содержимое форматированного текста, которое было прикреплено к свойству RtfContent моего AutoRichLabel на первом изображении, было следующим:

{\colortbl ;\red0\green77\blue187;}
{\pard\b BOLD\b0  \i ITALIC\i0  \ul UNDERLINE\ul0 \\\{\}\par}
{\pard\cf1\b BOLD\b0  \i ITALIC\i0  \ul UNDERLINE\ul0\cf0 \\\{\}\par}

AutoRichLabel с отформатированным содержимым RTF

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

Развлекайся!

person Martin Braun    schedule 19.10.2015

В Code Project есть отличная статья 2009 года под названием «Профессиональный HTML-рендерер, который вы будете использовать.", который реализует что-то похожее на то, что нужно исходному плакату.

Я успешно использую его в нескольких наших проектах.

person Uwe Keim    schedule 30.12.2011

Очень простое решение:

  1. Добавьте на форму две метки: LabelA и LabelB.
  2. Перейдите к свойствам LabelA и закрепите его слева.
  3. Перейдите к свойствам LabelB и также закрепите его слева.
  4. Установите для шрифта полужирный шрифт для LabelA .

Теперь LabelB будет смещаться в зависимости от длины текста LabelA.

Это все.

person user3541933    schedule 16.04.2014

Мне тоже было бы интересно узнать, возможно ли это.

Когда мы не смогли найти решение, мы прибегли к элементу управления Component Ones «SuperLabel», который позволяет использовать HTML-разметку в метке.

person Martin    schedule 14.08.2008

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

Помимо того, что уже упоминалось, LabelControl DevExpress — это метка, которая поддерживает это поведение — демонстрация здесь. Увы, это часть платной библиотеки.

Если вы ищете бесплатные решения, я считаю, что HTML Renderer — лучший выбор.

person pKami    schedule 27.02.2014
comment
Раньше, когда мы использовали общие элементы управления DevExpress, у них были огромные проблемы с темами. Например, легко заставить их использовать какую-то квир-тему, но сложно сделать так, чтобы они выглядели так же, как текущая ОС. - person hypersw; 13.08.2015

FlowLayoutPanel хорошо подходит для вашей проблемы. Если вы добавите метки на панель потока и отформатируете свойства шрифта и поля каждой метки, то у вас могут быть разные стили шрифта. Довольно быстрое и простое решение для работы.

person jakebic    schedule 27.08.2014

Ага. Вы можете реализовать, используя HTML Render. Как видите, нажмите на ссылку: https://htmlrenderer.codeplex.com/ Надеюсь, это будет полезно .

person Marinpietri    schedule 01.04.2015