2010-01-20 2 views
1

Я создаю пользовательский combobox, который может рисовать разделители. Поэтому я переопределяю методы OnDrawItem() и OnMeasureItem().
Проблема заключается в том, что OnMeasureItem() вызывается только один раз при изменении источника данных. Поэтому, если я хочу указать элемент разделителя позже, мне нужно изменить его высоту (поскольку элементы с разделителем должны быть выше), но кажется, что все методы, которые могут привести к переоценке высоты элемента, являются частными, поэтому я не могу их назвать ,
Я не знаю, легко ли понять, что я написал выше, поэтому я буду повторять то, что мне нужно:
Мне нужно переоценить высоту элемента (нужно вызывать OnMeasureItem() каждый раз, когда я указываю, что элемент должен быть нарисован с помощью разделителя.Как сделать высоту позиции переименования combobox?

separatorableComboBox.DataSource = customers; 
// and now I want the third customer in the list to be drawn with a separator, 
// so it needs to be taller and therefore OnMeasureItem() should be called 
separatorableComboBox.SpecifySeparatorItem(customers[2]); 

UPD. Ребята, вызывая RefreshItems() работает, но это очень медленно (> 20 мс на моей машине), есть ли более быстрые методы?
UPD2. Прямо сейчас я использую SendMessage (..., CB_SETITEMHEIGHT, ...); метод, рекомендованный serge_gubenko. Но мне просто интересно, есть ли быстрый способ выполнить задачу с .NET (или, более конкретно, с самим классом ComboBox)?

ответ

3

Чтобы уточнить, я предполагаю, что вы используете стиль OwnerDrawVariable для своей комбинации. Если я правильно понял ваш вопрос, есть несколько способов, чтобы сделать то, что вам нужно:

  • Вызов RefreshItems метода из выпадающего списка, который будет воссоздать элементы и вызвать onMeasureItem события для каждого элемента. Этот метод защищен для ComboBox класса, поэтому ниже приводится пример того, как вы могли бы сделать это с помощью отражения:
MethodInfo method = comboBox1.GetType().GetMethod(
     "RefreshItems", BindingFlags.Instance | BindingFlags.NonPublic); 
    if (method != null) method.Invoke(comboBox1, null); 
  • Послать CB_SETITEMHEIGHT сообщение для управления с новой высоты элемента всякий раз, когда вам хотим изменить его:
public const int CB_SETITEMHEIGHT = 0x0153; 
    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam); 
    ... 
    // this will set height to 100 for the item with index 2 
    SendMessage(comboBox1.Handle, CB_SETITEMHEIGHT, 2, 100); 

Надеется, что это помогает, считает

+0

Отправка сообщения работает быстро, но мне просто интересно, есть ли более правильный и быстрый способ выполнить задачу с управляемым кодом (более конкретно, возможно, с классом ComboBox)? – nightcoder

+0

Я бы не стал слишком беспокоиться об этом при использовании winforms, в конце концов все еще есть элемент управления COMBOBOX Windows (http://msdn.microsoft.com/en-us/library/bb775792(VS.85).aspx), работающий на ваша форма; вы можете проверить его со шпионом ++. Класс ComboBox делает то же самое при настройке высоты элемента в методе UpdateItemHeight(), который является приватным, поэтому вам нужно использовать отражение, чтобы вызвать его. Что касается RefreshItems, он полностью перезагружает список элементов. В принципе, он должен быть таким же, чтобы установить значение null в его свойство DataSource, а затем восстановить его обратно до предыдущего значения –

4

Вы можете позвонить ComboBox.RefreshItems() для того, чтобы поднять MeasureItem() звонки, либо внутри SpecifySeparatorItem() вашего класса CustomCombo:

public void SpecifySeparatorItem(object arg) 
{ 
    //do some stuff 

    this.RefreshItems(); 

    //do some more stuff 
} 

Или подвергая ComboBox.RefreshItems() через общедоступный метод, который можно вызвать в другом месте

public partial class CustomCombo : ComboBox 
{ 
    public CustomCombo() 
    { 
     InitializeComponent(); 
    } 

    protected override void OnMeasureItem(MeasureItemEventArgs e) 
    { 
     base.OnMeasureItem(e); 
    } 

    public void RaiseOnMeasureItem() 
    { 
     this.RefreshItems(); 
    } 
} 
+0

Ребят, позвонив RefreshItems() работает, но он очень медленный (> 20 мс на моей машине), есть ли более быстрые методы? – nightcoder

Смежные вопросы