题
您如何检测您的用户界面?在过去,我读到人们已经对他们的用户界面进行了检测,但我没有找到关于的示例或提示 如何 来检测 UI。
我所说的检测是指收集有关系统使用情况和性能的数据。关于 Instrumentation 的 MSDN 文章是 http://msdn.microsoft.com/en-us/library/x5952w0c.aspx. 。我想捕获用户单击哪些按钮、他们使用哪些键盘快捷键、他们使用哪些术语进行搜索等。
- 您如何检测您的 UI?
- 您存储仪器的格式是什么?
- 您如何处理仪器数据?
- 您如何使用此检测逻辑保持 UI 代码整洁?
具体来说,我正在 WPF 中实现 UI,因此与检测基于 Web 的应用程序相比,这将带来额外的挑战。(IE。需要将检测数据传输回中央位置等)。也就是说,我认为该技术可以通过附加属性等概念提供更简单的检测实现。
- 您是否检测过 WPF 应用程序?您对如何实现这一目标有什么建议吗?
编辑:以下博客文章提出了一个有趣的解决方案: 像素基因博客:WPF 应用程序上的 UI 审核技术
解决方案 4
以下博客文章提供了一些关于检测 WPF 应用程序的好主意:WPF 应用程序上的 UI 审核技术.
其他提示
下面是我如何使用简单的事件管理器来挂钩 UI 事件并提取事件的关键信息的示例,例如 UI 元素的名称和类型、事件名称和父窗口的类型名称。对于列表,我还提取所选项目。
此解决方案仅侦听从 ButtonBase 派生的控件(Button、ToggleButton 等)的单击以及从 Selector 派生的控件(ListBox、TabControl 等)中的选择更改。它应该很容易扩展到其他类型的 UI 元素或实现更细粒度的解决方案。该解决方案的灵感来自于 布拉德·利奇的回答.
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
}
为了进行实际的日志记录,我使用 log4net 并创建了一个名为“Interaction”的单独记录器来记录用户交互。这里的“Log”类只是我自己的 log4net 静态包装器。
/// <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
你可以考虑 日志4网. 。它是一个存在于单个 DLL 中的强大的日志记录框架。它还以“非要求”类型模式完成,因此如果正在进行关键进程,则在资源释放更多之前不会记录。
您可以轻松地设置一堆 INFO 级别记录器并跟踪您所需的所有用户交互,并且不会发生错误崩溃来将文件发送给您自己。然后,您还可以将所有错误和致命代码记录到单独的文件中,该文件可以轻松地邮寄给您进行处理。
如果您使用 WPF 命令,则每个自定义命令都可以记录所采取的操作。您还可以记录启动命令的方式。
也许是 微软用户界面自动化 对于WPF可以帮忙吗?它是一个用于自动化你的 UI 的框架,也许它可以用来为你记录东西......
我们使用自动化框架在 WPF 中自动测试我们的 UI。
免责声明:我为销售该产品的公司工作,不仅如此,我还是该特定产品的开发人员:)。
如果您对提供此功能的商业产品感兴趣,则可以使用 Runtime Intelligence(Dotfuscator 的功能插件)将使用情况跟踪功能注入到您的 .NET 应用程序中。我们不仅提供跟踪功能的实际实现,还提供数据收集、处理和报告功能。
最近,软件商业论坛上有一个关于这个主题的讨论,我也发布在此处: http://discuss.joelonsoftware.com/default.asp?biz.5.680205.26 .
有关我们产品的高级概述,请参见此处: http://www.preemptive.com/runtime-intelligence-services.html .
此外,我目前正在编写一些更面向技术的文档,因为我们意识到这是一个我们绝对可以改进的领域,如果有人有兴趣在我完成后收到通知,请告诉我。