Domanda

Come stai strumentando la tua interfaccia utente?In passato ho letto che le persone hanno strumentato le proprie interfacce utente, ma quello che non ho trovato sono esempi o suggerimenti su Come per strumentare un'interfaccia utente.

Per strumentazione intendo la raccolta di dati relativi all'utilizzo e alle prestazioni del sistema.Un articolo MSDN sulla strumentazione è http://msdn.microsoft.com/en-us/library/x5952w0c.aspx.Vorrei catturare su quali pulsanti fanno clic gli utenti, quali scorciatoie da tastiera utilizzano, quali termini utilizzano per effettuare la ricerca, ecc.

  • Come stai strumentando la tua interfaccia utente?
  • In che formato conservi la strumentazione?
  • Come stai elaborando i dati strumentati?
  • Come mantieni pulito il codice dell'interfaccia utente con questa logica di strumentazione?

Nello specifico, sto implementando la mia interfaccia utente in WPF, quindi ciò fornirà ulteriori sfide rispetto alla strumentazione di un'applicazione basata sul Web.(cioè.necessità di trasferire nuovamente i dati strumentati in una posizione centrale, ecc.).Detto questo, ritengo che la tecnologia possa fornire un'implementazione più semplice della strumentazione tramite concetti come le proprietà allegate.

  • Hai strumentato un'applicazione WPF?Avete qualche consiglio su come raggiungere questo obiettivo?

Modificare:Il seguente post del blog presenta una soluzione interessante: Blog Pixel-In-Gene:Tecniche per il controllo dell'interfaccia utente nelle app WPF

È stato utile?

Soluzione 4

Il seguente post di blog fornisce alcune buone idee per la strumentazione di un'applicazione WPF:Tecniche per il controllo dell'interfaccia utente nelle app WPF.

Altri suggerimenti

Ecco un esempio di come utilizzo un semplice gestore di eventi per collegarmi agli eventi dell'interfaccia utente ed estrarre le informazioni chiave degli eventi, come nome e tipo dell'elemento dell'interfaccia utente, nome dell'evento e nome del tipo della finestra principale.Per gli elenchi estraggo anche l'elemento selezionato.

Questa soluzione ascolta solo i clic dei controlli derivati ​​da ButtonBase (Button, ToggleButton, ...) e le modifiche alla selezione nei controlli derivati ​​da Selector (ListBox, TabControl, ...).Dovrebbe essere facile estenderlo ad altri tipi di elementi dell'interfaccia utente o ottenere una soluzione più dettagliata.La soluzione è ispirata a La risposta di Brad Leach.

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
}

E per eseguire la registrazione vera e propria, utilizzo log4net e ho creato un logger separato denominato "Interazione" per registrare l'interazione dell'utente.La classe "Log" qui è semplicemente il mio wrapper statico per 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);
    }
}

L'output sarebbe quindi simile a questo, omettendo voci di registro non rilevanti.

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

Potresti considerare log4net.Si tratta di un robusto framework di registrazione che esiste in una singola DLL.Viene eseguito anche in una modalità di tipo "non impegnativo" in modo che, se è in corso un processo critico, non verrà registrato finché le risorse non verranno liberate un po' di più.

Potresti facilmente impostare una serie di logger di livello INFO e tenere traccia di tutte le interazioni dell'utente di cui hai bisogno, e non ci vorrebbe un crash di bug per inviare il file a te stesso.Potresti anche registrare tutti i tuoi codici ERRORE e IRREVERSIBILE in un file separato che potrebbe essere facilmente inviato per posta per l'elaborazione.

Se si utilizzano comandi WPF, ogni comando personalizzato potrebbe quindi registrare l'azione eseguita.Puoi anche registrare il modo in cui è stato avviato il comando.

Forse il Automazione dell'interfaccia utente Microsoft per WPF puoi dare una mano?È un framework per automatizzare la tua interfaccia utente, forse può essere usato per registrare cose per te...

Utilizziamo Automation Framework per testare automaticamente la nostra interfaccia utente in WPF.

Disclaimer:Lavoro per l'azienda che vende questo prodotto, non solo, ma sono uno sviluppatore di questo particolare prodotto :).

Se sei interessato a un prodotto commerciale per fornire questo, è disponibile Runtime Intelligence (un componente aggiuntivo funzionale a Dotfuscator) che inserisce funzionalità di monitoraggio dell'utilizzo nelle tue applicazioni .NET.Forniamo non solo l'effettiva implementazione della funzionalità di tracciamento, ma anche la funzionalità di raccolta, elaborazione e reporting dei dati.

Recentemente c'è stata una discussione sul forum Business of Software su questo argomento che ho anche pubblicato qui: http://discuss.joelonsoftware.com/default.asp?biz.5.680205.26 .

Per una panoramica di alto livello delle nostre cose, vedere qui: http://www.preemptive.com/runtime-intelligence-services.html .

Inoltre sto attualmente lavorando alla stesura di documentazione più orientata alla tecnica poiché ci rendiamo conto che è un'area che potremmo sicuramente migliorare, per favore fatemi sapere se qualcuno è interessato a essere avvisato quando l'avrò completata.

Non ho ancora sviluppato utilizzando WPF..Ma suppongo che sia uguale alla maggior parte delle altre applicazioni in quanto si desidera mantenere il codice dell'interfaccia utente il più leggero possibile.In questo caso è possibile utilizzare numerosi modelli di progettazione, come quello ovvio MVC E Facciata.Personalmente cerco sempre di mantenere gli oggetti che viaggiano tra gli strati UI e BL il più leggeri possibile, mantenendoli primitivi se posso.

Questo mi aiuta quindi a concentrarmi sul miglioramento del livello dell'interfaccia utente senza la preoccupazione di qualcosa che succede una volta restituiti i miei dati (primitivi).

Spero di aver compreso correttamente la tua domanda e mi spiace di non poter offrire ulteriore aiuto contestuale con WPF.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top