web-dev-qa-db-fra.com

ListView AutoResizeColumns basé sur le contenu et l'en-tête de la colonne

nous utilisons ces deux méthodes pour ajuster la longueur de la colonne en fonction du contenu et de l'en-tête de colonne, respectivement.

ListView.AutoResizeColumns (ColumnHeaderAutoResizeStyle.ColumnContent); ListView.AutoResizeColumns (ColumnHeaderAutoResizeStyle.HeaderSize);

Mais comment ajuster en fonction des deux? c'est-à-dire ajuster à la plus grande longueur pour le contenu de l'en-tête et de la colonne. 

17
william007

lvw.Columns[0].Width = -2

Voir les remarques dans MSDN pour plus de détails: http://msdn.Microsoft.com/en-us/library/system.windows.forms.columnheader.width.aspx

Notez également que MSDN indique que 'Pour réduire automatiquement la largeur de l'en-tête de colonne, définissez la propriété Width sur -2.', Mais que cela fonctionne pour le contenu de l'en-tête de colonne ET de la colonne.

Voici un code pour prouver que:

    lvw.Columns.Add(new String('x', 25));   // short header
    lvw.Items.Add(new String('x', 100));    // long content

    lvw.Columns[0].Width = -2;
    // in result column width will be set to fit content
28
Anton Kedrov

Comme répondu ici , l'appel des deux options de redimensionnement remplit les fonctions suivantes:

myListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
myListView.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
18
Tanguy

C'est ce que j'utilise pour ajuster la largeur de la colonne au contenu et à l'en-tête:

public static void autoResizeColumns(ListView lv)
{
    lv.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
    ListView.ColumnHeaderCollection cc = lv.Columns;
    for (int i = 0; i < cc.Count; i++)
    {
        int colWidth = TextRenderer.MeasureText(cc[i].Text, lv.Font).Width + 10;
        if (colWidth > cc[i].Width)
        {
            cc[i].Width = colWidth;
        }
    }
}

Exemple d'utilisation:

autoResizeColumns(listView1);

La méthode n’est pas bien testée, mais au moins elle fonctionne dans le contexte dans lequel je l’utilise.

3
matsolof

Il est en effet possible d'utiliser MeasureText, puis de calculer l'espace disponible et de le répartir d'une manière ou d'une autre entre toutes les colonnes. Mais c'est une approche rapide et sale que j'ai rapidement codée:

    /// <summary>
    /// Enables autoresizing for specific listview.
    /// You can specify how much to scale in columnScaleNumbers array - length of that array
    /// should match column count which you have.
    /// </summary>
    /// <param name="listView">control for which to enable auto-resize</param>
    /// <param name="columnScaleNumbers">Percentage or numbers how much each column will be scaled.</param>
    private void EnableAutoresize(ListView listView, params int[] columnScaleNumbers)
    {
        listView.View = View.Details;
        for( int i = 0; i < columnScaleNumbers.Length; i++ )
        {
            if( i >= listView.Columns.Count )
                break;
            listView.Columns[i].Tag = columnScaleNumbers[i];
        }

        listView.SizeChanged += lvw_SizeChanged;
        DoResize(listView);
    }

    void lvw_SizeChanged(object sender, EventArgs e)
    {
        ListView listView = sender as ListView;
        DoResize(listView);
    }

    bool Resizing = false;
    void DoResize( ListView listView )
    {
        // Don't allow overlapping of SizeChanged calls
        if (!Resizing)
        {
            // Set the resizing flag
            Resizing = true;

            if (listView != null)
            {
                float totalColumnWidth = 0;

                // Get the sum of all column tags
                for (int i = 0; i < listView.Columns.Count; i++)
                    totalColumnWidth += Convert.ToInt32(listView.Columns[i].Tag);

                // Calculate the percentage of space each column should 
                // occupy in reference to the other columns and then set the 
                // width of the column to that percentage of the visible space.
                for (int i = 0; i < listView.Columns.Count; i++)
                {
                    float colPercentage = (Convert.ToInt32(listView.Columns[i].Tag) / totalColumnWidth);
                    listView.Columns[i].Width = (int)(colPercentage * listView.ClientRectangle.Width);
                }
            }
        }

        // Clear the resizing flag
        Resizing = false;            
    }

Et en fonction du nombre de colonnes que vous avez - vous spécifiez chaque colonne "pourcentage" ou simplement nombre. Par exemple, pour 3 colonnes, l'appel ressemble à ceci:

        EnableAutoresize(listView1, 6, 3, 1);

Cela distribuera les tailles de colonne de la manière suivante:.

Ceci est en quelque sorte le pauvre homme rapide mise en œuvre. :-)

1
TarmoPikaro

Voici une solution C # qui peut être utilisée pour tout ListView. Cela suppose que le nombre de colonnes et les en-têtes ne changeront pas pour une vue de liste donnée. Supprimez le dictionnaire listViewHeaderWidths si vous souhaitez recalculer à chaque fois la largeur des en-têtes (si les en-têtes changent ou le nombre de colonnes change).

    private Dictionary<string, int[]> listViewHeaderWidths = new Dictionary<string, int[]>();    
    private void ResizeListViewColumns(ListView lv)
    {
        int[] headerWidths = listViewHeaderWidths.ContainsKey(lv.Name) ? listViewHeaderWidths[lv.Name] : null;

        lv.BeginUpdate();

        if (headerWidths == null)
        {
            lv.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);

            headerWidths = new int[lv.Columns.Count];

            for (int i = 0; i < lv.Columns.Count; i++)
            {
                headerWidths[i] = lv.Columns[i].Width;
            }

            listViewHeaderWidths.Add(lv.Name, headerWidths);
        }

        lv.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);

        for(int j = 0; j < lv.Columns.Count; j++)
        {
            lv.Columns[j].Width = Math.Max(lv.Columns[j].Width, headerWidths[j]);
        }

        lv.EndUpdate();
    }
0
GreggD

Dans mon cas, je le fais en suivant les étapes suivantes (pour deux colonnes de données):

  1. Création d'un objet ColumnHeader pour chaque colonne.
  2. Définition de la taille par redimensionnement automatique en fonction de HeaderSize (sur les deux colonnes)
  3. Stocker cette valeur dans une variable Integer
  4. Définition de la taille par redimensionnement automatique en fonction de ColumnContent (sur les deux colonnes)
  5. Mise à jour de la valeur de chaque variable entière via les critères Max entre l'ancienne valeur et la nouvelle valeur (pour chaque colonne).
  6. Définition de la taille de la largeur de colonne pour chaque objet ColumnHeader.

En VB.NET:

'Create two header objects as ColumnHeader Class
Dim header1, header2 As ColumnHeader

'Construcción de los objetos header
header1 = New ColumnHeader
header1.Text = "ID"
header1.TextAlign = HorizontalAlignment.Right
header1.Width = 10

header2 = New ColumnHeader
header2.Text = "Combinaciones a Procesar"
header2.TextAlign = HorizontalAlignment.Left
header2.Width = 10

'Add two columns using your news headers objects 
ListView.Columns.Add(header1)
ListView.Columns.Add(header2)

'Fill three rows of data, for each column
ListView.Items.Add(New ListViewItem({"A1", "B1"}))
ListView.Items.Add(New ListViewItem({"A2", "B2"}))
ListView.Items.Add(New ListViewItem({"A3", "B3"}))

'Change the size of each column
Dim headsz1, headsz2 As Integer
SelectionInTable.ListView.AutoResizeColumn(0,             ColumnHeaderAutoResizeStyle.HeaderSize)
SelectionInTable.ListView.AutoResizeColumn(1, ColumnHeaderAutoResizeStyle.HeaderSize)
headsz1 = header1.Width
headsz2 = header2.Width
SelectionInTable.ListView.AutoResizeColumn(0, ColumnHeaderAutoResizeStyle.ColumnContent)
SelectionInTable.ListView.AutoResizeColumn(1,     ColumnHeaderAutoResizeStyle.ColumnContent)
headsz1 = Math.Max(headsz1, header1.Width)
headsz2 = Math.Max(headsz2, header2.Width)
header1.Width = headsz1
header2.Width = headsz2
0
Asrhael

C'est simple (même s'il m'a fallu un certain temps pour comprendre) ...

Nous savons que la largeur doit être au moins égale à celle des en-têtes de colonne, de sorte que tout le texte de l'en-tête soit visible. Au-delà, la largeur peut s’étendre plus grande pour accueillir le contenu. Par conséquent, nous faisons ce qui suit:

  1. Autosize les colonnes à en-tête. 
  2. Parcourez les colonnes et définissez la propriété width minimum de chaque colonne sur la largeur actuelle de la colonne (ce qui garantit que vos colonnes ne seront jamais trop petites pour voir l'en-tête).
  3. A partir de maintenant, redimensionnez automatiquement les colonnes par contenu.

Il n'est pas nécessaire de suivre les largeurs séparément et de les réinitialiser comme le suggèrent d'autres affiches. La définition de la largeur minimale de la colonne résout le problème jusqu'à ce que le texte de l'en-tête soit modifié. Dans ce cas, définissez la largeur minimale sur 0, redimensionnez automatiquement la colonne modifiée, puis redéfinissez la largeur minimale sur la largeur actuelle.

EDIT: Mes excuses, j'ai oublié que je n'utilisais pas la liste standard, mais le produit tiers BetterListView (une version gratuite est disponible). Les colonnes listview standard ne semblent pas prendre en charge la largeur minimale. Je recommande vivement BetterListView comme une excellente alternative (ensemble de fonctionnalités et de performances bien meilleures).

0
Ben W.

La réponse d'Anton Kedrov est la meilleure, mais dans mon cas, j'ai une liste de vues avec plus de 50 colonnes et je mets fréquemment à jour ses données.

Première méthode en paramétrant avec à -2

public void AutoUpdateColumnWidth(ListView lv)
{
    for (int i = 0; i <= lv.Columns.Count - 1; i++) {
        lv.Columns(i).Width = -2;
    }
}

Deuxième méthode que j'ai utilisée (moins de scintillement lors d'appels multiples)

public void AutoUpdateColumnWidth(ListView lv)
{
    ListViewItem nLstItem = new ListViewItem(lv.Columns(0).Text);
    for (int i = 1; i <= lv.Columns.Count - 1; i++) {
        nLstItem.SubItems.Add(lv.Columns(i).Text);
    }
    v.Items.Add(nLstItem);
    lv.AutoResizeColumns(ColumnHeaderAutoResizeStyle.ColumnContent);
    lv.Items.RemoveAt(nLstItem.Index);
}
0
Jack Gajanan