Combobox как установить selectedValue - PullRequest
0 голосов
/ 28 мая 2020

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

public YourForm()
{
    InitializeComponent();

    ComboBoxFonts.DrawItem += ComboBoxFonts_DrawItem;           
    ComboBoxFonts.DataSource = System.Drawing.FontFamily.Families.ToList();
}

private void ComboBoxFonts_DrawItem(object sender, DrawItemEventArgs e)
{
    var comboBox = (ComboBox)sender;
    var fontFamily = (FontFamily)comboBox.Items[e.Index];
    var font = new Font(fontFamily, comboBox.Font.SizeInPoints);

    e.DrawBackground();
    e.Graphics.DrawString(font.Name, font, Brushes.Black, e.Bounds.X, e.Bounds.Y);
}

сейчас я внес только одно изменение в этот код, и вот оно:

cmbFonts.DrawMode = DrawMode.OwnerDrawFixed;

нет проблем с загрузкой шрифтов и он работает, но я пытаюсь установить выбранное значение при загрузке формы. Например, я пытаюсь установить шрифт с именем «arial». Для этого я использую это:

var dataSource = cmbFonts.DataSource as List<FontFamily>;
int res = -1;
try
{
  res = dataSource.IndexOf(new FontFamily(StaticVariables.FontName));
}
catch { }
if (res != -1)
  cmbFonts.SelectedIndex = res;

теперь, когда я это делаю, я получаю System.ArgumentOutOfRangeException ошибку, потому что я не добавил никаких элементов в Combobox, я привязываю DataSource, поэтому, когда я пытаюсь чтобы установить SelectedIndex, я получаю эту ошибку, и я знаю, что я также пробовал это:

cmbFonts.SelectedValue = StaticVariables.FontName;

, но когда я запускаю свой код с точками останова в Visual Studio, я вижу, что мой SelectedValue никогда не меняется. Перед выполнением строки я вижу null, а после выполнения я все еще вижу null в SelectedValue, я проверил свою переменную StaticVariables.FontName, и шрифт представлен там.

Я также пытался использовать combobox.Text, но не повезло, это похоже на SelectedValue, это была пустая строка раньше и все та же после того, как я пропускаю ее с помощью точки останова.

TL; DR: Я пытаюсь выбрать элемент при загрузке формы в поле со списком, которое я заполнено DataSource

1 Ответ

0 голосов
/ 29 мая 2020

Вот пользовательский класс 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 и Межстрочный интервал .
Некоторые подробности того, как использовать эти функции, описаны здесь:

Правильное рисование текста с помощью пути к графике
Шрифты и текст метрики

Вот как это работает:

Custom ComboBox Font Selector


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();
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...