错误控件






4.63/5 (14投票s)
扩展错误提供程序、ToolStripErrorDropDown 和 MessageBox 的替代品。
引言
本文将介绍三个工具,它们应该能帮助任何窗体开发人员。它们是
- 对话框 - 对消息框的改进。
- 扩展错误提供程序 - 为错误提供程序添加一些附加功能。
- 工具条错误下拉列表 - 一个与扩展错误提供程序挂钩的控件。
扩展错误提供程序
错误提供程序是一个很棒的工具。任何将其与数据绑定一起使用过的人都知道它有多神奇。然而,它遗漏了如此多简单的东西,这让我感到惊讶。例如,错误提供程序上有多少错误?我最大的问题是——缺乏事件。我想要的两个事件是错误设置时和错误清除时。
错误提供程序也真的很难继承。没有有用的东西被声明为虚方法,所以我们无法覆盖。这意味着我们需要大量使用反射。我认为这带来的性能问题微不足道;然而,更大的问题是我们依赖内部实现而不是公共契约。如果他们改变实现,控件就会停止工作。但是,这种情况不太可能发生,如果我们想添加额外功能,这是唯一的方法。
扩展错误提供程序的实现可以分为三个部分——在使用数据绑定时触发事件、在不使用数据绑定时触发事件,以及其余部分。
不使用数据绑定时触发事件
这部分很简单。我们只需为 SetError
和 Clear
声明新方法,调用基类,然后触发事件。不需要反射。当然,问题是,如果它被引用为 Error Provider 并且这些方法被调用,那么事件将不会被调用。
使用数据绑定时触发事件
这要困难得多,并且需要了解错误提供程序的实现方式。错误提供程序有一个名为 errorManager
的字段,类型为 BindingManagerBase
。它处理绑定。我们需要连接到这些事件,然后触发我们自己的事件。要查看此内容,请查看 WireEvents
方法。另一个问题是在何处订阅这些事件。我们希望在 DataSource
和 DataMember
更改时订阅它们,因此我们需要声明这些新方法。
我们面临的一个问题是,如果组件正在初始化,我们必须延迟订阅,直到初始化完成。这部分让我很困扰。错误提供程序实现了 ISupportInitialize
接口。然而,它仍然不是一个虚方法。.NET 为我们提供了一个解决方案。通过指定扩展错误提供程序也实现了 ISupportInitialize
并编写一个 EndInit
方法,我们的 EndInit
将被调用,而不是错误提供程序的。我们还希望在连接事件之前运行基类的 EndInit
;但是,要做到这一点,我们必须使用反射。
其他一些要做的事情
最后一件事情是实现三个属性:ControlsWithErrors
、ErrorCount
和 HasErrors
。它们的实现非常简单,但我们需要对错误提供程序的实现有一点了解。错误提供程序将控件及其错误消息列表保存在一个名为 items
的 Hashtable
中,因此通过使用反射获取此 Hashtable
,我们可以轻松实现这三个属性。
所以,我们现在有了扩展错误提供程序的实现。但是,它有多大用处呢?嗯,当关闭一个窗体时,你可以快速检查上面是否有错误并显示它们。但是,你的业务对象可能已经能够做到这一点了。嗯,你可以使用 ErrorSet
事件在错误出现时闪烁控件。但是,展示扩展错误提供程序如何使用的最佳示例是工具条错误下拉列表。
工具条错误下拉列表
这不仅仅是一个展示扩展错误提供程序的工具,它确实是一个每当你有一个错误提供程序时都想使用的工具。错误提供程序为错误提供了一个不错的 UI,但是如果你有选项卡会发生什么?我的观点是并非所有错误都能一次性可见。工具条错误下拉列表(如果有人能想到更好的名字,我将不胜感激,我想我已经改名了大约五次,但仍然不满意)解决了这个问题。它位于状态栏中,并提供错误的摘要。此外,当你点击一个错误时,它会聚焦该控件并使其闪烁。这使其成为修复错误的一种非常有用的方法。
那么,你如何使用它呢?只需将其添加到状态栏并设置其 ErrorProvider
属性即可!它已准备就绪。
更多有趣的事情
ErrorTerminology
属性用于将消息从“5 errors”更改为“5 warnings”。它允许我们不仅显示错误,还显示警告。
有一个 AutoSort
属性,它按控件 TabIndex
排序。默认情况下它是 false
,因此最新的错误总是出现在底部。还有一个 Sort
方法。在加载后设置初始错误后调用它是一个好主意。
组件上使用的图像是错误提供程序上的图标。
当您点击“Should be Number 1”时,第一个文本框将被选中并闪烁。
对话框
我一直对 Windows 的消息框感到非常失望。它缺少太多有用的功能。很多次,当我收到别人发来的错误消息时,都是消息框的屏幕截图。难道微软真的很难允许文本被选中和复制吗?
另一个问题是,你在消息框中显示多少信息?太多会让用户感到困惑,太少则过于笼统,无法弄清楚发生了什么。而且,找到平衡可能是不可能的。例如,开发人员可能需要堆栈跟踪,但将其作为消息显示给用户什么也说明不了,反而会让他们感到困惑。我为对话框开发的解决方案非常简单。它提供了一条消息和一条扩展消息。扩展消息默认是隐藏的,通过点击“更多详情”显示。
我只使用了一部分图标——错误、信息、警告和问题。我也不允许“无”。在我看来,所有消息都可以归入这四种类型,不添加图标是偷懒,并且提供了更糟糕的界面。消息框的一个问题是这种情况发生得太频繁了,一个主要原因是消息框使得添加图标变得很麻烦。要添加图标,你不仅要指定图标,还要指定按钮(因为按钮参数在图标参数之前)。为了让这更容易,对话框不仅有 Display
方法,还有 DisplayError
、DisplayInformation
和 DisplayQuestion
。
对话框还有一个复制按钮,方便用户复制所有内容。
我最后一个问题是大小。原因有点难解释,但我希望它能调整大小。
对话框还有一个 UseStandardDialogs
变量,可用于改用消息框。
对话框 1:简单,不会让最终用户感到困惑,但没有给我们任何信息,我们也不知道发生了什么。
MessageBox.Show(this, "An unknown error occured",
"Error", MessageBoxButtons.OK,
MessageBoxIcon.Error);
对话框 2:为开发人员提供了有用的信息,帮助他们弄清楚发生了什么。但对于最终用户来说,这毫无意义,他们不应该被迫看到这些。
MessageBox.Show(this, ex.StackTrace, "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
对话框 3、4 和 5:对话框默认显示消息 (Dlg3)。用户可以点击“更多详情”获取更多信息 (Dlg 4)。另请注意,与对话框 2 相比,对话框的形状更美观。如果用户认为这样可以使数据更具可读性,则可以调整对话框大小 (Dlg 4)。
DialogBox.DisplayError(this, "An unknown error has occured", ex.StackTrace);
最终想法
我想为扩展错误提供程序添加一个 ErrorDoubleClick
事件,当错误图标被双击时触发。它将允许我显示一个包含错误的对话框。但是,我不知道该怎么做,而且我有一种感觉这不可能。但是,如果有人知道怎么做并且愿意告诉我,我将不胜感激。
另外,DialogBox
中使用的图标显然来自 Windows Vista。我不确定这适用于哪些版权。如果我不应该使用它们,请告诉我,我会找一些替代品。
最后,如果您要投反对票,请留下反馈好吗?我只是觉得很奇怪,人们会说“我不喜欢这个”,然后不给出理由。如果给出理由,我就可以改进组件。