2010-01-20 56 views
1

我正在创建一个可以绘制分隔符的自定义组合框。所以,我重写OnDrawItem()和OnMeasureItem()方法。
问题是OnMeasureItem()仅在数据源更改时被调用一次。因此,如果我想稍后指定分隔项目,我需要重新测量它的高度(因为带分隔符的项目应该更高),但似乎所有可能导致项目高度被重新测量的方法都是私有的,所以我不能称它们为。
我不知道是否很容易理解我上面写的东西,所以我会重复我需要的东西:
每次我需要重新测量项目高度(必须调用OnMeasureItem())时,我指定项目应该用分隔符绘制。如何使组合框重新测量项目高度?

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 2010-01-20 22:14:48

+0

使用winforms时,我不会担心它太多,最终还是会有一个windows COMBOBOX控件(http://msdn.microsoft.com/en-us/library/bb775792(VS.85).aspx)运行你的形式;你可以用spy ++来检查它。 ComboBox类在其UpdateItemHeight()方法中调整项目高度时使用相同的方法,该方法是私有的,因此您需要使用反射来调用它。至于RefreshItems,它完全重新加载项目列表。基本上它应该是相同的,将null设置为其DataSource属性,然后将其恢复为以前的值 – 2010-01-21 01:18:52

4

您可以拨打ComboBox.RefreshItems()以提高MeasureItem()电话,要么你对你的CustomCombo类SpecifySeparatorItem()内:

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 2010-01-20 21:45:48