2011-12-02 5 views
1

J'essaie d'implémenter un ListView dessiné par le propriétaire car le contrôle de base mange le caractère de tabulation dont j'ai besoin pour aligner des valeurs dans une colonne. En utilisant un exemple de MSDN comme base, j'ai pu me rapprocher. Le seul problème que j'ai toujours est que les périodes d'ellipse utilisées quand le texte ne rentre pas dans la colonne sont beaucoup plus rapprochées que dans le rendu de texte par défaut; le point que si la police est en gras, les périodes s'enchaînent en un trait de soulignement.Listview Problèmes de rendu de texte en mode ownerdraw

Le programme ci-dessous illustre le problème. Il a 4 ListViews: Les deux sur le dessus sont dessinés en utilisant le rendu par défaut. Les deux sur le fond sont ownerdrawn, et la paire dans le côté droit sont en gras. Pour des raisons de longueur, j'ai supprimé tout ce dont je n'avais pas besoin pour démontrer le problème. C'est pourquoi les ListViews ownerdawn n'ont pas d'en-têtes de colonnes.

En regardant une capture d'écran zoomée, les périodes des points de suspension dans les ListView dessinés par le propriétaire sont espacées d'un pixel; ceux du dessin par défaut ont deux pixels d'espacement. Lorsque la fonction Bolding élargit les points à deux pixels, les objets dessinés par le propriétaire fusionnent en une masse solide qui ressemble à un trait de soulignement.

Il existe également d'autres différences mineures dans le rendu du texte; mais l'ellipse est la seule qui soit facilement apparente sans zoomer. Ces différences me font cependant suspecter que le problème est un problème plus général. Peut-être rendu GDI vs GDI +? Sauf que je pensais que cela ne pouvait varier au niveau de l'application. Apparemment non, basculer Application.SetCompatibleTextRenderingDefault() n'affectait rien.

using System; 
using System.Drawing; 
using System.Windows.Forms; 

namespace WindowsFormsApplication1 
{ 
    public class Form1 : Form 
    { 
     private void ListViewDrawSubItem(object sender, DrawListViewSubItemEventArgs e) 
     { 
      ListView listView = sender as ListView; 
      using (StringFormat sf = new StringFormat()) 
      { 
       // Draw the standard background. 
       e.DrawBackground(); 
       sf.SetTabStops(0, new float[] {12, 12, 12, 12, 12}); 
       sf.FormatFlags = sf.FormatFlags | StringFormatFlags.NoWrap; 
       sf.Trimming = StringTrimming.EllipsisCharacter; 

       // Draw the header text. 
       // passing the controls font directly causes an ArguementException); 
       using (Font headerFont = new Font(listView.Font.Name, listView.Font.Size, listView.Font.Style)) 
       { 
        e.Graphics.DrawString(e.SubItem.Text, headerFont, Brushes.Black, e.Bounds, sf); 
       } 
      } 
     } 

     public Form1() 
     { 
      InitializeComponent(); 
      LoadData(listView1); 
      LoadData(listView2); 
      LoadData(listView3); 
      LoadData(listView4); 
     } 

     private void LoadData(ListView listView) 
     { 
      listView.Columns.Add("first", 35); 
      listView.Columns.Add("second", 75); 

      for (int i = 0; i < 5; i++) 
      { 
       listView.Items.Add("test"); 
       listView.Items[i].SubItems.Add("test test test test"); 
      } 
     } 

     #region from Form1.Designer 
     /// <summary> 
     /// Required designer variable. 
     /// </summary> 
     private System.ComponentModel.IContainer components = null; 

     /// <summary> 
     /// Clean up any resources being used. 
     /// </summary> 
     /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 
     protected override void Dispose(bool disposing) 
     { 
      if (disposing && (components != null)) 
      { 
       components.Dispose(); 
      } 
      base.Dispose(disposing); 
     } 

     #region Windows Form Designer generated code 

     /// <summary> 
     /// Required method for Designer support - do not modify 
     /// the contents of this method with the code editor. 
     /// </summary> 
     private void InitializeComponent() 
     { 
      this.listView1 = new System.Windows.Forms.ListView(); 
      this.listView2 = new System.Windows.Forms.ListView(); 
      this.listView3 = new System.Windows.Forms.ListView(); 
      this.listView4 = new System.Windows.Forms.ListView(); 
      this.SuspendLayout(); 
      // 
      // listView1 
      // 
      this.listView1.Location = new System.Drawing.Point(12, 12); 
      this.listView1.Name = "listView1"; 
      this.listView1.Size = new System.Drawing.Size(121, 116); 
      this.listView1.TabIndex = 0; 
      this.listView1.UseCompatibleStateImageBehavior = false; 
      this.listView1.View = System.Windows.Forms.View.Details; 
      // 
      // listView2 
      // 
      this.listView2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 
      this.listView2.Location = new System.Drawing.Point(151, 12); 
      this.listView2.Name = "listView2"; 
      this.listView2.Size = new System.Drawing.Size(121, 116); 
      this.listView2.TabIndex = 1; 
      this.listView2.UseCompatibleStateImageBehavior = false; 
      this.listView2.View = System.Windows.Forms.View.Details; 
      // 
      // listView3 
      // 
      this.listView3.Location = new System.Drawing.Point(12, 134); 
      this.listView3.Name = "listView3"; 
      this.listView3.OwnerDraw = true; 
      this.listView3.Size = new System.Drawing.Size(121, 116); 
      this.listView3.TabIndex = 2; 
      this.listView3.UseCompatibleStateImageBehavior = false; 
      this.listView3.View = System.Windows.Forms.View.Details; 
      this.listView3.DrawSubItem += new System.Windows.Forms.DrawListViewSubItemEventHandler(this.ListViewDrawSubItem); 
      // 
      // listView4 
      // 
      this.listView4.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 
      this.listView4.Location = new System.Drawing.Point(151, 134); 
      this.listView4.Name = "listView4"; 
      this.listView4.OwnerDraw = true; 
      this.listView4.Size = new System.Drawing.Size(121, 116); 
      this.listView4.TabIndex = 3; 
      this.listView4.UseCompatibleStateImageBehavior = false; 
      this.listView4.View = System.Windows.Forms.View.Details; 
      this.listView4.DrawSubItem += new System.Windows.Forms.DrawListViewSubItemEventHandler(this.ListViewDrawSubItem); 
      // 
      // Form1 
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
      this.ClientSize = new System.Drawing.Size(284, 262); 
      this.Controls.Add(this.listView4); 
      this.Controls.Add(this.listView3); 
      this.Controls.Add(this.listView2); 
      this.Controls.Add(this.listView1); 
      this.Name = "Form1"; 
      this.Text = "Form1"; 
      this.ResumeLayout(false); 

     } 

     #endregion 

     private System.Windows.Forms.ListView listView1; 
     private System.Windows.Forms.ListView listView2; 
     private System.Windows.Forms.ListView listView3; 
     private System.Windows.Forms.ListView listView4; 
     #endregion 

     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Application.Run(new Form1()); 
     } 
    } 
} 
+0

Vous devez aligner des valeurs dans une colonne? Avez-vous envisagé d'ajouter une colonne? –

+0

@HansPassant J'ai. J'affiche des données de famille; une rangée/famille. Le nombre d'enfants est arbitraire; dans la plupart des cas, il y en a peu, mais il y en a quelques-uns avec beaucoup de données dans l'ensemble de données. Il y a un désir d'éviter d'avoir un grand nombre de colonnes et la barre de défilement horizontale résultante pour quelque chose qui n'est nécessaire que pour quelques pourcents des rangées. Étant donné que l'info-bulle par défaut d'une cellule qui doit être rétrécie pour éviter d'être tronquée est le texte intégral de la cellule, elle donne un autre moyen de voir toutes les valeurs aberrantes sans défilement. Cela semblait être un compromis raisonnable à l'époque. Kid 1 ... Kid N colonnes sont l'option de secours. –

Répondre

6

J'ai trouvé une implémentation conditionnelle pour la méthode de sous-élément draw. Les principales mises en garde que j'ai sont que la taille de l'onglet est fixe (bien que je pourrais laisser tomber à win32 si nécessaire pour le changer); et que la combinaison de drapeaux dont j'ai besoin tout en travaillant sur ma machine est mutuellement incompatible dans MSDN.

private void ListViewDrawSubItem(object sender, DrawListViewSubItemEventArgs e) 
{ 
    //toggle colors if the item is highlighted 
    if (e.Item.Selected && e.Item.ListView.Focused) 
    { 
     e.SubItem.BackColor = SystemColors.Highlight; 
     e.SubItem.ForeColor = e.Item.ListView.BackColor; 
    } 
    else if (e.Item.Selected && !e.Item.ListView.Focused) 
    { 
     e.SubItem.BackColor = SystemColors.Control; 
     e.SubItem.ForeColor = e.Item.ListView.ForeColor; 
    } 
    else 
    { 
     e.SubItem.BackColor = e.Item.ListView.BackColor; 
     e.SubItem.ForeColor = e.Item.ListView.ForeColor; 
    } 

    // Draw the standard header background. 
    e.DrawBackground(); 

    //add a 2 pixel buffer the match default behavior 
    Rectangle rec = new Rectangle(e.Bounds.X + 2, e.Bounds.Y+2, e.Bounds.Width - 4, e.Bounds.Height-4); 

    //TODO Confirm combination of TextFormatFlags.EndEllipsis and TextFormatFlags.ExpandTabs works on all systems. MSDN claims they're exclusive but on Win7-64 they work. 
    TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.EndEllipsis | TextFormatFlags.ExpandTabs | TextFormatFlags.SingleLine; 

    //If a different tabstop than the default is needed, will have to p/invoke DrawTextEx from win32. 
    TextRenderer.DrawText(e.Graphics, e.SubItem.Text, e.Item.ListView.Font, rec, e.SubItem.ForeColor, flags); 
} 
Questions connexes