web-dev-qa-db-fra.com

Autoriser multi-sélectionner dans un arborescence .net

Je suis bloqué dans les formulaires Windows .NET 2.0.

Il ne semble pas que la possibilité de sélectionner plusieurs nœuds existe dans le contrôle standard TreeView.

J'essaie de le faire pour une sélection de menu contextuel. Ainsi, les cases à cocher ne sont pas un paradigme UI acceptable ici.

Quelle est la meilleure façon de fournir cette fonctionnalité très nécessaire?

22
Darcy Casselman

Nous l'avons fait dans un projet WTL une fois, mais le travail de base nécessaire est le même pour .NET. Pour obtenir un contrôle d'arborescence de sélection multiple, vous devrez dessiner vous-même les objets d'arborescence et remplacer la manipulation du clavier et de la souris. Vous devrez également conserver votre propre liste d'éléments sélectionnés.

N'oubliez pas d'envisager des règles de sélection (les parents et les enfants et les enfants sont-ils autorisés, par exemple), et n'oubliez pas de mettre en œuvre les raccourcis clavier, y compris la sélection à l'aide de Ctrl, de décalage et de Ctrl + Shift, ainsi que la barre d'espace pour la sélection/la désélectionner .

10
Jeff Yates
7
user1228

Sont des cases à cocher une option? OU VOULEZ-VOUS THE SELECT QUE VOUS INSTRUCTEZ UNE BOITE DE LISTE?

  • les cases à cocher sont construites dans
  • sélectionnez comme si vous entrez dans une liste de liste nécessite un contrôle d'arbre personnalisé

Il existe un contrôle d'arborescence multi-sélection disponible sur CODEPROJECTION: Vue d'arborescence multi-sélection

5
Jay Mooney

Le code ci-dessous vous permettra de régler la couleur d'arrière-plan que vous utilisez pour vous assurer que tous les nœuds sélectionnés sont mis en surbrillance.

protected override void WndProc(ref Message m)
{
    switch (m.Msg) {
        // WM_REFLECT is added because WM_NOTIFY is normally sent just
        // to the parent window, but Windows.Form will reflect it back
        // to us, MFC-style.
        case Win32.WM_REFLECT + Win32.WM_NOTIFY: {
            Win32.NMHDR nmhdr = (Win32.NMHDR)m.GetLParam(typeof(Win32.NMHDR));
            switch((int)nmhdr.code) {
                case Win32.NM_CUSTOMDRAW:
                    base.WndProc(ref m);
                    Win32.NMTVCUSTOMDRAW nmTvDraw = (Win32.NMTVCUSTOMDRAW)m.GetLParam(typeof(Win32.NMTVCUSTOMDRAW));
                    switch (nmTvDraw.nmcd.dwDrawStage) {
                        case Win32.CDDS_ITEMPREPAINT:
                            // Find the node being painted.
                            TreeNode n = TreeNode.FromHandle(this, nmTvDraw.nmcd.lItemlParam);
                            if (allSelected.Contains(n))
                                // Override its background colour.
                                nmTvDraw.clrTextBk = ColorTranslator.ToWin32(SystemColors.Highlight);
                            m.Result = (IntPtr)Win32.CDRF_DODEFAULT;  // Continue rest of painting as normal
                            break;
                    }
                    Marshal.StructureToPtr(nmTvDraw, m.LParam, false);  // copy changes back
                    return;
            }
            break;
        }
    }
    base.WndProc(ref m);
}

// WM_NOTIFY notification message header.
[System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
public class NMHDR
{
    private IntPtr hwndFrom;
    public IntPtr idFrom;
    public uint code;
}

[StructLayout(LayoutKind.Sequential)]
public struct NMCUSTOMDRAW
{
    public NMHDR hdr;
    public int dwDrawStage;
    public IntPtr hdc;
    public RECT rc;
    public IntPtr dwItemSpec;
    public int uItemState;
    public IntPtr lItemlParam;
}

[StructLayout(LayoutKind.Sequential)]
public struct NMTVCUSTOMDRAW
{
    public NMCUSTOMDRAW nmcd;
    public int clrText;
    public int clrTextBk;
    public int iLevel;
}

public const int CDIS_SELECTED = 0x0001;
public const int CDIS_FOCUS = 0x0010;
public const int CDDS_PREPAINT = 0x00000001;
public const int CDDS_POSTPAINT = 0x00000002;
public const int CDDS_PREERASE = 0x00000003;
public const int CDDS_POSTERASE = 0x00000004;
public const int CDDS_ITEM = 0x00010000;  // item specific 
public const int CDDS_ITEMPREPAINT = (CDDS_ITEM | CDDS_PREPAINT);
public const int CDDS_ITEMPOSTPAINT = (CDDS_ITEM | CDDS_POSTPAINT);
public const int CDDS_ITEMPREERASE = (CDDS_ITEM | CDDS_PREERASE);
public const int CDDS_ITEMPOSTERASE = (CDDS_ITEM | CDDS_POSTERASE);
public const int CDDS_SUBITEM = 0x00020000;
public const int CDRF_DODEFAULT = 0x00000000;
public const int CDRF_NOTIFYITEMDRAW = 0x00000020;
public const int CDRF_NOTIFYSUBITEMDRAW = 0x00000020;  // flags are the same, we can distinguish by context

public const int WM_USER = 0x0400;
public const int WM_NOTIFY = 0x4E;
public const int WM_REFLECT = WM_USER + 0x1C00;
4
Oliver Bock

Vous pourriez regarder une solution tierce. L'arbre Infragistics cela. Pas gratuit, mais le temps passé à essayer de trouver une solution n'est pas vraiment gratuit, non plus.

4
Jon B

La solution la plus simple consisterait à étendre le contrôle existant de l'arborescence expédié avec le cadre et remplacer les méthodes ONBEFORFORESELLECT et ONAFterSélectionnez avec la logique pour capturer plusieurs sélections.

Un exemple peut être trouvé ici: http://www.arstdesign.com/articles/treeviewnms.html

3
timpeck