前陣子開發(fā)一個小軟件与斤,由于添加到ListBox中的單項文本可能會非常長。默認情況下ListBox會只顯示一部分:
而這個軟件要求每一項如果內容多了就多行顯示尼斧,也就是如下的效果:
????這個就用到了WinForm中的自繪(OwnerDraw)技術姜贡,也就是自定義控件的繪制代替系統(tǒng)的默認繪制,做法也比較套路:1)設置控件的DrawMode屬性為OwnerDrawVariable棺棵;2)監(jiān)聽控件的MeasureItem事件楼咳,計算每一項的顯示高度;3)監(jiān)聽控件的DrawItem事件烛恤,繪制每一項的內容母怜。
具體例子代碼如下:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApp9
{
? ? public partial class Form1 : Form
? ? {
? ? ? ? private const int ITEM_PADDING = 10;//各項之間的邊距
? ? ? ? public Form1()
? ? ? ? {
? ? ? ? ? ? InitializeComponent();
? ? ? ? ? ? listBox1.DrawMode = DrawMode.OwnerDrawVariable;
? ? ? ? ? ? listBox1.DrawItem += ListBox1_DrawItem;
? ? ? ? ? ? listBox1.MeasureItem += ListBox1_MeasureItem;
? ? ? ? ? ? string[] items = new string[]{ "DNSPod稱,該事件將影響部分家用路由器用戶缚柏,訪問所有網絡服務時DNS解析被調度到江蘇電信或周邊線路苹熏,因跨網、跨省币喧、節(jié)點容量等原因造成訪問延遲升高或訪問失敗轨域。",
? ? ? ? ? ? ? ? "近日我們監(jiān)控到多起客戶在全國各地各運營商流量被調度到江蘇電信的問題,經過與第三方的合作分析排查確認粱锐,這是一起大規(guī)模的黑產攻擊事件疙挺,非DNSPod問題。",
? ? ? ? ? ? ? ? "引導報障用戶檢查無線路由器DNS是否被黑客篡改怜浅,并及時修正DNS∈弑溃可改為運營商默認DNS或者我們對外提供的公共DNS:119.29.29.29或119.28.28.28恶座。建議DNSPod客戶臨時將江蘇電信線路調整使用BGP節(jié)點進行覆蓋。目前DNSPod也在聯(lián)合第三方和有關部門(CNCERT等)進一步分析處理沥阳,有最新消息將及時同步跨琳,詳情請關注后續(xù)DNSPod及CNCERT的公告。" };
? ? ? ? ? ? listBox1.Items.AddRange(items);
? ? ? ? }
? ? ? ? private void ListBox1_MeasureItem(object sender, MeasureItemEventArgs e)
? ? ? ? {
? ? ? ? ? ? ListBox listBox = sender as ListBox;
? ? ? ? ? ? int index = e.Index;//獲取當前要進行繪制的行的序號桐罕,從0開始脉让。
? ? ? ? ? ? if (index < 0)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
? ? ? ? ? ? string text = Convert.ToString(listBox.Items[index]);
? ? ? ? ? ? //超范圍后自動換行
? ? ? ? ? ? Size size = TextRenderer.MeasureText(index + ":" + text, listBox.Font, listBox.Size, TextFormatFlags.WordBreak);
? ? ? ? ? ? e.ItemWidth = size.Width;
? ? ? ? ? ? e.ItemHeight = size.Height + ITEM_PADDING*2;//適當多一點高度桂敛,避免太擠
? ? ? ? }
? ? ? ? private void ListBox1_DrawItem(object sender, DrawItemEventArgs e)
? ? ? ? {
? ? ? ? ? ? int index = e.Index;//獲取當前要進行繪制的行的序號,從0開始溅潜。
? ? ? ? ? ? if (index < 0)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? }
? ? ? ? ? ? ListBox listBox = sender as ListBox;
? ? ? ? ? ? e.DrawBackground();//畫背景顏色
? ? ? ? ? ? e.DrawFocusRectangle();//畫聚焦項的邊框
? ? ? ? ? ? Graphics g = e.Graphics;//獲取Graphics對象术唬。
? ? ? ? ? ? Rectangle itemBounds = e.Bounds;//獲取當前要繪制的行的一個矩形范圍。
? ? ? ? ? ? //文字繪制的區(qū)域滚澜,留出一定間隔
? ? ? ? ? ? Rectangle textBounds = new Rectangle(itemBounds.X, itemBounds.Y + ITEM_PADDING, itemBounds.Width, itemBounds.Height);
? ? ? ? ? ? string text = Convert.ToString(listBox.Items[index]);
? ? ? ? ? ? //因為文本可能會非常長粗仓,因此要用自繪實現(xiàn)ListBox項目的自動換行
? ? ? ? ? ? TextRenderer.DrawText(g, index + ":" + text, e.Font, textBounds, e.ForeColor,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TextFormatFlags.WordBreak);
? ? ? ? ? ? g.DrawRectangle(Pens.Blue, itemBounds);//畫每一項的邊框,這樣清楚分出來各項设捐。
? ? ? ? }
? ? }
}
最后感慨一下借浊,類似這樣的效果如果用WPF或者Electron等hybrid的解決方案,完全沒必要這么麻煩萝招,幾行代碼就搞定蚂斤,這里強烈建議大家以及我自己:開發(fā)窗口程序盡量不要用WinForm了,復雜效果很麻煩的槐沼,WPF橡淆、Electron等是更好的選擇。