2011-07-03 78 views
14

我想在列表視圖中更改項目的/行的高度。C#更改列表視圖項/行的高度

我搜索了每一處,我發現爲了改變高度,我需要使用LBS_OWNERDRAWFIXEDMeasureItem或類似的東西。

問題是,我不知道該怎麼辦以及如何使用它..
任何人都可以幫我嗎?

編輯:
我,因爲我使用的是SmallImageList真正不能使用的ImageList背,我需要不同的線高度從ImageList中的圖像大小。

謝謝!

+0

請參閱http://stackoverflow.com/questions/1244090/how-to-set-wpf-listview-row-height。解決方案簡單 – 2014-06-03 16:53:41

+0

提到的「簡單解決方案」是針對WPF的 - 確實很簡單。這個問題是關於WinForms - 它決定不簡單。 – Grammarian

回答

11

它可以通過SmallImageList技巧來完成 - 你就必須要小心。 ObjectListView - 圍繞標準.NET開放源代碼包裝器ListView - 使用該技巧成功實現RowHeight屬性。

如果您需要每行32像素,請分配一個爲16x32(寬x高)的ImageList,然後將每個圖像放置在32像素高度的垂直中間位置。

此屏幕截圖顯示32像素行和自動換行這是因爲額外的空間可能:

enter image description here

ObjectListView做這一切爲你工作。事實上,如果你想用ListView做任何事情,你應該認真考慮使用ObjectListView來代替。它使許多困難的事情(例如,按列類型排序,自定義工具提示)變得微不足道,並且幾個不可能的事情(例如覆蓋,虛擬列表上的組)也是可能的。

+1

那麼,我只是想調整行大小和300kb,因爲我計劃的程序太多了。無論如何,這是一個很好的解決方案。 – Ron

+2

我認爲你提出了一個如此複雜的解決方案 –

13

你必須使用一點黑客。訣竅是在StateImageList屬性中使用圖像列表。 ListView將根據ImageList的ImageSize屬性的高度來調整它的項目高度。您不必爲項目指定圖像,但僅使用StateImageList將強制ListView進行調整。在下面的示例中,我將圖像列表大小設置爲32x32,因此生成32px高度的ListViewItem(s)。

enter image description here

+1

我忘了說,我在SmallImageList proeprty中使用ImageList,所以我不能使用該黑客。 – Ron

+0

然後,你將不得不編寫自己的控件,因爲從經驗和研究來看,對於現有的WinForms ListView來說這是不可能的。這也是來自MSFT社區支持開發人員的同樣迴應,他們也爲一些人研究了這個問題,並最終建議編寫一個自定義控件。 –

+0

我在詳細模式下測試了這個。這個技巧僅用於增加超出高度的行高度。你不能使行比Windows定義的更緊密。請注意列表視圖行的高度取決於操作系統。例如,在Windows 7上,行數比在XP上高得多。可悲的是,這個技巧對我來說並不有用。 – Elmue

1

根據控件的字體大小計算ListView的默認行高(在報表視圖模式下)。

因此,要選擇行高,請在ListView屬性中選擇具有正確高度的字體。 例如,選擇MS無襯線18

然後你就可以更改所有項目所使用的字體: 當你插入一個新的項目,設置其字體屬性。

要優化字體的設置,你應該申報的項目字體作爲形式的私有成員:

Private Font stdfont = new Font("Consolas", 9.0f, FontStyle.Regular); 

然後加入項目時:

ListViewItem i = new ListViewItem("some text"); 
i.Font = stdfont; 
MyListView.Items.Add(i); 

這招是唯一容易的允許有較小的線高;) iE設置控件的字體大小爲7,並設置項目字體大小10 (測試用VS 2008)

11

對於仍與此strugling的人來說,這裏是我的代碼使用方法:

private void SetHeight(ListView listView, int height) 
{ 
    ImageList imgList = new ImageList(); 
    imgList.ImageSize = new Size(1, height); 
    listView.SmallImageList = imgList; 
} 

要使用這只是做:

SetHeight(lvConnections, 25); 
+0

我在詳細模式下對此進行了測試。這個技巧僅用於增加超出高度的行高度。你不能使行比Windows定義的更緊密。請注意列表視圖行的高度取決於操作系統。例如,在Windows 7上,行數比在XP上高得多。可悲的是,這個技巧對我來說並不有用。 – Elmue

0

Plasmabubble有正確的想法。這擴大了這一點,我正在使用一個狹窄的線條寬度的項目。

在ListView的linespacing取決於ListView的字體,不能更改。但是,您可以將ListView中項目的字體設置爲比ListView字體更大的字體。

如果你希望它是成比例的,創建一個基於項目的字體的字體。 我想要的項目高度爲90%的正常的,無論字體選擇。

當我填充列表我用存儲在設置的字體,但你也可以使用文字的字體,如「索拉」。

lvResults.Font = 
    new Font(Properties.Settings.Default.usrHookFont.FontFamily, 
     (float)(Properties.Settings.Default.usrHookFont.Size * .9)); 

foreach (HookSet item in resultSet) 
    { 
     ListViewItem lvi = new ListViewItem(); 
     lvi.Font = Properties.Settings.Default.usrHookFont; 
     <dot><dot><dot> 
} 
0

可悲的是沒有人回答你原來的問題是如何在這些年來使用LBS_OWNERDRAWFIXED

您已接受正在整合一個龐大的系統工程(含演示和文檔3,3MB)答案。但只是爲了設置ListView的行高度,這是過度的。

此處建議的其他解決方法(添加ImageList)僅適用於增加行高。但它不允許真正設置獨立於圖像高度的RowHeight。此外,默認行高取決於操作系統。例如,在Windows 7上,行數比在XP上高得多。你不能選擇讓他們更緊,只能更高。

但非常幾行,你可以做你想做的。 只需複製並粘貼下面的類:

using System; 
using System.Drawing; 
using System.Diagnostics; 
using System.ComponentModel; 
using System.Runtime.InteropServices; 
using System.Windows.Forms; 

namespace ExtendedControls 
{ 

public class ListViewEx : ListView 
{ 
    #region Windows API 

    /* 
    struct MEASUREITEMSTRUCT 
    { 
     public int CtlType;  // Offset = 0 
     public int CtlID;  // Offset = 1 
     public int itemID;  // Offset = 2 
     public int itemWidth; // Offset = 3 
     public int itemHeight; // Offset = 4 
     public IntPtr itemData; 
    } 
    */ 

    [StructLayout(LayoutKind.Sequential)] 
    struct DRAWITEMSTRUCT 
    { 
     public int ctlType; 
     public int ctlID; 
     public int itemID; 
     public int itemAction; 
     public int itemState; 
     public IntPtr hWndItem; 
     public IntPtr hDC; 
     public int rcLeft; 
     public int rcTop; 
     public int rcRight; 
     public int rcBottom; 
     public IntPtr itemData; 
    } 

    // LVS_OWNERDRAWFIXED: The owner window can paint ListView items in report view. 
    // The ListView control sends a WM_DRAWITEM message to paint each item. It does not send separate messages for each subitem. 
    const int LVS_OWNERDRAWFIXED = 0x0400; 
    const int WM_SHOWWINDOW  = 0x0018; 
    const int WM_DRAWITEM  = 0x002B; 
    const int WM_MEASUREITEM  = 0x002C; 
    const int WM_REFLECT   = 0x2000; 

    #endregion 

    bool mb_Measured = false; 
    int ms32_RowHeight = 14; 

    /// <summary> 
    /// Constructor 
    /// </summary> 
    public ListViewEx() 
    { 
     SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true); 
    } 

    /// <summary> 
    /// Sets the row height in Details view 
    /// This property appears in the Visual Studio Form Designer 
    /// </summary> 
    [Category("Appearance")] 
    [Description("Sets the height of the ListView rows in Details view in pixels.")] 
    public int RowHeight 
    { 
     get { return ms32_RowHeight; } 
     set 
     { 
      if (!DesignMode) Debug.Assert(mb_Measured == false, "RowHeight must be set before ListViewEx is created."); 
      ms32_RowHeight = value; 
     } 
    } 

    protected override CreateParams CreateParams 
    { 
     get 
     { 
      CreateParams k_Params = base.CreateParams; 
      k_Params.Style |= LVS_OWNERDRAWFIXED; 
      return k_Params; 
     } 
    } 

    /// <summary> 
    /// The messages WM_MEASUREITEM and WM_DRAWITEM are sent to the parent control rather than to the ListView itself. 
    /// They come here as WM_REFLECT + WM_MEASUREITEM and WM_REFLECT + WM_DRAWITEM 
    /// They are sent from Control.WmOwnerDraw() --> Control.ReflectMessageInternal() 
    /// </summary> 
    protected override void WndProc(ref Message k_Msg) 
    { 
     base.WndProc(ref k_Msg); // FIRST 

     switch (k_Msg.Msg) 
     { 
      case WM_SHOWWINDOW: // called when the ListView becomes visible 
      { 
       Debug.Assert(View == View.Details, "ListViewEx supports only Details view"); 
       Debug.Assert(OwnerDraw == false, "In ListViewEx do not set OwnerDraw = true"); 
       break; 
      } 
      case WM_REFLECT + WM_MEASUREITEM: // called once when the ListView is created, but only in Details view 
      { 
       mb_Measured = true; 

       // Overwrite itemHeight, which is the fifth integer in MEASUREITEMSTRUCT 
       Marshal.WriteInt32(k_Msg.LParam + 4 * sizeof(int), ms32_RowHeight); 
       k_Msg.Result = (IntPtr)1; 
       break; 
      } 
      case WM_REFLECT + WM_DRAWITEM: // called for each ListViewItem to be drawn 
      { 
       DRAWITEMSTRUCT k_Draw = (DRAWITEMSTRUCT) k_Msg.GetLParam(typeof(DRAWITEMSTRUCT)); 
       using (Graphics i_Graph = Graphics.FromHdc(k_Draw.hDC)) 
       { 
        ListViewItem i_Item = Items[k_Draw.itemID]; 

        Color c_BackColor = i_Item.BackColor; 
        if (i_Item.Selected) c_BackColor = SystemColors.Highlight; 
        if (!Enabled)  c_BackColor = SystemColors.Control; 

        using (SolidBrush i_BackBrush = new SolidBrush(c_BackColor)) 
        { 
         // Erase the background of the entire row 
         i_Graph.FillRectangle(i_BackBrush, i_Item.Bounds); 
        } 

        for (int S=0; S<i_Item.SubItems.Count; S++) 
        { 
         ListViewItem.ListViewSubItem i_SubItem = i_Item.SubItems[S]; 

         // i_Item.SubItems[0].Bounds contains the entire row, rather than the first column only. 
         Rectangle k_Bounds = (S>0) ? i_SubItem.Bounds : i_Item.GetBounds(ItemBoundsPortion.Label); 

         // You can use i_Item.ForeColor instead of i_SubItem.ForeColor to get the same behaviour as without OwnerDraw 
         Color c_ForeColor = i_SubItem.ForeColor; 
         if (i_Item.Selected) c_ForeColor = SystemColors.HighlightText; 
         if (!Enabled)  c_ForeColor = SystemColors.ControlText; 

         TextFormatFlags e_Flags = TextFormatFlags.NoPrefix | TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter | TextFormatFlags.SingleLine; 
         switch (Columns[S].TextAlign) 
         { 
          case HorizontalAlignment.Center: e_Flags |= TextFormatFlags.HorizontalCenter; break; 
          case HorizontalAlignment.Right: e_Flags |= TextFormatFlags.Right; break; 
         } 

         TextRenderer.DrawText(i_Graph, i_SubItem.Text, i_SubItem.Font, k_Bounds, c_ForeColor, e_Flags); 
        } 
       } 
       break; 
      } 
     } 
    } 
} // class 
} // namespace 

添加ListViewEx你的表格後,你會看到在Visual Studio窗體設計器,允許設置在像素的行高度的新特性:

Setting RowHeight in a C# ListView

您輸入的值將是以像素爲單位的行高度,並且在所有操作系統上都將嚴格遵守。我測試了它在Windows XP,Windows 7和10:

ListViewEx.RowHeight sample

另外我班有超過原來的ListView兩個優點:它吸引了無閃爍並尊重前景色字體設置爲ListViewSubItem,它被原始的Microsoft ListView忽略。所以你可以用不同的顏色和字體繪製每個單元格。

重要:由於MSDN說LBS_OWNERDRAWFIXED已設計的詳細信息視圖(報表視圖)。我的代碼僅適用於此模式,這是因爲Microsoft已經這樣設計它。

此外請注意,設置ListView.OwnerDraw = true是完全不同的東西比使用LVS_OWNERDRAWFIXED

我沒有執行繪圖圖標,因爲我不需要那個。但是你可以很容易地添加這個。

+0

CreateParams覆蓋導致子項目文本不顯示... – user1932634

+0

我完全不知道你在說什麼。我在我的應用程序中使用此代碼。它完美的工作!在上面的屏幕截圖中,您可以看到所有子項都可以正確繪製,即使是彩色的。 – Elmue