Wpf 检测UI

Wpf 检测UI,wpf,user-interface,instrumentation,Wpf,User Interface,Instrumentation,你是如何检测你的用户界面的?在过去,我曾读到人们对他们的用户界面进行了检测,但我没有找到关于如何对UI进行检测的示例或提示 通过检测,我的意思是收集有关系统使用和性能的数据。MSDN中有一篇关于仪器的文章。我想捕获用户点击的按钮、他们使用的键盘快捷键、他们搜索时使用的术语等等 你是如何检测你的用户界面的 您存储仪器的格式是什么 您是如何处理检测数据的 如何使用这种检测逻辑保持UI代码的干净 具体地说,我是在WPF中实现我的UI的,因此这将比使用基于web的应用程序提供额外的挑战。(即,需要将

你是如何检测你的用户界面的?在过去,我曾读到人们对他们的用户界面进行了检测,但我没有找到关于如何对UI进行检测的示例或提示

通过检测,我的意思是收集有关系统使用和性能的数据。MSDN中有一篇关于仪器的文章。我想捕获用户点击的按钮、他们使用的键盘快捷键、他们搜索时使用的术语等等

  • 你是如何检测你的用户界面的
  • 您存储仪器的格式是什么
  • 您是如何处理检测数据的
  • 如何使用这种检测逻辑保持UI代码的干净
具体地说,我是在WPF中实现我的UI的,因此这将比使用基于web的应用程序提供额外的挑战。(即,需要将仪表化数据传输回中心位置等)。这就是说,我觉得这项技术可以通过附加属性等概念更容易地实现检测

  • 您是否检测了WPF应用程序?你对如何实现这一目标有什么建议吗


编辑:下面的博文提供了一个有趣的解决方案:

我还没有使用WPF开发。。但是我假设它与大多数其他应用程序一样,您希望使UI代码尽可能轻。。在这种情况下,可以使用许多设计模式,例如显而易见的和不确定的模式。我个人总是尽量使在UI和BL层之间移动的对象尽可能轻,如果可以的话,尽量使它们保持原语

然后,这有助于我专注于改进UI层,而不必担心一旦我抛出(原始)数据后会发生什么

希望我能正确地理解你的问题,很抱歉我不能给WPF提供更多的上下文帮助。

< P>你可以考虑。它是一个健壮的日志框架,存在于单个DLL中。它也是在“非要求”类型的模式下完成的,这样,如果关键流程正在进行,它将不会记录日志,直到资源释放多一点


您可以轻松地设置一组信息级记录器,并跟踪所需的所有用户交互,并且不需要bug崩溃就可以将文件发送给您自己。然后,您还可以将所有错误和致命代码记录到单独的文件中,该文件可以轻松地邮寄给您进行处理。

如果使用WPF命令,则每个自定义命令都可以记录所采取的操作。您还可以记录命令的启动方式。

也许for WPF可以提供帮助?它是一个自动化用户界面的框架,也许可以用来为你记录东西


我们使用自动化框架在WPF中自动测试我们的UI。

以下博客文章提供了许多用于检测WPF应用程序的好主意:
.

免责声明:我为销售此产品的公司工作,不仅如此,我还是此特定产品的开发人员:)

如果您对提供此功能的商业产品感兴趣,则可以使用运行时智能(Dotfuscator的功能性附加组件),将使用情况跟踪功能注入到您的.NET应用程序中。我们不仅提供跟踪功能的实际实现,还提供数据收集、处理和报告功能

最近有一个关于软件商业论坛的讨论,我也在这里发布了

有关我们产品的高级概述,请参见此处:


此外,我目前正在编写一些技术性更强的文档,因为我们意识到这是一个我们绝对可以改进的领域,请告诉我是否有人希望在我完成后收到通知。

下面是一个示例,说明我如何使用简单的事件管理器连接到UI事件并提取事件的关键信息,例如UI元素的名称和类型、事件的名称和父窗口的类型名称。对于列表,我还提取所选项目

此解决方案仅侦听从ButtonBase派生的控件(Button,ToggleButton,…)的单击以及从Selector派生的控件(ListBox,TabControl,…)中的选择更改。它应该很容易扩展到其他类型的UI元素,或者实现更细粒度的解决方案。这一解决方案是受以下因素启发而提出的

公共类UserInteractionEventsManager
{
公共委托无效按钮ClickedHandler(日期时间、字符串事件名称、字符串发送者名称、字符串发送者类型名称、字符串父窗口名称);
公共委托无效选择器SelectedHandler(日期时间、字符串事件名称、字符串发送者名称、字符串发送者类型名称、字符串parentWindowName、对象selectedObject);
公共事件按钮ClickedHandler按钮Clicked;
公共事件选择器Selected处理程序选择器Selected;
公共用户InteractionEventsManager()
{

RegisterClassHandler(typeof(ButtonBase)、ButtonBase.ClickEvent、new RoutedEventHandler(HandleButtonClicked));
EventManager.RegisterClassHandler(typeof(Selector)、Selector.SelectionChangedEvent、new RoutedEventHandler(HandleSelectorSelected)); } #区域处理事件 private void HandleSelector Selector(对象发送方,路由目标e) { //避免由于冒泡而发生多个事件。例如:TabControl中的列表框将导致两者都发送SelectionChangedEvent。 如果(发送方!=e.OriginalSource)返回; var args=e作为selectionchangedventargs; if(args==null | | args.AddedItems.Count==0)返回; var element=发送方作为框架元素; if(element==null)返回; 字符串senderName=GetSenderName(元素); 字符串parentWindowName=GetParentWindowTypeName(发件人); DateTime=DateTime.Now; 字符串eventName=e.RoutedEvent.Name; 字符串senderTypeName=sender.GetType().Name; 字符串selectedItemText=args.AddedItems.con
public class UserInteractionEventsManager
{
    public delegate void ButtonClickedHandler(DateTime time, string eventName, string senderName, string senderTypeName, string parentWindowName);
    public delegate void SelectorSelectedHandler(DateTime time, string eventName, string senderName, string senderTypeName, string parentWindowName, object selectedObject);

    public event ButtonClickedHandler ButtonClicked;
    public event SelectorSelectedHandler SelectorSelected;

    public UserInteractionEventsManager()
    {
        EventManager.RegisterClassHandler(typeof(ButtonBase), ButtonBase.ClickEvent, new RoutedEventHandler(HandleButtonClicked));
        EventManager.RegisterClassHandler(typeof(Selector), Selector.SelectionChangedEvent, new RoutedEventHandler(HandleSelectorSelected));
    }

    #region Handling events

    private void HandleSelectorSelected(object sender, RoutedEventArgs e)
    {
        // Avoid multiple events due to bubbling. Example: A ListBox inside a TabControl will cause both to send the SelectionChangedEvent.
        if (sender != e.OriginalSource) return;

        var args = e as SelectionChangedEventArgs;
        if (args == null || args.AddedItems.Count == 0) return;

        var element = sender as FrameworkElement;
        if (element == null) return;

        string senderName = GetSenderName(element);
        string parentWindowName = GetParentWindowTypeName(sender);
        DateTime time = DateTime.Now;
        string eventName = e.RoutedEvent.Name;
        string senderTypeName = sender.GetType().Name;
        string selectedItemText = args.AddedItems.Count > 0 ? args.AddedItems[0].ToString() : "<no selected items>";

        if (SelectorSelected != null)
            SelectorSelected(time, eventName, senderName, senderTypeName, parentWindowName, selectedItemText);
    }

    private void HandleButtonClicked(object sender, RoutedEventArgs e)
    {
        var element = sender as FrameworkElement;
        if (element == null) return;

        string parentWindowName = GetParentWindowTypeName(sender);
        DateTime time = DateTime.Now;
        string eventName = e.RoutedEvent.Name;
        string senderTypeName = sender.GetType().Name;
        string senderName = GetSenderName(element);

        if (ButtonClicked != null) 
            ButtonClicked(time, eventName, senderName, senderTypeName, parentWindowName);
    }

    #endregion

    #region Private helpers

    private static string GetSenderName(FrameworkElement element)
    {
        return !String.IsNullOrEmpty(element.Name) ? element.Name : "<no item name>";
    }


    private static string GetParentWindowTypeName(object sender)
    {
        var parent = FindParent<Window>(sender as DependencyObject);
        return parent != null ? parent.GetType().Name : "<no parent>";
    }

    private static T FindParent<T>(DependencyObject item) where T : class
    {
        if (item == null) 
            return default(T);

        if (item is T)
            return item as T;

        DependencyObject parent = VisualTreeHelper.GetParent(item);
        if (parent == null)
            return default(T);

        return FindParent<T>(parent);
    }

    #endregion
}
/// <summary>
/// The user interaction logger uses <see cref="UserInteractionEventsManager"/> to listen for events on GUI elements, such as buttons, list boxes, tab controls etc.
/// The events are then logged in a readable format using Log.Interaction.Info().
/// </summary>
public class UserInteractionLogger
{
    private readonly UserInteractionEventsManager _events;
    private bool _started;

    /// <summary>
    /// Create a user interaction logger. Remember to Start() it.
    /// </summary>
    public UserInteractionLogger()
    {
        _events = new UserInteractionEventsManager();

    }

    /// <summary>
    /// Start logging user interaction events.
    /// </summary>
    public void Start()
    {
        if (_started) return;

        _events.ButtonClicked += ButtonClicked;
        _events.SelectorSelected += SelectorSelected;

        _started = true;
    }

    /// <summary>
    /// Stop logging user interaction events.
    /// </summary>
    public void Stop()
    {
        if (!_started) return;

        _events.ButtonClicked -= ButtonClicked;
        _events.SelectorSelected -= SelectorSelected;

        _started = false;
    }

    private static void SelectorSelected(DateTime time, string eventName, string senderName, string senderTypeName, string parentWindowTypeName, object selectedObject)
    {
        Log.Interaction.Info("{0}.{1} by {2} in {3}. Selected: {4}", senderTypeName, eventName, senderName, parentWindowTypeName, selectedObject);
    }

    private static void ButtonClicked(DateTime time, string eventName, string senderName, string senderTypeName, string parentWindowTypeName)
    {
        Log.Interaction.Info("{0}.{1} by {2} in {3}", senderTypeName, eventName, senderName, parentWindowTypeName);
    }
}
04/13 08:38:37.069 INFO Iact ToggleButton.Click by AnalysisButton in MyMainWindow 04/13 08:38:38.493 INFO Iact ListBox.SelectionChanged by ListView in MyMainWindow. Selected: Andreas Larsen 04/13 08:38:44.587 INFO Iact Button.Click by EditEntryButton in MyMainWindow 04/13 08:38:46.068 INFO Iact Button.Click by OkButton in EditEntryDialog 04/13 08:38:47.395 INFO Iact ToggleButton.Click by ExitButton in MyMainWindow