Что заставляет ComboBox показывать `System.Data.DataRowView` - PullRequest
0 голосов
/ 09 октября 2019

ОК, так что это немного странно.

У меня довольно просто DataTable:

DataTable dt = new DataTable();
dt.Columns.Add("Display", typeof(string));
dt.Columns.Add("Value", typeof(string));
dt.Rows.Add("Equals", "==");
dt.Rows.Add("Is Less Than", "<");
dt.Rows.Add("Is Less Than Or Equal To", "<=");
dt.Rows.Add("Is Greater Than", ">");
dt.Rows.Add("Is Greater Than Or Equal To", ">=");

Теперь, если я прикреплю это DataTable к совершенно новомуComboBox, все работает как надо.

 comboBox1.DataSource = dt;
 comboBox1.ValueMember = "Value";
 comboBox1.DisplayMember = "Display";

Этот элемент управления отображает Equals, Is Less Than и т. Д.

В моей форме, однако, у меня есть еще один ComboBoxэто динамически создается, учитывая динамическое имя, основанное на том, в какой строке в TableLayoutPanel он находится, и т. д. Когда я использую для него точно такой же код , он отображает System.Data.DataRowView для каждого выпадающего списка:

Screenshot

Итак, вместо того, чтобы я проходил каждую строчку кода одну за другой и пытался реинжиниринг этого, может кто-нибудь сказать мне, чтоможет ли это произойти? Есть ли какой-нибудь предсказуемый и повторяемый способ вызвать такое поведение? Я попробовал все следующее, чтобы перевернуть , но ничего не работает:

dtecComboAction.DataSource = null;
dtecComboAction.DataBindings.Clear();
dtecComboAction.Items.Clear();
dtecComboAction.BindingContext = this.BindingContext;

Я уверен, что делаю что-то очевидное где-то еще в моем коде, но я не могуразберись.

Спасибо!

1 Ответ

1 голос
/ 09 октября 2019

Неожиданное поведение, описанное в вопросе, определяется пользовательским чертежом ComboBox OwnerDrawn (пользовательский элемент управления, производный от ComboBox).

Когда DataSource ListControl является сложным объектом - как в этом случае, DataTable.DefaultView ( DataView ) - каждый элемент в списке являетсяСам сложный объект, DataRowView здесь.

По этой причине при рисовании элементов ListControl OwnerDrawn (переопределяя метод OnDrawItem) текст элемента, отображаемый в видимой области элемента управления, должен извлекаться с использованием GetItemText из ListControl. ) метод.

Этот метод извлекает текст элемента (используя внутренний Datamanager, если определен источник данных, или TypeDescriptor, если нет), независимо от типа элемента:

ЕслиСвойство DisplayMember не указано, значение, возвращаемое GetItemText (Object), является значением метода ToString элемента. В противном случае метод возвращает строковое значение члена, указанного в свойстве DisplayMember для объекта, указанного в параметре элемента.

.Net Исходный код ListControl.GetItemText ()

Классическая ошибка при рисовании текста Предмета для преобразования в строку объекта Предмета:
Это может работать, если текст Предмета является простой строкой, а не если это сложный объект. В этом случае [ComplexObject].ToString() возвращает тип данных объекта (System.Data.DataRowView, в данном случае).

protected override void OnDrawItem(DrawItemEventArgs e)
{
    // (...)
    e.DrawBackground();
    using (var brush = new SolidBrush(this.ForeColor)) {
        e.Graphics.DrawString(this.Items[e.Index].ToString()), this.Font, brush, e.Bounds);
    }
    // (...)
}

Упрощенный пример кода, не использовать:)

При использовании GetItemText() возвращается значение свойства DisplayMemberкак строкаНачиная с comboBox1.DisplayMember = "Display";, он будет возвращать содержимое столбца DataTable Display.

protected override void OnDrawItem(DrawItemEventArgs e)
{
    // (...)
    e.DrawBackground();
    using (var brush = new SolidBrush(this.ForeColor)) {
        e.Graphics.DrawString(this.GetItemText(this.Items[e.Index]), this.Font, brush, e.Bounds);
    }
    // (...)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...