【问题标题】:Logging all button clicks in WinForms app记录 WinForms 应用程序中的所有按钮点击
【发布时间】:2013-07-30 17:44:57
【问题描述】:

我希望为用户单击的每个 WinForms 按钮单击添加一个日志语句,理想情况下,是父窗体的标识符(例如标题栏)。我看过记录所有鼠标点击的帖子,但我只对记录按钮点击感兴趣。我已阅读接受的答案here 并对其进行了修改:

public class ButtonLogger
{
    private static readonly ILog Logger = LogManager.GetLogger(typeof(ButtonLogger));
    public static void AttachButtonLogging(Control.ControlCollection controls)
    {
        foreach (var button in controls.OfType<Button>())
        {
            button.Click += LogButtonClick;
        }
    }
    private static void LogButtonClick(object sender, EventArgs eventArgs)
    {
        Button button = sender as Button;
        Logger.InfoFormat("Button clicked: {0} ({1})", button.Text, button.Parent.Text);
    }
}

这个类用在构造函数的末尾,例如: :

ButtonLogger.AttachButtonLogging(this.Controls);

我面临的问题是 Controls 属性似乎没有对我的按钮的引用。这可能是因为按钮没有直接添加到表单中,而是添加到 Controls 属性中的另一个控件。但是,Controls 属性只包含一个控件,即 ToolStrip。

有没有一种方法可以利用表单上的所有按钮,而不管它们的父容器是什么?我的最终目标是在我的按钮中添加一个日志语句,所以如果除了按钮单击事件方法之外还可以通过其他方式完成,那么我也愿意这样做

【问题讨论】:

    标签: c# winforms button logging


    【解决方案1】:

    我相信你需要递归搜索按钮:

    public static void AttachButtonLogging(Control.ControlCollection controls)
    {
        foreach (var control in controls.Cast<Control>())
        {
            if (control is Button)
            {
               Button button = (Button)control;
               button.Click += LogButtonClick;
            }
            else
            {
                AttachButtonLogging(control.Controls);
            }
        }
    }
    

    【讨论】:

    • 有一种情况,我们在一些TabPage上有一个TabControl和一些Buttons,我们必须查看TabControl.TabPages。我遇到过这个问题,但是如果不是 OP 的情况,这段代码可以正常工作。
    • @KingKing 谢谢,很好的说明。坦率地说,我认为标签页会出现在 TabControl 的控件中。奇怪的设计!
    • 这是否会在构建表单时导致任何性能问题?虽然这是递归,但它应该很轻,因为特定表单上有少量控件(最多可能 20 个)。此外,由于这些是在“真实”事件附加到按钮之后附加的,因此它不应该延迟您希望在单击按钮时发生的实际处理。
    • @StealthRabbi 我认为这不会造成明显的延迟。我认为可以在此处进行一些改进(即避免为每个控件初始化控件集合),但您应该尝试一下 - 也许一切都可以
    • 你能想出什么方法可以优先“真实”事件之前?这种在真实事件之后记录的方法有几个问题:首先,如果按钮单击打开了一个模态对话框,然后该对话框中的某些操作导致应用程序崩溃,则永远不会记录单击(使其看起来好像崩溃来自父母)。同样,模态对话框中的单击将出现在父级单击之前,即无序。最后,如果按钮单击关闭父对话框,则 button.Parent 将为 null。
    【解决方案2】:

    您可以考虑的一件事是创建标准Button 类的子类,并让按钮自己进行日志记录。当然,您必须四处走动,将应用程序中的所有按钮替换为您自己的实现,但应该可以通过全局搜索+替换来做到这一点。

    这是一个示例实现:

    public class LoggerButton : Button
    {
        private static readonly ILog Logger = LogManager.GetLogger(typeof(LoggerButton));
    
        protected override void OnClick(EventArgs e)
        {
            base.OnClick(e);
            Logger.InfoFormat("Button clicked: {0} ({1})", this.Text, this.Parent.Text);
        }
    }
    

    【讨论】:

    • 这对设计师来说也更具挑战性。您必须创建一个自定义工具箱调色板并使用自定义按钮类而不是内置按钮类。虽然这是一个肯定的选择,但可能有点滥用继承。
    • @StealthRabbi 真的吗?我从来不需要做任何特别的事情来让我的自定义控件显示在 Visual Studio 工具箱中。但是,是的,我同意这有点 hacky。
    猜你喜欢
    • 2014-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-20
    相关资源
    最近更新 更多