[英]c# unsubscribe anonym method with extra parameters
我將PictureBox
中的圖像添加到TableLayoutPanel
並使用匿名方法在圖像上寫入文本,如下所示:
private void AddPictureWithText(string text, int textX, int textY, int col, int row)
{
var picBox = new PictureBox()
{
Image = Properties.Resources.ProgressStage_LT_GRAY,
SizeMode = PictureBoxSizeMode.Zoom,
Dock = DockStyle.Fill,
};
picBox.Paint += (sender, e) => { picPaint(sender, e, text, textX, textY); };
tableLayoutPanel1.Controls.Add(picBox, col, row);
}
private void picPaint(object sender, PaintEventArgs e, string text, int textPosX, int textPosY)
{
using (Font myFont = new Font("Arial", 12))
{
e.Graphics.DrawString(text, myFont, Brushes.White, new Point(textPosX, textPosY));
}
}
我需要使用匿名方法,因為必須向Paint event
添加額外的參數。
我如何退訂該活動?
您訂閱了一個匿名方法,然后要取消訂閱,則需要對該方法的引用(您尚未引用)。 為了使其更加復雜,它也是一個閉包,那么您不能簡單地將其移至普通類方法。
首先也是最簡單的解決方法(不要這樣做)是將該委托存儲在Control.Tag
屬性中。 您可以具有局部變量,或者在C#7中可以具有局部函數:
private void AddPictureWithText(string text, int textX, int textY, int col, int row)
{
var picBox = new PictureBox
{
Image = Properties.Resources.ProgressStage_LT_GRAY,
SizeMode = PictureBoxSizeMode.Zoom,
Dock = DockStyle.Fill,
Tag = PaintPictureBox
};
picBox.Paint += PaintPictureBox;
tableLayoutPanel1.Controls.Add(picBox, col, row);
void PaintPictureBox(object sender, PaintEventArgs e)
=> picPaint(sender, e, text, textX, textY);
}
要刪除它,您只需要選擇PictureBox.Tag
,將其轉換為PaintEventHandler
並刪除即可:
pbox.Paint -= (PaintEventHandler)pbox.Tag;
不要這樣 這只是錯誤解決問題的方法。
讓我們分步驟進行:首先聲明一個簡單的 PaintEventHandler
:
private void PaintPictureBox(object sender, PaintEventArgs e)
{
}
然后,您需要一些參數,最好的辦法可能是跟蹤使用模型必須繪制的內容,但讓我們稍后進行討論。 現在,您可以向Control.Tag
添加所需的參數:
var picBox = new PictureBox
{
Image = Properties.Resources.ProgressStage_LT_GRAY,
SizeMode = PictureBoxSizeMode.Zoom,
Dock = DockStyle.Fill,
Tag = new PaintModel { Text = text, Locaiton = new Point(textx, texty) }
};
內部PaintPictureBox
:
var data = (PaintModel)((Control)sender).Tag;
您可以訪問data.Text
和data.Location
。 不要忘記使用相關屬性聲明所需的PaintModel
類/結構(或使用命名元組)。 如果不需要任何其他屬性,則可以將Point
直接放在Tag
屬性中,並使用隱藏的 PictureBox.Text
屬性作為標題(顯然,在這種情況下,您不需要PaintModel
類/結構。)
不要這樣做 。 這只是一個稍微好一點的方法,因為我們仍在搞亂職責(其他人負責在PictureBox
繪制文本而不是其自身。)接下來是什么? 讓我們介紹一個自定義控件:
sealed class PictureBoxWithText : PictureBox
{
public Point TextLocation { get; set; }
public override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
using (Font myFont = new Font("Arial", 12))
pe.Graphics.DrawString(Text, myFont, Brushes.White, TextLocation);
}
}
然后,您的AddPictureWithText()
將是:
var picBox = new PictureBoxWithText
{
Text = text,
TextLocation = new Point(textx, texty),
Image = Properties.Resources.ProgressStage_LT_GRAY,
SizeMode = PictureBoxSizeMode.Zoom,
Dock = DockStyle.Fill,
};
tableLayoutPanel1.Controls.Add(picBox, col, row);
稍好一點 ,我們還有一些要改進的地方:我們正在為每個繪制操作創建(並正確處置) Font
對象。 它很慢並且消耗資源。 將其設為私有字段:
sealed class PictureBoxWithText : PictureBox
{
private readonly Font _textFont = new Font("Arial", 12);
protected override Dispose(bool disposing)
{
try
{
if (disposing)
_textFont?.Dispose();
}
finally
{
base.Dispose(disposing);
}
}
// Existing implementation
}
如果字體是固定的,則可以將其移動到static readonly
字段(然后無需覆蓋Dispose(bool)
)。
請記住,這不是完美的解決方案,也不是始終使用的解決方案,如果這樣做是為了顯示大量圖片和文本,則添加100多個控件會嚴重影響性能,在這種情況下,最好保留一個列表顯示的對象並進行相應的繪制(將TableLayoutPanel
和PictureBox
放在一起)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.