我的代码正在创建具有不同控件和事件的表单的多个实例。这是在将i
增加到表单总量的同时完成的。目的是将事件添加到表单中的按钮控件。我的表单是Ticker
的实例,是我创建的Form
的子类。
我遇到的问题是,当我在运行时点击按钮时,事件处理程序启动,i
超出界限,因为循环已经完成。
下面是代码片段,事件处理程序被集成到一个递增i
的循环中,该循环也包含交换机。 thisObject
的任何方式都等于当前活动的自动收报机,同时仍然将事件处理程序保留在循环中?
编辑:我提供了全班,以便更清晰。相关部分通过action_set>>电子邮件>>触发器>>点击案例进行。
public partial class DesktopTickers : Form
{
public DesktopTickers(List<string> tickerArgs)
{
InitializeComponent();
this.Opacity = 0;
this.ShowInTaskbar = false;
int totalTickers = tickerArgs.Count();
Rectangle screenBounds = GetDpiSafeResolution();
Size iconSizeDefault = this.Size;
string iconDirectory = @"\\server\Tickers\";
string iconSuffix = "_icon.png";
string configDirectory = @"\\server\Tickers\";
string configSuffix = ".txt";
char paramDelimiter = ':';
char controlDelimiter = '=';
char[] controlSeparatorL = {'('};
char controlSeparatorR = ')';
char actionDelimiter = '=';
char[] actionSeparatorL = {'('};
char actionSeparatorR = ')';
char propertyDelimiter = '-';
int maxWidthDefault = iconSizeDefault.Width;
int maxHeightDefault = iconSizeDefault.Height;
Ticker[] tickers = new Ticker[tickerArgs.Count()];
List<Control> controls = new List<Control>();
for (int i = 0; i < tickerArgs.Count(); i++)
{
string tickerArg = tickerArgs[i];
string tickerConfigPath = configDirectory + tickerArg + configSuffix;
string tickerResourcePath = iconDirectory + @"\" + tickerArg + @"\";
string tickerIconPath = tickerResourcePath + tickerArg + iconSuffix;
tickers[i] = new Ticker(screenBounds, tickerArg, i+1, tickerArgs.Count(), iconSizeDefault,
maxHeightDefault, maxWidthDefault, tickerIconPath);
string[] tickerConfigContents = File.ReadAllLines(tickerConfigPath);
for (int j = 0; j < tickerConfigContents.Length; j++)
{
string thisConfigLine = tickerConfigContents[j];
int configParamEnd = thisConfigLine.IndexOf(paramDelimiter);
if (configParamEnd < 0) { configParamEnd = 0; }
string tickerConfigParam = thisConfigLine.Substring(0, configParamEnd);
string tickerConfigValue = thisConfigLine.Substring(configParamEnd + 1);
switch (tickerConfigParam.ToLower())
{ //TICKER LEVEL PARAMETERS
case "icon_width":
tickers[i].iconWidth = Convert.ToInt32(tickerConfigValue);
break;
case "icon_height":
tickers[i].iconHeight = Convert.ToInt32(tickerConfigValue);
break;
case "max_width":
tickers[i].maxWidth = Convert.ToInt32(tickerConfigValue);
break;
case "max_height":
tickers[i].maxHeight = Convert.ToInt32(tickerConfigValue);
break;
case "control_set":
for (int k = j + 1; k < tickerConfigContents.Length; k++)
{ //CONTROL LEVEL PARAMETERS
string thisControlLine = tickerConfigContents[k];
if(thisControlLine == "end") { break; }
int controlParamEnd = thisControlLine.IndexOf(controlDelimiter);
string thisControlType = thisControlLine.Substring(0, controlParamEnd);
string thisControlDetails = thisControlLine.Substring(controlParamEnd+ 1);
thisControlDetails = thisControlDetails.Replace(controlSeparatorR.ToString(), "");
string[] controlProperties = thisControlDetails.Split(controlSeparatorL, StringSplitOptions.RemoveEmptyEntries);
switch (thisControlType.ToLower())
{ //CONTROL TYPE LEVEL PARAMETERS
case "image":
PictureBox thisImage = new PictureBox();
for (int l = 0; l < controlProperties.Length; l++)
{
string thisProperty = controlProperties[l];
int propertyParamEnd = thisProperty.IndexOf(propertyDelimiter);
string propertyType = thisProperty.Substring(0, propertyParamEnd - 1);
string propertyValue = thisProperty.Substring(propertyParamEnd + 2);
switch (propertyType.ToLower())
{ //PROPERTY LEVEL PARAMETERS
case "file":
try { thisImage.BackgroundImage = Image.FromFile(tickerResourcePath + propertyValue); }
catch { thisImage.BackgroundImage = thisImage.ErrorImage; }
break;
case "bounds":
char[] pointDelimiter = { ',' };
string[] boundsValues = propertyValue.Split(pointDelimiter);
Rectangle bounds = new Rectangle(
new Point(Convert.ToInt32(boundsValues[0]), Convert.ToInt32(boundsValues[1])),
new Size(Convert.ToInt32(boundsValues[2]), Convert.ToInt32(boundsValues[3])));
thisImage.Bounds = bounds;
break;
case "layout":
switch(propertyValue.ToLower())
{
case "stretch":
thisImage.BackgroundImageLayout = ImageLayout.Stretch;
break;
case "zoom":
thisImage.BackgroundImageLayout = ImageLayout.Zoom;
break;
case "tile":
thisImage.BackgroundImageLayout = ImageLayout.Tile;
break;
case "center":
thisImage.BackgroundImageLayout = ImageLayout.Center;
break;
default:
thisImage.BackgroundImageLayout = ImageLayout.None;
break;
}
break;
case "id":
thisImage.Name = propertyValue;
break;
}
tickers[i].Controls.Add(thisImage);
thisImage.Show();
}
break;
case "label":
Label thisLabel = new Label();
for (int l = 0; l < controlProperties.Length; l++)
{
string thisProperty = controlProperties[l];
int propertyParamEnd = thisProperty.IndexOf(propertyDelimiter);
string propertyType = thisProperty.Substring(0, propertyParamEnd - 1);
string propertyValue = thisProperty.Substring(propertyParamEnd + 2);
thisLabel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
switch (propertyType.ToLower())
{ //PROPERTY LEVEL PARAMETERS
case "text":
thisLabel.Text = propertyValue;
break;
case "font":
char fontDelimiter = ',';
int fontSplitIndex = propertyValue.IndexOf(fontDelimiter);
string fontName = propertyValue.Substring(0, fontSplitIndex);
string fontSize = propertyValue.Substring(fontSplitIndex + 1);
int fontSizeNum = int.Parse(fontSize);
thisLabel.Font = new Font(propertyValue, fontSizeNum);
break;
case "bounds":
char[] pointDelimiter = {','};
string[] boundsValues = propertyValue.Split(pointDelimiter);
Rectangle bounds = new Rectangle(
new Point(Convert.ToInt32(boundsValues[0]), Convert.ToInt32(boundsValues[1])),
new Size(Convert.ToInt32(boundsValues[2]), Convert.ToInt32(boundsValues[3])));
thisLabel.Bounds = bounds;
break;
case "id":
thisLabel.Name = propertyValue;
break;
}
thisLabel.Show();
tickers[i].Controls.Add(thisLabel);
}
break;
case "button":
Button thisButton = new Button();
for (int l = 0; l < controlProperties.Length; l++)
{
string thisProperty = controlProperties[l];
int propertyParamEnd = thisProperty.IndexOf(propertyDelimiter);
string propertyType = thisProperty.Substring(0, propertyParamEnd - 1);
string propertyValue = thisProperty.Substring(propertyParamEnd + 2);
switch (propertyType.ToLower())
{
case "text":
thisButton.Text = propertyValue;
break;
case "font":
char fontDelimiter = ',';
int fontSplitIndex = propertyValue.IndexOf(fontDelimiter);
string fontName = propertyValue.Substring(0, fontSplitIndex);
string fontSize = propertyValue.Substring(fontSplitIndex + 1);
int fontSizeNum = int.Parse(fontSize);
thisButton.Font = new Font(propertyValue, fontSizeNum);
break;
case "bounds":
char[] pointDelimiter = { ',' };
string[] boundsValues = propertyValue.Split(pointDelimiter);
Rectangle bounds = new Rectangle(
new Point(Convert.ToInt32(boundsValues[0]), Convert.ToInt32(boundsValues[1])),
new Size(Convert.ToInt32(boundsValues[2]), Convert.ToInt32(boundsValues[3])));
thisButton.Bounds = bounds;
break;
case "id":
thisButton.Name = propertyValue;
break;
}
thisButton.Show();
tickers[i].Controls.Add(thisButton);
}
break;
case "textbox":
TextBox thisTextBox = new TextBox();
for (int l = 0; l < controlProperties.Length; l++)
{
string thisProperty = controlProperties[l];
int propertyParamEnd = thisProperty.IndexOf(propertyDelimiter);
string propertyType = thisProperty.Substring(0, propertyParamEnd - 1);
string propertyValue = thisProperty.Substring(propertyParamEnd + 2);
thisTextBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
switch (propertyType.ToLower())
{ //PROPERTY LEVEL PARAMETERS
case "text":
thisTextBox.Text = propertyValue;
break;
case "font":
char fontDelimiter = ',';
int fontSplitIndex = propertyValue.IndexOf(fontDelimiter);
string fontName = propertyValue.Substring(0, fontSplitIndex);
string fontSize = propertyValue.Substring(fontSplitIndex + 1);
int fontSizeNum = int.Parse(fontSize);
thisTextBox.Font = new Font(propertyValue, fontSizeNum);
break;
case "bounds":
char[] pointDelimiter = { ',' };
string[] boundsValues = propertyValue.Split(pointDelimiter);
Rectangle bounds = new Rectangle(
new Point(Convert.ToInt32(boundsValues[0]), Convert.ToInt32(boundsValues[1])),
new Size(Convert.ToInt32(boundsValues[2]), Convert.ToInt32(boundsValues[3])));
thisTextBox.Bounds = bounds;
break;
case "id":
thisTextBox.Name = propertyValue;
break;
}
thisTextBox.Show();
tickers[i].Controls.Add(thisTextBox);
}
break;
}
}
break;
case "action_set":
for (int k = j + 1; k < tickerConfigContents.Length; k++)
{ //ACTION LEVEL PARAMETERS
string thisActionLine = tickerConfigContents[k];
if (thisActionLine == "end") { break; }
int actionParamEnd = thisActionLine.IndexOf(actionDelimiter);
string thisActionType = thisActionLine.Substring(0, actionParamEnd);
string thisActionDetails = thisActionLine.Substring(actionParamEnd + 1);
thisActionDetails = thisActionDetails.Replace(actionSeparatorR.ToString(), "");
string[] actionProperties = thisActionDetails.Split(actionSeparatorL, StringSplitOptions.RemoveEmptyEntries);
Control thisObject = new Control();
switch (thisActionType.ToLower())
{ //ACTION TYPE LEVEL PARAMETERS
case "email":
//email requires trigger, objectid, action to send email, email action params
for (int l = 0; l < actionProperties.Length; l++)
{
string thisProperty = actionProperties[l];
int propertyParamEnd = thisProperty.IndexOf(propertyDelimiter);
string propertyType = thisProperty.Substring(0, propertyParamEnd - 1);
string propertyValue = thisProperty.Substring(propertyParamEnd + 2);
string emailDomain = "";
string emailServer = "";
int emailPort = 0;
string emailTemplate = "";
string emailRecipient = "";
switch (propertyType.ToLower())
{
case "domain":
emailDomain = propertyValue;
break;
case "server":
emailServer = propertyValue;
break;
case "port":
emailPort = Convert.ToInt32(propertyValue);
break;
case "file":
emailTemplate = tickerResourcePath + propertyValue;
break;
case "recipient":
emailRecipient = propertyValue;
break;
case "object":
thisObject = tickers[i].Controls.Find(propertyValue, false).FirstOrDefault() as Control;
//thisObject = objects[0];
break;
case "trigger":
tickers[i].SetEmailProperties(emailDomain, emailServer, emailPort, emailTemplate, emailRecipient);
switch(propertyValue.ToLower())
{
case "click":
thisObject.MouseDown += new MouseEventHandler((sender, e)
=> tickers[i].SendEmail_Event(sender, e));
break;
}
break;
}
}
break;
}
}
break;
}
}
tickers[i].Show();
}
}
private Rectangle GetDpiSafeResolution()
{
using (Graphics graphics = this.CreateGraphics())
{
return new Rectangle(new Point(0, 0), new Size((Screen.PrimaryScreen.Bounds.Width * (int)graphics.DpiX) / 96
, (Screen.PrimaryScreen.Bounds.Height * (int)graphics.DpiY) / 96));
}
}
}
答案 0 :(得分:0)
这似乎是一个捕获问题。您需要在创建表单时捕获i
的值,并在创建事件处理程序时保留此值。这可以通过在创建表单时创建新变量iValue
或tickerInd
来完成,并在事件处理程序代码中使用此变量而不是i
。
我正在以一种推测的方式写这个答案。请提供更大的代码段,以便我们查看表单和处理程序的创建代码。但我相信您当前的代码如下。我标记为&#34;代码的部分基于i&#34;是您当前提供的代码段。
for (var i = 0; i < formCount; ++i)
{
var form = new Ticker();
form.Button.OnClicked += () =>
{
//code based on i
doSomething(i);
};
}
需要如下:
for (var i = 0; i < formCount; ++i)
{
var formInd = i;
var form = new Ticker();
form.Button.OnClicked += () =>
{
//code based on i
doSomething(formInd);
};
}
编辑:您需要更改以下代码:
case "click":
//replace i with tickerInd, this will capture the current value of i
var tickerInd = i;
thisObject.MouseDown += new MouseEventHandler((sender, e)
=> tickers[tickerInd].SendEmail_Event(sender, e));
break;
注意:您的代码似乎需要一些重构。首先,您真的不需要Ticker[] tickers
,您可以简单地执行以下操作:
public DesktopTickers(List<string> tickerArgs)
{
for (var i = 0; i < tickerArgs.Count; ++i)
{
var tickerArg = tickerArgs[i];
var ticker = new Ticker(...);
//your whole initialization code goes here
//replace all "tickers[i]" with "ticker"
ticker.Show();
}
}
之后,您可以通过将此初始化移动到Ticker
构造函数中进行进一步的重构,然后进一步将其划分为初始化方法。
答案 1 :(得分:0)
我不认为我完全理解这个问题,但是看起来你的问题不仅仅是循环。
在C#4中,编译器中存在一个错误,其中包含foreach
和for
个变量,这样当它们关闭时,它始终是最后一个赋值。这已在C#5中修复。
如果ticker[i]
中的(sender, e) => tickers[i].SendEmail_Event(sender, e)
总是超出范围,可能是因为你的迭代器变量是在循环范围之外声明的。
int i = 0;
var funcs = new Func<int>[100];
do
{
funcs[i] = () => i;
}while(++i < 100);
Assert.That(funcs[0](), Is.EqualTo(0));
此测试将失败,因为它们都关闭i,当循环结束时实际上将为100。要解决此问题,您需要一个位于内部范围内的变量(因此在这种情况下,每次迭代都是唯一的):
int i = 0;
var funcs = new Func<int>[100];
do
{
int closedInt = i;
funcs[i] = () => closedInt;
}while(++i < 100);
Assert.That(funcs[0](), Is.EqualTo(0));