c#取消订阅带有额外参数的匿名方法
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
添加额外的参数。
如何取消订阅此活动?
您订阅了一个匿名方法然后取消订阅您需要对该方法的引用(您没有)。为了使它更复杂,它也是一个闭包,那么你不能简单地将它移动到一个普通的 class 方法。
第一个也是最简单的解决方法(不要这样做)是将该委托存储在 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;
不要这样做。这只是解决问题的错误方法的解决方法。
让我们分步进行:首先声明一个 plain 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
class/struct(或使用命名元组)。如果你不需要任何其他属性你可以直接把Point
放在Tag
属性中并使用hiddenPictureBox.Text
属性 作为标题(在这种情况下,显然你不需要 PaintModel
class/struct。)
不要这样做。这只是一个稍微好一点的方法,因为我们仍在处理职责(其他人负责在 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
object。它很慢并且会消耗资源。将其设为私有字段:
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)
)。
请记住,这不是完美或always-use-this解决方案,如果您这样做是为了显示很多图片+文本然后添加 100 多个控件会严重影响性能,在这种情况下你最好保留一个你正在显示的 object 的列表并相应地执行绘画(删除 TableLayoutPanel
和PictureBox
一起。)
我将 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
添加额外的参数。
如何取消订阅此活动?
您订阅了一个匿名方法然后取消订阅您需要对该方法的引用(您没有)。为了使它更复杂,它也是一个闭包,那么你不能简单地将它移动到一个普通的 class 方法。
第一个也是最简单的解决方法(不要这样做)是将该委托存储在 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;
不要这样做。这只是解决问题的错误方法的解决方法。
让我们分步进行:首先声明一个 plain 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
class/struct(或使用命名元组)。如果你不需要任何其他属性你可以直接把Point
放在Tag
属性中并使用hiddenPictureBox.Text
属性 作为标题(在这种情况下,显然你不需要 PaintModel
class/struct。)
不要这样做。这只是一个稍微好一点的方法,因为我们仍在处理职责(其他人负责在 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
object。它很慢并且会消耗资源。将其设为私有字段:
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)
)。
请记住,这不是完美或always-use-this解决方案,如果您这样做是为了显示很多图片+文本然后添加 100 多个控件会严重影响性能,在这种情况下你最好保留一个你正在显示的 object 的列表并相应地执行绘画(删除 TableLayoutPanel
和PictureBox
一起。)