Как отобразить шрифт из памяти privatefontcollection в редактируемые элементы управления

Это продолжение загрузки шрифта из ресурсов в PrivateFontCollection приводит к повреждению

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

  • Посмотреть список
  • Текстовое окно
  • RichTextBox
  • Поле со списком
  • ... и многое другое...

Я попытался информацию отсюда, которая в основном играет с Application.SetCompatibleTextRenderingDefault линия в Program.cs (никто не уточнил, где этот параметр по умолчанию, поэтому я документирую его здесь). Я также поиграл с текстовыми элементами управления Telerik, DevExpress и Infragistics, все, кроме Telerik, не имеют встроенной функции совместимого рендеринга текста. Элемент управления Teleriks имеет метод, однако он имеет нулевой эффект, включая невозможность установить передний цвет на то, что сохраняется в свойстве (другое животное, просто отметив сбой элемента управления Telerik radTextBox).

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

В итоге:

  • Шрифт загружается из ресурса в память в PrivateFontCollection
  • Приложение не падает
  • Тот же шрифт успешно используется на ярлыках (с ними работает UseCompatibleTextRendering) - в той же форме, в том же проекте.

  • Элементы управления, на которые влияет эта (новая?) Проблема, являются строго любыми элементами управления, которые можно потенциально "ввести", такими как TextEdit, ListView, RichText, Combo и т. Д.

  • Говоря о переключении, игре или игре - это означает, что я пытался использовать все возможные комбинации указанных элементов управления и / или кода, которые были мне предоставлены. Например: Application.SetCompatibleTextRenderingDefault имеет только 3 возможных комбинации в себе. (true)(false) или полностью опущен. После завершения этих трех комбинаций я продолжил (базовое устранение неполадок здесь, но считаю необходимым объяснить все базы), чтобы добавить элемент управления Telerik, а затем попробовать все комбинации в элементе управления Telerik вместе со всеми комбинациями Application.SetCompatibleTextRenderingDefault команда. Количество тестов является экспоненциальным и представляет собой число возможных комбинаций возможностей рендеринга, умноженное на количество попыток элементов управления, умноженное на количество возможностей для элемента управления рендеринга, которые есть у каждого из этих элементов управления, и так далее.

1 ответ

Решение

После долгих раскопок и пустых рассуждений по этому вопросу (в том числе по поводу этого вопроса, который меня до сих пор озадачивает), я нашел решение этой проблемы, с которой, как мне кажется, многие столкнулись, а также оказалось пустым - Вручил прибегнуть к простой установке шрифта в виде файла в системе пользователей. Как я и думал, это вовсе не обязательно, и вы МОЖЕТЕ встроить шрифт простым способом, который позволяет использовать его на любом элементе управления, включая TextBox, ComboBox и т. Д. Все, что пожелает ваше сердце.

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

Шаг 1 - Выбор жертвы (выбор шрифта)

Для демонстрационных целей (и популярного спроса) я буду использовать шрифт FontAwesome (v 4.1 на момент написания этой статьи)

  • Внутри вашего проекта, перейдите к Project > <your project name> Properties
  • Нажмите Resources (должно быть на левой стороне)
  • Нажмите стрелку раскрывающегося меню справа от Add Resource и выберите Add Existing File,

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

  • Убедитесь, что All Files (*.*) В раскрывающемся списке выберите нужный файл шрифта и выберите его, затем нажмите кнопку [Открыть]. введите описание изображения здесь

Теперь вы должны увидеть что-то вроде следующего: введите описание изображения здесь

  • Нажмите [CTRL]+[S], чтобы сохранить проект.

Шаг 2 - Погружение в код

Скопируйте следующий код и сохраните его как "MemoryFonts.cs", затем добавьте его в свой проект

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Runtime.InteropServices;
using System.Drawing.Text;
using System.Drawing;

public static class MemoryFonts {

    [DllImport( "gdi32.dll" )]
    private static extern IntPtr AddFontMemResourceEx( IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts );
    private static PrivateFontCollection pfc { get; set; }

    static MemoryFonts() {
        if ( pfc==null ) { pfc=new PrivateFontCollection(); }
    }

    public static void AddMemoryFont(byte[] fontResource) {
        IntPtr p;
        uint c = 0;

        p=Marshal.AllocCoTaskMem( fontResource.Length );
        Marshal.Copy( fontResource, 0, p, fontResource.Length );
        AddFontMemResourceEx( p, (uint)fontResource.Length, IntPtr.Zero, ref c );
        pfc.AddMemoryFont( p, fontResource.Length );
        Marshal.FreeCoTaskMem( p );

        p = IntPtr.Zero;
    }

    public static Font GetFont( int fontIndex, float fontSize = 20, FontStyle fontStyle = FontStyle.Regular ) {
        return new Font(pfc.Families[fontIndex], fontSize, fontStyle);
    }

    // Useful method for passing a 4 digit hex string to return the unicode character
    // Some fonts like FontAwesome require this conversion in order to access the characters
    public static string UnicodeToChar( string hex ) {
        int code=int.Parse( hex, System.Globalization.NumberStyles.HexNumber );
        string unicodeString=char.ConvertFromUtf32( code );
        return unicodeString;
    }

}

Шаг 3 - Сделать это красиво (используя шрифт)

  • В главной форме добавьте элемент управления TextBox из панели инструментов. введите описание изображения здесь

  • Внутри form_Load событие, поставьте следующий код (в моем случае ресурс fontawesome_webfont, замените его на любое имя вашего шрифтового ресурса)

    private void Form1_Load( object sender, EventArgs e ) {
        MemoryFonts.AddMemoryFont( Properties.Resources.fontawesome_webfont );
        textBox1.Font = MemoryFonts.GetFont(
                            // using 0 since this is the first font in the collection
                            0,
    
                            // this is the size of the font
                            20, 
    
                            // the font style if any. Bold / Italic / etc
                            FontStyle.Regular
                        );
    
        // since I am using FontAwesome, I would like to display one of the icons
        // the icon I chose is the Automobile (fa-automobile). Looking up the unicode
        // value using the cheat sheet https://fortawesome.github.io/Font-Awesome/cheatsheet/
        // shows :  fa-automobile (alias) [&#xf1b9;]
        // so I pass 'f1b9' to my UnicodeToChar method which returns the Automobile icon 
        textBox1.Text = MemoryFonts.UnicodeToChar( "f1b9" );
    }
    

Конечный результат

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


Вы можете заметить или не заметить, что я создал этот метод, имея в виду, что вы можете добавить несколько встроенных шрифтов. В этом случае вы просто позвоните AddMemoryFont() для каждого из шрифтов, которые вы хотите добавить, а затем используйте соответствующее значение индекса (на основе нуля) при использовании GetFont()

Вопреки документу, касающемуся документации PrivateFontCollection.AddMemoryFont() от Microsoft, вам НЕ НУЖНО использовать UseCompatibleTextRendering или же SetCompatibleTextRenderingDefault совсем. Метод, который я описал выше, позволяет естественную визуализацию шрифта в объектах / элементах управления.

Другие вопросы по тегам