Align the text of a Listview Column in Windows Forms C# to right without changing the header text alignment

StackOverflow https://stackoverflow.com/questions/20449196

Question

I have a System Windows Forms ListView in C# 2008 (Net 2.0) on Win7 which has 4 columns and is in details mode with small icons, fullrowselection on, hideselection false, showtooltips true.

The column No. 3 shall be as the only column aligned to the right and not to the left like the others. I have set the corresponding designer-property to textalignment right which is logical. But Microsoft disappoints here hardly: Microsoft Visual Studio also aligns the columns headline to the right which I don't want!!! Only all the elements shall be aligned right in the column No. 3, the headline texts of all the columns will all stay aligned left. This seems to be not possible with the designer settings.

I searched long in Google and found this - the code aligns my items how I want it, but the items text disappears and appears again, the highlighting and selection doesn't work partial the ListView disappears in parts or in a whole, the text renders weird and like not being sharp etc. etc. - the ListView stopped default behavior after I applied the code below. How can I solve this without this troubles (Ownerdraw is with the code below set to true. I have Fullrowselect, hideselection false and detailsmode on). Basically I need only the subitems in column 3 to be aligned right by my wish without the columnheaders textalignment changed, all other shall be default drawing - I don't wanna ever change any drawing - only the alignment shall be my custom one which I described above.

 private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
    {
        TextFormatFlags flags = TextFormatFlags.Left;

        if (e.ColumnIndex == 3)
        {
            flags = TextFormatFlags.Right;
            e.DrawText(flags);
        }
        else
        {
            e.DrawDefault = true;
        }
    }

    private void listView1_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
    {
        e.DrawDefault = true;
    }
Was it helpful?

Solution

Instead of drawing the ColumnHeader as default while drawing all the items yourself, why not draw all the items as default and draw the ColumnHeader yourself? I've tried this code but the look and feel of the ColumnHeader when the mouse is over is not good, it's not like the default look of a ColumnHeader, to make it look similarly, I'm sure we need much more code, however it's not much different because of the very similar color I used. You can take more time to customize it. This is just a demo:

public Form1(){
  InitializeComponent();
  listView1.OwnerDraw = true;
  invalidateHeaders = typeof(ListView).GetMethod("InvalidateColumnHeaders",
                                       System.Reflection.BindingFlags.NonPublic |
                                       System.Reflection.BindingFlags.Instance);
} 

bool hot;
System.Reflection.MethodInfo invalidateHeaders;
//DrawColumnHeader event handler
private void listView1_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) {
  if (e.Header.TextAlign == HorizontalAlignment.Right) {
      e.DrawBackground();
      e.DrawText(TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter);
      if (e.Bounds.Contains(listView1.PointToClient(MousePosition))) {
          bool selected = (e.State & ListViewItemStates.Selected) != 0;
          var solidColor = selected ? Color.FromArgb(30, Color.FromArgb(0, 200, 200)) :
                                      Color.FromArgb(30, Color.Aqua);
          var borderColor = selected ? Color.DarkGray : Color.Aqua;
          e.Graphics.FillRectangle(new SolidBrush(solidColor), e.Bounds);
          var rect = e.Bounds;
          rect.Width -= 2;
          rect.Height -= 2;                    
          ControlPaint.DrawBorder(e.Graphics, rect, 
                       Color.FromArgb(40, borderColor), ButtonBorderStyle.Solid);
          hot = true;
       }
       else hot = false;
   } else {
       e.DrawDefault = true;
       if (hot) {
          invalidateHeaders.Invoke(listView1, null);
          hot = false;
       }
   }
}
//DrawItem event handler
private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e) {
   e.DrawDefault = true;
}
//MouseMove event handler
private void listView1_MouseMove(object sender, MouseEventArgs e) {
   invalidateHeaders.Invoke(listView1, null);
}    
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top