Вот пользовательский класс ComboBox (здесь он называется FontListCombo
), который показывает совместимые системные шрифты, представляющие каждый элемент ComboBox с использованием FontFamily имя в качестве текста элемента и соответствующий шрифт для рисования текста элемента (на практике классический c селектор шрифтов ComboBox).
Пользовательский элемент управления автоматически заполняется во время выполнения списком доступных шрифтов в системе. Он также реагирует на сообщения WM_FONTCHANGE
(транслируется при изменении пула системных шрифтов; например, шрифт добавляется или удаляется из папки Fonts
), чтобы обновить список шрифтов и отразить изменение ( чтобы также не пытаться использовать шрифт, которого больше не существует).
Текст элементов ComboBox отрисовывается с использованием TextRenderer.DrawText () вместо Graphics.DrawString () , поскольку первый дает более четкие результаты в этом контексте.
Коллекция ComboBox.Items
представлена коллекцией объектов класса FontObject
, классом publi c, в котором хранятся некоторые свойства каждого FontFamily, а также предоставляется пара stati c методы, используемые внутри для возврата объекта Font или FontFamily, вызывая соответствующие методы publi c настраиваемого ComboBox:
- Метод
GetSelectedFont(SizeInPoints, FontStyle)
вернуть объект Font из текущего ComboBox.SelectedItem
. GetSelectedFontFamily()
вернуть объект FontFamily из текущего ComboBox.SelectedItem
.
Он также переопределяет ToString()
, чтобы вернуть сводку значений его свойств.
Этот тип контейнера объектов здесь больше подходит: сохранение объекта FontFamily в качестве элементов ConboBox, несомненно, создаст различные виды проблем, наиболее заметной и c самой заметной является то, что некоторые объекты FontFamily становятся недействительными. со временем или даже сразу после того, как они были сохранены. Эти объекты изначально не предназначены для постоянного хранения, так что это не совсем сюрприз.
Как показано в примере, чтобы получить текущий Font и FontFamily из ComboBox.SelecteItem
:
(здесь экземпляр ComboBox назван cboFontList
)
private void cboFontList_SelectionChangeCommitted(object sender, EventArgs e)
{
Font font = cboFontList.GetSelectedFont(this.Font.SizeInPoints, FontStyle.Regular);
FontFamily family = cboFontList.GetSelectedFontFamily();
string fontDetails = (cboFontList.SelectedItem as FontListCombo.FontObject).ToString();
}
Класс FontObject хранит некоторые важные детали FontFamily, такие как Cell Ascent , Cell Descent , EM Size и Межстрочный интервал .
Некоторые подробности того, как использовать эти функции, описаны здесь:
Правильное рисование текста с помощью пути к графике
Шрифты и текст метрики
Вот как это работает:
FontListCombo Пользовательский элемент управления:
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
[DesignerCategory("Code")]
public class FontListCombo : ComboBox
{
private List<FontObject> fontList = null;
public FontListCombo() {
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.DrawMode = DrawMode.OwnerDrawVariable;
}
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
if (!DesignMode) GetFontFamilies();
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
if ((Items.Count == 0) || e.Index < 0) return;
e.DrawBackground();
var flags = TextFormatFlags.Left | TextFormatFlags.VerticalCenter;
using (var family = new FontFamily(this.GetItemText(Items[e.Index])))
using (var font = new Font(family, 10F, FontStyle.Regular, GraphicsUnit.Point)) {
TextRenderer.DrawText(e.Graphics, family.Name, font, e.Bounds, this.ForeColor, flags);
}
e.DrawFocusRectangle();
base.OnDrawItem(e);
}
protected override void OnMeasureItem(MeasureItemEventArgs e) {
base.OnMeasureItem(e);
e.ItemHeight = this.Font.Height + 4;
}
private void GetFontFamilies()
{
this.fontList = new List<FontObject>();
fontList.AddRange(FontFamily.Families
.Where(f => f.IsStyleAvailable(FontStyle.Regular))
.Select(f => new FontObject(f)).ToArray());
this.DisplayMember = "FamilyName";
this.ValueMember = "EmHeight";
this.DataSource = fontList;
}
public FontFamily GetSelectedFontFamily()
{
if (this.SelectedIndex < 0) return null;
return FontObject.GetSelectedFontFamily((FontObject)this.SelectedItem);
}
public Font GetSelectedFont(float sizeInPoints, FontStyle style)
{
if (this.SelectedIndex < 0) return null;
return FontObject.GetSelectedFont((FontObject)this.SelectedItem, sizeInPoints, style);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg) {
case WM_FONTCHANGE: // The System Font pool has changed
GetFontFamilies();
break;
}
}
public class FontObject
{
public FontObject(FontFamily family) { GetFontFamilyInfo(family); }
public string FamilyName { get; set; }
public int EmHeight { get; set; }
public int CellAscent { get; set; }
public int CellDescent { get; set; }
public int LineSpacing { get; set; }
private void GetFontFamilyInfo(FontFamily family)
{
this.FamilyName = family.Name;
this.EmHeight = family.GetEmHeight(FontStyle.Regular);
this.CellAscent = family.GetCellAscent(FontStyle.Regular);
this.CellDescent = family.GetCellDescent(FontStyle.Regular);
this.LineSpacing = family.GetLineSpacing(FontStyle.Regular);
}
internal static FontFamily GetSelectedFontFamily(FontObject fobj)
=> new FontFamily(fobj.FamilyName);
internal static Font GetSelectedFont(FontObject fobj, float sizeInPoints, FontStyle style)
=> new Font(GetSelectedFontFamily(fobj), sizeInPoints, style);
public override string ToString()
{
var sb = new StringBuilder();
sb.AppendLine(this.FamilyName);
sb.AppendLine($"Em Height: {this.EmHeight}");
sb.AppendLine($"Cell Ascent: {this.CellAscent}");
sb.AppendLine($"Cell Descent: {this.CellDescent}");
sb.AppendLine($"Line Spacing: {this.LineSpacing}");
return sb.ToString();
}
}
}