Инструментирование пользовательского интерфейса

StackOverflow https://stackoverflow.com/questions/8214

Вопрос

Как вы настраиваете свой пользовательский интерфейс?В прошлом я читал, что люди инструментировали свои пользовательские интерфейсы, но чего я не нашел, так это примеров или советов по как для настройки пользовательского интерфейса.

Под инструментированием я подразумеваю сбор данных об использовании и производительности системы.Статья MSDN об инструментовке - это http://msdn.microsoft.com/en-us/library/x5952w0c.aspx.Я хотел бы зафиксировать, на какие кнопки нажимают пользователи, какие сочетания клавиш они используют, какие термины они используют для поиска и т.д.

  • Как вы настраиваете свой пользовательский интерфейс?
  • В каком формате вы храните инструментарий?
  • Как вы обрабатываете инструментальные данные?
  • Как вы поддерживаете чистоту своего пользовательского интерфейса с помощью этой инструментальной логики?

В частности, я реализую свой пользовательский интерфейс в WPF, так что это создаст дополнительные проблемы по сравнению с инструментированием веб-приложения.(т.е.необходимо перенести измеренные данные обратно в центральное местоположение и т.д.).Тем не менее, я чувствую, что технология может обеспечить более простую реализацию инструментария с помощью таких концепций, как прикрепленные свойства.

  • Вы инструментировали приложение WPF?Есть ли у вас какие-либо советы о том, как этого можно достичь?

Редактировать:В следующем сообщении в блоге представлено интересное решение: Блог Pixel-In-Gene:Методы аудита пользовательского интерфейса в приложениях WPF

Это было полезно?

Решение 4

В следующем сообщении в блоге приводится немало хороших идей по инструментированию приложения WPF:Методы аудита пользовательского интерфейса в приложениях WPF.

Другие советы

Вот пример того, как я использую простой менеджер событий для подключения к событиям пользовательского интерфейса и извлечения ключевой информации о событиях, такой как имя и тип элемента пользовательского интерфейса, название события и имя типа родительского окна.Для списков я также извлекаю выбранный элемент.

Это решение прослушивает только щелчки элементов управления, полученных из ButtonBase (Button, ToggleButton, ...), и изменения выбора в элементах управления, полученных из Selector (ListBox, TabControl, ...).Его должно быть легко распространить на другие типы элементов пользовательского интерфейса или добиться более детального решения.Это решение вдохновлено Ответ Брэда Лича.

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

Вы могли бы рассмотреть log4net.Это надежная платформа ведения журнала, которая существует в одной библиотеке DLL.Это также выполняется в режиме "нетребовательного" типа, так что, если выполняется критический процесс, он не будет регистрироваться до тех пор, пока ресурсы не будут освобождены еще немного.

Вы могли бы легко настроить кучу регистраторов информационного уровня и отслеживать все необходимые вам взаимодействия с пользователем, и не потребовалось бы сбоя из-за ошибки, чтобы отправить файл самому себе.Затем вы также можете записать все свои ОШИБКИ и ФАТАЛЬНЫЙ код в отдельный файл, который можно легко отправить вам по почте для обработки.

Если вы используете команды WPF, каждая пользовательская команда может затем регистрировать выполненные действия.Вы также можете записать в журнал способ, которым была инициирована команда.

Возможно, тот Автоматизация пользовательского интерфейса Microsoft ибо WPF может чем-то помочь?Это фреймворк для автоматизации вашего пользовательского интерфейса, возможно, его можно использовать для ведения журнала за вас...

Мы используем платформу автоматизации для автоматического тестирования нашего пользовательского интерфейса в WPF.

Отказ от ответственности:Я работаю в компании, которая продает этот продукт, и не только это, но я являюсь разработчиком этого конкретного продукта :) .

Если вы заинтересованы в коммерческом продукте, обеспечивающем это, тогда Runtime Intelligence (функциональное дополнение к Dotfuscator), которое внедряет в ваши приложения функцию отслеживания использования .Доступны NET applications.Мы обеспечиваем не только фактическую реализацию функциональности отслеживания, но и сбор, обработку данных и создание отчетов.

Недавно на форуме Business of Software состоялась дискуссия на эту тему, которую я также опубликовал в разделе, расположенном здесь: http://discuss .joelonsoftware.com/default.asp?biz.5.680205.26 .

Подробный обзор наших материалов смотрите здесь: http://www.preemptive.com/runtime-intelligence-services.html .

Кроме того, в настоящее время я работаю над написанием более технически ориентированной документации, поскольку мы понимаем, что это область, которую мы определенно могли бы улучшить, пожалуйста, дайте мне знать, если кто-нибудь заинтересован в том, чтобы его уведомили, когда я ее завершу.

Я еще не разрабатывал с использованием WPF..Но я бы предположил, что это то же самое, что и в большинстве других приложений, в том смысле, что вы хотите сохранить код пользовательского интерфейса как можно более легким..При этом может быть использован ряд шаблонов проектирования, таких как очевидный MVC и Façade.Лично я всегда стараюсь, чтобы объекты, перемещающиеся между слоями пользовательского интерфейса и BL, были как можно более легкими, по возможности сводя их к примитивам.

Затем это помогает мне сосредоточиться на улучшении уровня пользовательского интерфейса, не беспокоясь о том, что что-то произойдет, как только я верну свои (примитивные) данные обратно..

Надеюсь, я правильно понял ваш вопрос, и сожалею, что не могу предложить более подробную контекстуальную помощь с WPF.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top