通过多个工作表设置单元格值
Setting cell values through multiple sheets
我有一个作为 VSTO 构建的股票代码,它获取价格,然后将其插入到特定工作的单元格中sheets。这些 sheet 由用户按下按钮添加,添加一个新的 sheet,对其进行格式化,然后将其名称添加到 "accountList" sheet(跟踪所有这些特殊的 sheets).
问题是它只写入用户添加的最新 sheet。这是 worksheet 循环期间发生的事情的片段。
foreach (Excel.Worksheet currentWorksheet in Globals.ThisAddIn.Application.Worksheets)
{
tickerRange = currentWorksheet.Range["A6:A1000", Type.Missing]; //location of ticker symbols
//compare the current worksheet name to any of the names in the accountList
if (Array.IndexOf(accountList.ToArray(), currentWorksheet.Name) >= 0) {
//for every row in the specified range
foreach (Excel.Range row in tickerRange) //for every row inside the tickerRange variable
{
try
{
quoteCell = row.Offset[0, 5]; //location where market price will be inserted
string currentStock = row.Value2; //set ticker Symbol equal to the cell of the range element
if (string.IsNullOrEmpty(currentStock) || currentStock.Trim().Length > 4) //if there is nothing in the cell or the length is more than 4 characters, don't call the fetchPrice.
{
badValue = true;
}//end if
else if (Regex.IsMatch(currentStock, "[ ]|[0-9]")) //if the cell has whitespace or numbers, don't call fetchPrice. This would result in bad output
{
badValue = true;
}
else
{
currentStock = currentStock.ToUpper();
}
if (!badValue) //if the dictionary contains the ticker symbol, no need to call fetchPrice again this loop, just get the value out of dictionary
{
price = tickerDictionary[currentStock];
quoteCell.Value2 = price;
//volumeCell.Value2 = (stockObject.minuteVolume / stockObject.currentVolume)*100;
//break;
}
} //end try
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException rbe) //i forget why i had to catch this in the first place. but it came up once, and now it's caught. so there's that.
{
Console.WriteLine("Runtime Binder Exception caught");
}//end catch
catch (System.Runtime.InteropServices.COMException ce)
{
stopTicker();
}
} //end 'row' foreach
} //end 'sheet' foreach
在调试期间观察局部变量,我可以看到 accountList 填充了正确的信息,并且 foreach 循环正在影响我的其他工作sheet,但是 quoteCell.Value2 = price
没有更新价格除了我的最新作品之外的任何其他作品sheet。
我是不是漏掉了什么愚蠢的东西?
我使用 this link here 发现了问题,它警告不要使用 foreach 的 COM 对象,因为它们的索引访问器不可靠。
在改变了一些东西,并用好的 ol'folded for 循环替换了我的 foreach 之后,我开始工作了。这是更新后的代码:
Sheets worksheets = Globals.ThisAddIn.Application.ActiveWorkbook.Sheets;
int wsCount = worksheets.Count;
for (int w = 1; w <= wsCount; w++)
{
Worksheet currentWorksheet = worksheets.Item[w] as Worksheet;
string mysheet = currentWorksheet.Name;
tickerRange = null;
tickerRange = currentWorksheet.Range["A6:A1000", Type.Missing]; //location of ticker symbols
if (Array.IndexOf(accountList.ToArray(), mysheet) >= 0)
{
//for every row in the specified range
//foreach (Range row in currentWorksheet.Range["A6:A1000", Type.Missing]) //for every row inside the tickerRange variable
for (int r = 6; r <=1000; r++)
{
try
{
badValue = false;
Range row = null;
row = currentWorksheet.Range["A" + r];
quoteCell = null;
//quoteCell = currentWorksheet.Range["A6:A1000", Type.Missing];
//quoteCell = quoteCell.Range[row.Offset[0, 5], Type.Missing];
quoteCell = row.Offset[0, 5]; //location where market price will be inserted
string currentStock = row.Value2; //set ticker Symbol equal to the cell of the range element
if (string.IsNullOrEmpty(currentStock) || currentStock.Trim().Length > 4) //if there is nothing in the cell or the length is more than 4 characters, don't call the fetchPrice.
{
badValue = true;
}//end if
else if (Regex.IsMatch(currentStock, "[ ]|[0-9]")) //if the cell has whitespace or numbers, don't call fetchPrice. This would result in bad output
{
badValue = true;
}
else
{
currentStock = currentStock.ToUpper();
}
if (!badValue) //if the dictionary contains the ticker symbol, no need to call fetchPrice again this loop, just get the value out of dictionary
{
price = tickerDictionary[currentStock];
quoteCell.Value2 = price;
//volumeCell.Value2 = (stockObject.minuteVolume / stockObject.currentVolume)*100;
//break;
}
} //end try
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException rbe) //i forget why i had to catch this in the first place. but it came up once, and now it's caught. so there's that.
{
Console.WriteLine("Runtime Binder Exception caught");
}//end catch
catch (System.Runtime.InteropServices.COMException ce)
{
stopTicker();
}
/*if a KeyNotFound exception was thrown, it was because the user entered a new stock symbol while the loop was running, but
AFTER assemblePrice() was called. This results in the dictionary being asked for something it doesn't have. Just run assemblePrice() again.
*/
catch (System.Collections.Generic.KeyNotFoundException knfe)
{
assemblePrice();
}
} //end for
}
Console.WriteLine("For Loop Completed");
Console.WriteLine("Sleep Started for " + restartTime + "seconds");
//if the timerbox is empty, is set to 5 or less, or contains non-numeric characters
if (string.IsNullOrEmpty(timerBox.Text) || Regex.Equals(timerBox.Text, "[0-5]") || Regex.IsMatch(timerBox.Text, "[^0-9]"))
{
restartTime = 10;
}//end else
else
{
restartTime = Convert.ToInt32(timerBox.Text); //restartTime gets the value after string contents of timerBox are cast to int.
}//end else
}//bigger for loop done
我有一个作为 VSTO 构建的股票代码,它获取价格,然后将其插入到特定工作的单元格中sheets。这些 sheet 由用户按下按钮添加,添加一个新的 sheet,对其进行格式化,然后将其名称添加到 "accountList" sheet(跟踪所有这些特殊的 sheets).
问题是它只写入用户添加的最新 sheet。这是 worksheet 循环期间发生的事情的片段。
foreach (Excel.Worksheet currentWorksheet in Globals.ThisAddIn.Application.Worksheets)
{
tickerRange = currentWorksheet.Range["A6:A1000", Type.Missing]; //location of ticker symbols
//compare the current worksheet name to any of the names in the accountList
if (Array.IndexOf(accountList.ToArray(), currentWorksheet.Name) >= 0) {
//for every row in the specified range
foreach (Excel.Range row in tickerRange) //for every row inside the tickerRange variable
{
try
{
quoteCell = row.Offset[0, 5]; //location where market price will be inserted
string currentStock = row.Value2; //set ticker Symbol equal to the cell of the range element
if (string.IsNullOrEmpty(currentStock) || currentStock.Trim().Length > 4) //if there is nothing in the cell or the length is more than 4 characters, don't call the fetchPrice.
{
badValue = true;
}//end if
else if (Regex.IsMatch(currentStock, "[ ]|[0-9]")) //if the cell has whitespace or numbers, don't call fetchPrice. This would result in bad output
{
badValue = true;
}
else
{
currentStock = currentStock.ToUpper();
}
if (!badValue) //if the dictionary contains the ticker symbol, no need to call fetchPrice again this loop, just get the value out of dictionary
{
price = tickerDictionary[currentStock];
quoteCell.Value2 = price;
//volumeCell.Value2 = (stockObject.minuteVolume / stockObject.currentVolume)*100;
//break;
}
} //end try
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException rbe) //i forget why i had to catch this in the first place. but it came up once, and now it's caught. so there's that.
{
Console.WriteLine("Runtime Binder Exception caught");
}//end catch
catch (System.Runtime.InteropServices.COMException ce)
{
stopTicker();
}
} //end 'row' foreach
} //end 'sheet' foreach
在调试期间观察局部变量,我可以看到 accountList 填充了正确的信息,并且 foreach 循环正在影响我的其他工作sheet,但是 quoteCell.Value2 = price
没有更新价格除了我的最新作品之外的任何其他作品sheet。
我是不是漏掉了什么愚蠢的东西?
我使用 this link here 发现了问题,它警告不要使用 foreach 的 COM 对象,因为它们的索引访问器不可靠。
在改变了一些东西,并用好的 ol'folded for 循环替换了我的 foreach 之后,我开始工作了。这是更新后的代码:
Sheets worksheets = Globals.ThisAddIn.Application.ActiveWorkbook.Sheets;
int wsCount = worksheets.Count;
for (int w = 1; w <= wsCount; w++)
{
Worksheet currentWorksheet = worksheets.Item[w] as Worksheet;
string mysheet = currentWorksheet.Name;
tickerRange = null;
tickerRange = currentWorksheet.Range["A6:A1000", Type.Missing]; //location of ticker symbols
if (Array.IndexOf(accountList.ToArray(), mysheet) >= 0)
{
//for every row in the specified range
//foreach (Range row in currentWorksheet.Range["A6:A1000", Type.Missing]) //for every row inside the tickerRange variable
for (int r = 6; r <=1000; r++)
{
try
{
badValue = false;
Range row = null;
row = currentWorksheet.Range["A" + r];
quoteCell = null;
//quoteCell = currentWorksheet.Range["A6:A1000", Type.Missing];
//quoteCell = quoteCell.Range[row.Offset[0, 5], Type.Missing];
quoteCell = row.Offset[0, 5]; //location where market price will be inserted
string currentStock = row.Value2; //set ticker Symbol equal to the cell of the range element
if (string.IsNullOrEmpty(currentStock) || currentStock.Trim().Length > 4) //if there is nothing in the cell or the length is more than 4 characters, don't call the fetchPrice.
{
badValue = true;
}//end if
else if (Regex.IsMatch(currentStock, "[ ]|[0-9]")) //if the cell has whitespace or numbers, don't call fetchPrice. This would result in bad output
{
badValue = true;
}
else
{
currentStock = currentStock.ToUpper();
}
if (!badValue) //if the dictionary contains the ticker symbol, no need to call fetchPrice again this loop, just get the value out of dictionary
{
price = tickerDictionary[currentStock];
quoteCell.Value2 = price;
//volumeCell.Value2 = (stockObject.minuteVolume / stockObject.currentVolume)*100;
//break;
}
} //end try
catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException rbe) //i forget why i had to catch this in the first place. but it came up once, and now it's caught. so there's that.
{
Console.WriteLine("Runtime Binder Exception caught");
}//end catch
catch (System.Runtime.InteropServices.COMException ce)
{
stopTicker();
}
/*if a KeyNotFound exception was thrown, it was because the user entered a new stock symbol while the loop was running, but
AFTER assemblePrice() was called. This results in the dictionary being asked for something it doesn't have. Just run assemblePrice() again.
*/
catch (System.Collections.Generic.KeyNotFoundException knfe)
{
assemblePrice();
}
} //end for
}
Console.WriteLine("For Loop Completed");
Console.WriteLine("Sleep Started for " + restartTime + "seconds");
//if the timerbox is empty, is set to 5 or less, or contains non-numeric characters
if (string.IsNullOrEmpty(timerBox.Text) || Regex.Equals(timerBox.Text, "[0-5]") || Regex.IsMatch(timerBox.Text, "[^0-9]"))
{
restartTime = 10;
}//end else
else
{
restartTime = Convert.ToInt32(timerBox.Text); //restartTime gets the value after string contents of timerBox are cast to int.
}//end else
}//bigger for loop done