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

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

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

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

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

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

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

11.08.2008 21:00:40
7 ОТВЕТОВ

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

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

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

-1
11.08.2008 21:21:31

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

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

2
11.08.2008 23:02:48

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

2
12.08.2008 04:38:19

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

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

0
12.08.2008 11:31:13
РЕШЕНИЕ

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

3
10.03.2017 21:37:11
EventManager.RegisterClassHandler действительно справился с задачей, когда мне нужно было вести некоторые журналы взаимодействия для нажатия кнопок, выбора списков и т. Д. Очень мало кода требуется для подключения к необходимым событиям для всего графического интерфейса.
angularsen 11.04.2011 07:08:29
Я просто хотел , чтобы обеспечить связь , которая работала для меня: blog.pixelingene.com/2008/08/...
Cyrus Downey 20.10.2015 17:55:35

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

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

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

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

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

0
2.10.2008 21:17:23

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

Это решение прослушивает только щелчки элементов управления, полученных из 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 и создал отдельный регистратор с именем «Взаимодействие» для регистрации взаимодействия с пользователем. Класс '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);
    }
}

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

13.04.08: 38: 37.069 ИНФОРМАЦИЯ Iact ToggleButton.Нажмите кнопку AnalysisButton в MyMainWindow
13.04.8: 38: 38.493 ИНФОРМАЦИЯ Iact ListBox.SelectionChanged ListView в MyMainWindow. Избранное: Андреас Ларсен
13.04.08: 38.54.587 ИНФОРМАЦИЯ Кнопка Iact.Нажмите EditEntryButton в MyMainWindow
13.04.08: 38: 46.068 ИНФОРМАЦИЯ Кнопка Iact.Нажмите OkButton в EditEntryDialog
13.04.8: 38: 47.395 ИНФОРМАЦИЯ Iact ToggleButton.Нажмите ExitButton в MyMainWindow
4
23.05.2017 10:30:04