代码之家  ›  专栏  ›  技术社区  ›  codekaizen

是否有任何工具/库(.Net/WPF)来度量和存储UI导航数据以供分析?

  •  18
  • codekaizen  · 技术社区  · 14 年前

    我想测量和分析用户在UI中的移动和手势,以改善应用程序的用户体验。我曾设想功能跟踪库(比如EQATEC或Preemptive的运行时智能)会允许这样做。然而,情况似乎并非如此。

    我的搜索结果是空的。OSS或商业存在吗?

    5 回复  |  直到 14 年前
        1
  •  6
  •   Sanjeevakumar Hiremath    12 年前
    1. 下载 Sources Version 2 从这个 article on code project
    2. Gma.UserActivityMonitor 投射并盲目地将其转换为.NET 4.0
    3. HookManager.Callbacks.cs 文件进行以下更改。

      1. 添加 using System.Diagnostics;
      2. s_MouseHookHandle = SetWindowsHookEx(
            WH_MOUSE_LL,
            s_MouseDelegate,
            Marshal.GetHINSTANCE(
                Assembly.GetExecutingAssembly().GetModules()[0]),
            0);
        

        using (Process curProcess = Process.GetCurrentProcess())
        using (ProcessModule curModule = curProcess.MainModule)
        {
            s_MouseHookHandle = SetWindowsHookEx(
                WH_MOUSE_LL,
                s_MouseDelegate,
               GetModuleHandle(curModule.ModuleName), 0);
        }
        
      3. 替换

        s_KeyboardHookHandle = SetWindowsHookEx(
            WH_KEYBOARD_LL,
            s_KeyboardDelegate,
            Marshal.GetHINSTANCE(
                Assembly.GetExecutingAssembly().GetModules()[0]),
            0);
        

        using (Process curProcess = Process.GetCurrentProcess())
        using (ProcessModule curModule = curProcess.MainModule)
        {
            s_KeyboardHookHandle = SetWindowsHookEx(
            WH_KEYBOARD_LL,
            s_KeyboardDelegate, 
            GetModuleHandle(curModule.ModuleName), 0);
        }
        
    4. HookManager.Windows.cs 在中的任意位置添加以下两行 HookManager

      [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
      public static extern IntPtr GetModuleHandle(string lpModuleName);
      
    5. 现在你应该可以建立这个并把它放在一边。现在开始WPF部分。

    6. WPFA应用程序1 在步骤1-5中生成的项目/程序集 System.Windows.Forms系统 .
    7. 现在替换 MainWindow.xaml 使用下面的XAML确保检查类名和项目名,我刚刚创建了WpfApplication1进行测试。

      <Window x:Class="WpfApplication1.MainWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              Title="MainWindow" Height="350" Width="525">
          <Grid>
              <Grid.RowDefinitions>
                  <RowDefinition Height="0.30*"/>
                  <RowDefinition Height="0.70*"/>
              </Grid.RowDefinitions>
              <StackPanel Grid.Row="0" Orientation="Horizontal">
                  <StackPanel Orientation="Vertical">
                      <CheckBox Name="MouseMove" Padding="5" Content="Mouse Move" Width="120" Height="30" Click="checkBoxOnMouseMove_CheckedChanged"/>
                      <CheckBox Name="MouseClick" Padding="5" Content="Mouse Click" Width="120" Height="30" Click="checkBoxOnMouseClick_CheckedChanged"/>
                      <CheckBox Name="MouseDown" Padding="5" Content="Mouse Down" Width="120" Height="30" Click="checkBoxOnMouseDown_CheckedChanged"/>
                  </StackPanel>
                  <StackPanel Orientation="Vertical">
                      <CheckBox Name="MouseUp" Padding="5" Content="Mouse Up" Width="120" Height="30" Click="checkBoxOnMouseUp_CheckedChanged"/>
                      <CheckBox Name="MouseDouble" Padding="5" Content="Mouse Double" Width="120" Height="30" Click="checkBoxMouseDoubleClick_CheckedChanged"/>
                      <CheckBox Name="MouseWheel" Padding="5" Content="Mouse Wheel" Width="120" Height="30" Click="checkBoxMouseWheel_CheckedChanged"/>
                  </StackPanel>
                  <StackPanel Orientation="Vertical">
                      <CheckBox Name="KeyDown" Padding="5" Content="Key Down" Width="120" Height="30" Click="checkBoxKeyDown_CheckedChanged"/>
                      <CheckBox Name="KeyPress" Padding="5" Content="Key Press" Width="120" Height="30" Click="checkBoxKeyPress_CheckedChanged"/>
                      <CheckBox Name="KeyUp" Padding="5" Content="Key Up" Width="120" Height="30" Click="checkBoxKeyUp_CheckedChanged"/>
                  </StackPanel>
                  <StackPanel Orientation="Vertical">
                      <TextBlock Name="labelMousePosition" Text="x={0:####}; y={1:####}"/>
                      <TextBlock Name="labelWheel" Text="Wheel={0:####}"/>
                  </StackPanel>
              </StackPanel>
              <TextBlock Name="textBoxLog" Text="START" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Visible"/>
          </Grid>
      </Window>
      
    8. 现在将以下代码添加到MainWindow类定义的MainWindow.xaml.cs文件中。

      #region Check boxes to set or remove particular event handlers.
      
      private void checkBoxOnMouseMove_CheckedChanged(object sender, EventArgs e)
      {
          if ((bool)MouseMove.IsChecked)
          {
              HookManager.MouseMove += HookManager_MouseMove;
          }
          else
          {
              HookManager.MouseMove -= HookManager_MouseMove;
          }
      }
      
      private void checkBoxOnMouseClick_CheckedChanged(object sender, EventArgs e)
      {
          if ((bool)MouseClick.IsChecked)
          {
              HookManager.MouseClick += HookManager_MouseClick;
          }
          else
          {
              HookManager.MouseClick -= HookManager_MouseClick;
          }
      }
      
      private void checkBoxOnMouseUp_CheckedChanged(object sender, EventArgs e)
      {
          if ((bool)MouseUp.IsChecked)
          {
              HookManager.MouseUp += HookManager_MouseUp;
          }
          else
          {
              HookManager.MouseUp -= HookManager_MouseUp;
          }
      }
      
      private void checkBoxOnMouseDown_CheckedChanged(object sender, EventArgs e)
      {
          if ((bool)MouseDown.IsChecked)
          {
              HookManager.MouseDown += HookManager_MouseDown;
          }
          else
          {
              HookManager.MouseDown -= HookManager_MouseDown;
          }
      }
      
      private void checkBoxMouseDoubleClick_CheckedChanged(object sender, EventArgs e)
      {
          if ((bool)this.MouseDouble.IsChecked)
          {
              HookManager.MouseDoubleClick += HookManager_MouseDoubleClick;
          }
          else
          {
              HookManager.MouseDoubleClick -= HookManager_MouseDoubleClick;
          }
      }
      
      private void checkBoxMouseWheel_CheckedChanged(object sender, EventArgs e)
      {
          if ((bool)MouseWheel.IsChecked)
          {
              HookManager.MouseWheel += HookManager_MouseWheel;
          }
          else
          {
              HookManager.MouseWheel -= HookManager_MouseWheel;
          }
      }
      
      private void checkBoxKeyDown_CheckedChanged(object sender, EventArgs e)
      {
          if ((bool)KeyDown.IsChecked)
          {
              HookManager.KeyDown += HookManager_KeyDown;
          }
          else
          {
              HookManager.KeyDown -= HookManager_KeyDown;
          }
      }
      
      
      private void checkBoxKeyUp_CheckedChanged(object sender, EventArgs e)
      {
          if ((bool)KeyUp.IsChecked)
          {
              HookManager.KeyUp += HookManager_KeyUp;
          }
          else
          {
              HookManager.KeyUp -= HookManager_KeyUp;
          }
      }
      
      private void checkBoxKeyPress_CheckedChanged(object sender, EventArgs e)
      {
          if ((bool)KeyPress.IsChecked)
          {
              HookManager.KeyPress += HookManager_KeyPress;
          }
          else
          {
              HookManager.KeyPress -= HookManager_KeyPress;
          }
      }
      
      #endregion
      
      //##################################################################
      #region Event handlers of particular events. They will be activated when an appropriate check box is checked.
      
      private void HookManager_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
      {
          textBoxLog.Text += (string.Format("KeyDown - {0}\n", e.KeyCode));
      
      }
      
      private void HookManager_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
      {
          textBoxLog.Text += (string.Format("KeyUp - {0}\n", e.KeyCode));
      
      }
      
      
      private void HookManager_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
      {
          textBoxLog.Text += (string.Format("KeyPress - {0}\n", e.KeyChar));
      
      }
      
      
      private void HookManager_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
      {
          labelMousePosition.Text = string.Format("x={0:0000}; y={1:0000}", e.X, e.Y);
      }
      
      private void HookManager_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
      {
          textBoxLog.Text += (string.Format("MouseClick - {0}\n", e.Button));
      
      }
      
      
      private void HookManager_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
      {
          textBoxLog.Text += (string.Format("MouseUp - {0}\n", e.Button));
      
      }
      
      
      private void HookManager_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
      {
          textBoxLog.Text += (string.Format("MouseDown - {0}\n", e.Button));
      
      }
      
      
      private void HookManager_MouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)
      {
          textBoxLog.Text += (string.Format("MouseDoubleClick - {0}\n", e.Button));
      
      }
      
      
      private void HookManager_MouseWheel(object sender, System.Windows.Forms.MouseEventArgs e)
      {
          labelWheel.Text = string.Format("Wheel={0:000}", e.Delta);
      }
      
      #endregion
      

    using Gma.UserActivityMonitor; 主窗口中的指令。

    所有的功劳都归于 George Mamaladze

    11.我刚刚做了一些小的改动,使之与WPF一起工作。感谢您关注这篇长文章,我不知道如何共享这段代码,这就是为什么提供这样的指令。

    12岁。 我真的很不擅长格式化代码,所以,有人能对如何格式化代码留下评论吗,XML很好。 也有人帮我格式化这篇文章的片段。谢谢您。

        2
  •  2
  •   Community CDub    8 年前

    UIAutomation Events ETW for WPF

    下面是一个示例:

    private Int32 _eventCount;
    
    public MainWindow()
    {
        InitializeComponent();
        EventManager.RegisterClassHandler(typeof(UIElement), MouseEnterEvent, (RoutedEventHandler)handleEvent, true);
        EventManager.RegisterClassHandler(typeof(UIElement), MouseLeaveEvent, (RoutedEventHandler)handleEvent, true);
        EventManager.RegisterClassHandler(typeof(UIElement), MouseMoveEvent, (RoutedEventHandler)handleEvent, true);
        EventManager.RegisterClassHandler(typeof(UIElement), MouseUpEvent, (RoutedEventHandler)handleEvent, true);
        EventManager.RegisterClassHandler(typeof(UIElement), MouseDownEvent, (RoutedEventHandler)handleEvent, true);
        EventManager.RegisterClassHandler(typeof(UIElement), KeyUpEvent, (RoutedEventHandler)handleEvent, true);
        EventManager.RegisterClassHandler(typeof(UIElement), KeyDownEvent, (RoutedEventHandler)handleEvent, true);
    }
    
    private void handleEvent(object sender, RoutedEventArgs e)
    {
        var uiElement = e.Source as UIElement;
    
        if (uiElement == null)
        {
            return;
        }
    
        EventStatusDisplay.Text = e.Source + " " + e.RoutedEvent.Name;
        EventCountDisplay.Text = (++_eventCount).ToString();
        var over = Mouse.DirectlyOver as UIElement;
        MouseIsOverDisplay.Text = over == null ? "" : over.ToString();
    }
    

    虽然这里没有显示,但一旦我得到 UIElement 我执行日志记录,甚至可以使用 UIElement.DataContext 要确定驱动视图的ViewModel的状态,以便我们可以在某些工作流、数据状态以及可视状态期间找到使用模式。然后我们可以得到关于这个的报告,以及通过工作流和数据值的路径来区分和比较我们的热图。

        4
  •  1
  •   LLucasAlday    14 年前

    尝试 http://iographica.com 它在鼠标光标移动的地方创建线,在鼠标光标停止的地方创建圆,圆越大,在那里停止的时间越长。

        5
  •  1
  •   Markus Hütter    14 年前

    Snoop 更像是一个检查WPF应用程序的可视化树的工具,但它也捕获事件(特别是它捕获这些事件的信息,包括它们发生的元素、它们在可视化树中的移动方式以及它们被处理的位置)。由于它是开源的,所以您可能需要提取有关跟踪事件的部分,并将此信息记录到您的需要中。

    推荐文章