我正在为我的winforms控件添加新功能,其中一部分要求曾经一度使用的变量现在是可选的(如果它为null,则从第二个源获取数据)。我做了一些更改并运行了我的表单,只是发现没有发生任何事情,甚至以前的功能。困惑我介入了代码并发现我的Winforms用户控件在遇到我的变量时抛出了NullReferenceException
,但是在UI中没有抛出任何错误。
我的设置是我有一个带有组合框的UserControl
。当用户更改该组合框时,它会在第一个控件具有的面板中加载辅助UserControl
。第二个控件就是抛出异常。
以下是代码路径:
private void cmbActionType_SelectedIndexChanged(object sender, EventArgs e)
{
if (_loading)
return;
// ActionType was changed, update the action.ActionType value
if (cmbActionType.SelectedItem != null)
{
if (cmbActionType.SelectedItem.ToString() == SETVALUE_OPTION)
_action.ActionType = ActionTypes.SetValue;
else if (cmbActionType.SelectedItem.ToString() == CHECKVALUE_OPTION)
_action.ActionType = ActionTypes.CheckValue;
else
_action.ActionType = ActionTypes.CustomAction;
}
RefreshActionPanel();
_editor.DataModified();
}
private void RefreshActionPanel()
{
// Control defaults
AnchorStyles styles = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top;
UserControl subControl = null;
// Clear the currently active control
pnlActionDetails.Controls.Clear();
// Determine what type of control to load in the panel
if (cmbActionType.SelectedItem != null && cmbCaseType.SelectedItem != null)
{
// SetValue or CheckValue actions
if (cmbActionType.SelectedItem.ToString() == CHECKVALUE_OPTION || cmbActionType.SelectedItem.ToString() == SETVALUE_OPTION)
{
if (_caseTypeMap.ContainsKey(cmbCaseType.SelectedItem.ToString()))
subControl = new SetCheckActionControl(_action, _editor, _caseTypeMap[cmbCaseType.SelectedItem.ToString()]);
}
// CustomAction action type
else
{
// Check if the requested case is a type or defined in a script
if (_caseTypeMap.ContainsKey(cmbCaseType.SelectedItem.ToString()))
{
subControl = new CustomActionControl(_action, _editor, _caseTypeMap[cmbCaseType.SelectedItem.ToString()]);
}
else if (_editor.ScriptDefinitions.Any(x => x.CaseName == cmbCaseType.SelectedItem.ToString()))
{
var definitions = _editor.ScriptDefinitions.Where(x => x.CaseName == cmbCaseType.SelectedItem.ToString()).ToList();
subControl = new CustomActionControl(_action, _editor, definitions);
}
}
}
if (subControl != null)
{
subControl.Anchor = styles;
subControl.Height = pnlActionDetails.Height;
subControl.Width = pnlActionDetails.Width;
pnlActionDetails.Controls.Add(subControl);
}
}
public CustomActionControl(TestAction action, fmEditor editor, IList<TcScriptDefinition> scriptDefinitions) : base(action, editor)
{
_loading = true;
InitializeComponent();
_scriptDefinitions = scriptDefinitions;
PopulateActionList();
SetupDataGrid();
_loading = false;
}
private void SetupDataGrid()
{
// Clear the current contents of the datagrid
grdParameters.Rows.Clear();
if (cmbAction.SelectedItem == null)
return;
// Retrieve the action code from the drop down
string actionCode = cmbAction.SelectedValue.ToString();
// Check if any paramters are available for this action
if (!_availableActionParameters.ContainsKey(actionCode))
return;
// Add a new row for each parameter available for this action
foreach (string param in _availableActionParameters[actionCode])
{
string display = param;
// Determine if the parameter has a display string
if (_formInstance.CodeDisplayMap.ContainsCode(param))
display = _formInstance.CodeDisplayMap.GetDisplayStringFromCode(param);
// Create the array for the row, with an empty string as the current value
string[] row = { display, string.Empty };
// Check if the current action uses this action code.
// If so, retrieve the value for this parameter and use it in the row
// Note: Case-INsensitive comparison must be performed here
if (_action.Attributes["action"].Equals(actionCode, StringComparison.CurrentCultureIgnoreCase))
if (_action.Attributes.ContainsKey(param))
row[1] = _action.Attributes[param];
grdParameters.Rows.Add(row);
}
}
NullReferenceException
来自SetupDataGrid()
方法,其中_formInstance
被调用。但是,通常当应用程序遇到未处理的异常时,JIT系统会抛出一条错误消息(如您所见,除非我是盲人,否则不会使用try/catch
语句。)
为什么我的winforms应用程序没有显示异常的迹象。我宁愿发生未处理的异常消息,而不是发生任何事情,因为这会让用户更难以知道重要的错误(而不是响应他们的命令)
<小时/> 编辑:为了澄清,因为似乎有一些混乱,我不关心在调试时在visual studio中打破这个异常。事实是,应用程序不应该隐藏未处理的异常,并且我的应用程序应该崩溃(或者更确切地说显示JIT消息发生了未处理的异常),即使在Visual Studio之外没有处于调试模式时也是如此。
< / p>
这不是调试时间问题,而是生产运行时问题。如果此代码抛出一个OutOfMemoryException
,我需要它不要被忽略。现在它被忽略了。
答案 0 :(得分:3)
从Visual Studio的菜单栏转到Debug->Exceptions...
(Ctrl-D, E
,如果您使用的是默认快捷方式),并选中Thrown
下的Common Language Runtime Exceptions
框。这将导致程序在异常中断,即使它们位于try / catch块中。然后,您可以向前迈出一步,查看代码跳转到下一条指令的位置。这应该会带你到隐藏你的异常的catch块。
它可能会跳转到.NET代码以获取捕获,您可以转到Debug->Options and Settings..
并打开Enable .NET framework Source Stepping
以查看其跳转到的内容。
以下是在代码
中捕获unhandeled execptions的示例static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.Run(new Form1());
MessageBox.Show("0");
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
{
MessageBox.Show("1");
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
throw new ArgumentNullException();
}
}
单击按钮,出现1,程序仍然应该在之后运行。
然而正如我在上一篇评论中所说,检查在Debug-&gt; Exceptions中检查用户unhandeled(可能是取消选中并重新检查),它可以解决您的初始问题..
答案 1 :(得分:2)
如果try
中有catch
/ Main
,或者您有ThreadException
处理程序,则可以抓住它们。另请查看SetUnhandledExceptionMode
。
请注意,如果它们被Main
捕获,您的程序将以静默方式退出。 ThreadException
可以“抓住”并忽略它们。
编辑:由于在Thrown
下取消选中Common Language Runtime Exceptions
的复选框时调试器不会中断,因此Windows窗体的代码会捕获它。这并不理想,但很多BCL都是这样做的。你不必担心它会抓住OutOfMemoryException
或类似的东西; BCL应该只捕获它期望的异常(vexing exceptions)。
要清楚,例外不是“未处理”。它由BCL代码处理。