WinForm應用實戰開發指南 - 如何實現自定義用戶控件及自定義事件處理?

在我們一些非標的用戶界面中,往往需要自定義用戶控件界面,從而實現不同的內容展示和處理規則,本文介紹使用Winform開發自定義用戶控件,以及實現相關自定義事件的處理。

PS:給大家推薦一個C#開發可以用到的界面組件——DevExpress WinForms,它能完美構建流暢、美觀且易於使用的應用程序,無論是Office風格的界面,還是分析處理大批量的業務數據,它都能輕鬆勝任!

 

用戶控件的界面分析

對於比較規範的界面,需要進行一定的分析,以便從中找到對應的規則,逐步細化爲自定義用戶控件的方式,例如對於由下面多個集合組成的界面內容。

WinForm應用實戰開發指南 - 如何實現自定義用戶控件及自定義事件處理?

我們截取其中之一,也就是由這些內容多個組合而成,集合可以通過佈局TableLayoutPanel(表格佈局)或者FlowLayoutPanel(順序流佈局)來添加即可。

WinForm應用實戰開發指南 - 如何實現自定義用戶控件及自定義事件處理?

而其中之一的內容,不同的顏色方格又可以定義爲一個用戶控件,因此最終有多個小方格組成的用戶控件的。

WinForm應用實戰開發指南 - 如何實現自定義用戶控件及自定義事件處理?

而單個用戶控件,可能承載不同的內容,我們可以定義更多的接口屬性以及一些事件來處理相關的邏輯。

甚至還可以在一個單元格里面放置更多的內容,如放置一些特殊的標籤來展示信息。

WinForm應用實戰開發指南 - 如何實現自定義用戶控件及自定義事件處理?

自定義用戶控件的接口和實現

爲了使用戶控件更加規範化,我們可以定義一個接口,聲明相關的屬性和處理方法,如下代碼所示。

/// <summary>
/// 自定義控件的接口
/// </summary>
public interface INumber
{
/// <summary>
/// 數字
/// </summary>
string Number { get; set; }

/// <summary>
/// 數值顏色
/// </summary>
Color Color { get; set; }

/// <summary>
/// 顯示文本
/// </summary>
string Animal { get; set; }

/// <summary>
/// 顯示文本
/// </summary>
string WuHan { get; set; }

/// <summary>
/// 設置選中的內容的處理
/// </summary>
/// <param name="data">事件數據</param>
void SetSelected(ClickEventData data);
}

然後我們創建一個用戶控件,並命名爲NumberItem,並使它繼承前面定義的接口 INumber ,實現相關的屬性和事件,如下代碼所示。

/// <summary>
/// 自定義用戶控件
/// </summary>
public partial class NumberItem : UserControl, INumber
{
/// <summary>
/// 數字
/// </summary>
public string Number { get; set; }

/// <summary>
/// 顏色
/// </summary>
public Color Color { get; set; }

/// <summary>
/// 顯示文本
/// </summary>
public string Animal { get; set; }

/// <summary>
/// 顯示文本
/// </summary>
public string WuHan { get; set; }

其中處理方法SetSelected先保留爲空,後面繼續完善。

/// <summary>
/// 設置選中的數值
/// </summary>
/// <param name="data">傳遞的數據</param>
public void SetSelected(ClickEventData data)
{

}

由於自定義控件,我們需要跟蹤用戶的單擊處理,並且需要把這個邏輯逐步推動到頂級界面上去進行處理,因此需要定義一個事件信息,如下所示。

/// <summary>
/// 事件處理
/// </summary>
public EventHandler<ClickEventData> ClickEventHandler { get; set; }

其中ClickEventData是我們定義的一個數據,用來承載用戶單擊的類型和值內容的信息結構,如下代碼所示。

/// <summary>
/// 對自定義控件觸發的事件信息
/// </summary>
public class ClickEventData
{
/// <summary>
/// 事件觸發類型
/// </summary>
public ClickEventType ClickEventType { get; set; } = ClickEventType.Number;

/// <summary>
/// 傳遞值
/// </summary>
public string Value { get; set; }

public ClickEventData()
{
}

/// <summary>
/// 參數化構造
/// </summary>
/// <param name="clickEventType">事件觸發類型</param>
/// <param name="value">傳遞值</param>
public ClickEventData(ClickEventType clickEventType, string value)
{
ClickEventType = clickEventType;
Value = value;
}
}

再創建一個整合多個號碼數值的一個自定義控件,它也是一個完整的單元之一,我們命名爲 LotteryItemControl2。

我們相當於把前面的自定義控件,組合爲一個新的用戶控件,形成一個相對完整的部分,這裏提供兩種思路,一種是使用常規的用戶控件,拖動已有的用戶控件組合而成,如下所示。

WinForm應用實戰開發指南 - 如何實現自定義用戶控件及自定義事件處理?

另一種是利用TableLayoutPanel,動態添加控件進行組合,可以根據預設的TableLayout佈局實現控件的順序添加。

WinForm應用實戰開發指南 - 如何實現自定義用戶控件及自定義事件處理?

表格的行列定義如下所示:

WinForm應用實戰開發指南 - 如何實現自定義用戶控件及自定義事件處理?

兩種方式都可以實現類似的效果,我們這裏以第一種爲例實現。

public partial class LotteryItemControl2 : UserControl
{
/// <summary>
/// 事件處理
/// </summary>
public EventHandler<ClickEventData> ClickEventHandler { get; set; }

/// <summary>
/// 第幾期
/// </summary>
public string Qi { get; set; }

/// <summary>
/// 數據列表
/// </summary>
public List<string> NumberList { get; set; }

數據列表就是展示在自定義控件的數字。在控件中定義一個函數 統一處理數據內容的綁定顯示。

/// <summary>
/// 綁定數據
/// </summary>
public void BindData()
{
//控件列表,方便統一處理
var controlList = new List<NumberItem>
{
this.numberItem1, this.numberItem2, this.numberItem3, this.numberItem4,
this.numberItem5, this.numberItem6, this.numberItem7
};

this.labelQi.Text = Qi; //設置第幾期
for(int i =0; i < this.NumberList.Count; i++)
{
var control = controlList[i];
var number = this.NumberList[i];

var shenxiao = LotteryToolHelper.NumberToShenXiaoDict[number]; //"馬";
var wuhan = LotteryToolHelper.NumberToWuhanDict[number];//"土"

control.Number = number;
control.Animal = shenxiao;
control.WuHan = wuhan;

var colorStr = LotteryToolHelper.ColorBall[number];
control.Color = LotteryToolHelper.GetColor(colorStr); //item % 2 == 0 ? Color.Red : Color.Green;

control.BindData();
control.ClickEventHandler += (s, data) =>
{
if (ClickEventHandler != null)
{
//傳遞父控件統一處理
ClickEventHandler(s, data);
}
};
}
}

其中該控件也可以設置選中,有具體的子控件調用設置選中的處理規則即可。

/// <summary>
/// 遍歷控件,設置選中的數值
/// </summary>
/// <param name="data">傳遞信息</param>
public void SetSelected(ClickEventData data)
{
foreach (var control in this.Controls)
{
if (control is NumberItem item)
{
item.SetSelected(data);
}
}
}

爲了提高性能,我們一般往往需要設置窗體或者Panel爲雙緩衝DoubleBuffered = true。

在主界面的面板中,我們可以添加一個FlowLayoutPanel 來按順序堆疊用戶控件,具體的實現邏輯就是根據從數據庫獲得的記錄進行展示即可。

var controlList = new List<LotteryItemControl2>();
foreach (var info in list)
{
var control = new LotteryItemControl2();

control.Qi = info.LineNo.ToString("D2");
var numberList = new List<string>()
{
info.No1.ToString("D2"),
info.No2.ToString("D2"),
info.No3.ToString("D2"),
info.No4.ToString("D2"),
info.No5.ToString("D2"),
info.No6.ToString("D2"),
info.No7.ToString("D2"),
};
control.NumberList = numberList;
control.BindData();

control.ClickEventHandler += (s, data) =>
{
//遍歷所有的控件統一處理樣式
foreach (var subCtrl in panel.Controls)
{
if (subCtrl is LotteryItemControl2 lottery)
{
lottery.SetSelected(data);
}
}
};
controlList.Add(control);
}
this.panel.Controls.AddRange(controlList.ToArray());

以上就是相關的處理邏輯,用來組織自定義用戶控件的統一展示處理。

如果需要用戶進行不同條件的數據展示,那麼展示前,就需要重新清空面板中的控件,如下所示。

//清空界面
while (panel.Controls.Count > 0)
{
var controltoremove = panel.Controls[0];
panel.Controls.RemoveAt(0);
controltoremove.Dispose();
}
panel.Controls.Clear();

上面代碼記得調用Dispose方法來釋放控件資源。

在最小的自定義控件中,我們可能需要根據一些條件進行一些自定義繪製處理,以突出顯示不同的內容(重點強調選中項目)。

private void NumberItem_Paint(object sender, PaintEventArgs e)

如下是一些特殊的繪製處理內容。

private void NumberItem_Paint(object sender, PaintEventArgs e)
{
this.BackColor = (this.BorderStyle == BorderStyle.FixedSingle) ? Color.Yellow : Color.Transparent;
if (this.BorderStyle == BorderStyle.FixedSingle)
{
IntPtr hDC = GetWindowDC(this.Handle);
Graphics g = Graphics.FromHdc(hDC);
ControlPaint.DrawBorder(
g,
new Rectangle(0, 0, this.Width, this.Height),
_borderColor,
_borderWidth,
ButtonBorderStyle.Solid,
_borderColor,
_borderWidth,
ButtonBorderStyle.Solid,
_borderColor,
_borderWidth,
ButtonBorderStyle.Solid,
_borderColor,
_borderWidth,
ButtonBorderStyle.Solid);
g.Dispose();
ReleaseDC(Handle, hDC);
}
}

最終展示效果如下所示,黃色強調的處理,是選中相同號碼的處理事件結果繪製。

WinForm應用實戰開發指南 - 如何實現自定義用戶控件及自定義事件處理?

本文轉載自:博客園 - 伍華聰

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章