2010-01-20 5 views
1

Je crée une liste déroulante personnalisée qui peut dessiner des séparateurs. Donc, je substitue les méthodes OnDrawItem() et OnMeasureItem().
Le problème est que OnMeasureItem() n'est appelé qu'une seule fois lorsque la source de données est modifiée. Donc, si je veux spécifier un élément séparateur plus tard, je dois réévaluer sa hauteur (parce que les éléments avec séparateur devraient être plus grands), mais il semble que toutes les méthodes qui permettent de réestimer la hauteur des objets sont privées, donc je ne peux pas les appeler .
Je ne sais pas s'il est facile de comprendre ce que j'ai écrit ci-dessus, donc je vais répéter ce dont j'ai besoin:
Je dois réestimer la hauteur de l'objet (OnMeasureItem() doit être appelé) chaque fois que je spécifie que l'article doit être dessiné avec un séparateur.Comment faire de la hauteur de l'objet remobilisé 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. Les gars, appelant RefreshItems() fonctionne, mais il est très lent (> 20 ms sur ma machine), y at-il des méthodes plus rapides?
UPD2. En ce moment j'utilise SendMessage (..., CB_SETITEMHEIGHT, ...); méthode comme serge_gubenko conseillé. Mais je suis juste curieux de savoir s'il existe un moyen rapide d'accomplir la tâche avec .NET (ou plus spécifiquement avec la classe ComboBox elle-même)?

Répondre

3

Juste pour clarifier, je suppose que vous utilisez le style OwnerDrawVariable pour votre combobox. Si je comprends bien votre question, il y a deux façons de faire ce que vous avez besoin:

  • Appel de méthode RefreshItems du combobox qui recréer des éléments et de déclencher l'événement onMeasureItem pour chaque élément. Cette méthode est protégée pour la classe ComboBox, donc ci-dessous est un exemple sur la façon dont vous pouvez le faire en utilisant la réflexion:
MethodInfo method = comboBox1.GetType().GetMethod(
     "RefreshItems", BindingFlags.Instance | BindingFlags.NonPublic); 
    if (method != null) method.Invoke(comboBox1, null); 
  • Envoyer le message CB_SETITEMHEIGHT au contrôle avec la nouvelle hauteur de l'élément chaque fois que vous veulent changer:
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); 

Hope this helps, considère

+0

Envoyer un message fonctionne rapidement, mais je suis juste curieux de savoir s'il existe une façon plus correcte et rapide d'accomplir la tâche avec du code managé (plus précisément peut-être avec la classe ComboBox)? – nightcoder

+0

Je ne m'inquiéterais pas trop à ce sujet lors de l'utilisation de winforms, finalement il reste un contrôle de COMBOBOX de Windows (http://msdn.microsoft.com/en-us/library/bb775792(VS.85).aspx) fonctionnant sur votre formulaire; vous pouvez le vérifier avec spy ++. La classe ComboBox fait de même lors de l'ajustement de la hauteur de l'élément dans sa méthode UpdateItemHeight(), qui est privée, donc vous devez utiliser la réflexion pour l'appeler. Quant à RefreshItems, il recharge complètement la liste des éléments. Fondamentalement, il devrait être le même pour définir null à sa propriété DataSource, puis le restaurer à la valeur précédente –

4

Vous pouvez appeler ComboBox.RefreshItems() afin d'augmenter MeasureItem() appels, soit à l'intérieur de votre SpecifySeparatorItem() de votre classe CustomCombo:

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

    this.RefreshItems(); 

    //do some more stuff 
} 

Ou en exposant ComboBox.RefreshItems() par une méthode publique que vous pouvez appeler ailleurs

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

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

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

Les gars, appeler RefreshItems() fonctionne, mais il est très lent (> 20 ms sur ma machine), y at-il des méthodes plus rapides? – nightcoder

Questions connexes