سؤال

كيف حالك instrumenting واجهة المستخدم الخاصة بك ؟ في الماضي كنت قد قرأت أن الناس قد المجهزة واجهات المستخدم الخاصة بهم, ولكن ما لم وجدت أمثلة أو نصائح كيف إلى أداة واجهة المستخدم.

قبل instrumenting ، أعني جمع البيانات بشأن الاستخدام وأداء النظام.MSDN المادة على الأجهزة هو http://msdn.microsoft.com/en-us/library/x5952w0c.aspx.أود أن القبض على الأزرار التي يمكن للمستخدمين النقر على لوحة المفاتيح shortucts يستخدمونها ، ما هي الشروط التي يستخدمونها في البحث ، وما إلى ذلك.

  • كيف حالك instrumenting واجهة المستخدم الخاصة بك?
  • ما شكل أنت تخزين الأجهزة?
  • كيف يمكنك معالجة المجهزة البيانات ؟
  • كيف يمكنك حفظ الخاص بك رمز واجهة المستخدم نظيفة مع هذه الأجهزة المنطق ؟

على وجه التحديد, انا تنفيذ بلدي واجهة المستخدم في برنامج الأغذية العالمي ، لذلك هذا سوف توفر تحديات إضافية مقارنة instrumenting تطبيق على شبكة الإنترنت.(أيتحتاج إلى نقل المجهزة البيانات إلى موقع مركزي ، إلخ).وقال أشعر التكنولوجيا قد توفر أسهل تنفيذ الأجهزة عبر مفاهيم مثل الخصائص المرفقة.

  • هل المجهزة WPF ؟ هل لديك أي نصائح حول كيف يمكن تحقيق ذلك ؟

تحرير:التالية بلوق وظيفة يقدم حلا للاهتمام: بكسل في الجينات بلوق:تقنيات واجهة المستخدم التدقيق على تطبيقات WPF

هل كانت مفيدة؟

المحلول 4

التالية بلوق وظيفة يعطي عدد غير قليل من الأفكار الجيدة من أجل instrumenting تطبيق WPF:تقنيات واجهة المستخدم التدقيق على تطبيقات WPF.

نصائح أخرى

هنا هو مثال على كيفية استخدام بسيط مدير الفعاليات ربط في واجهة الأحداث و استخراج المعلومات الأساسية من الأحداث ، مثل اسم و نوع عنصر واجهة المستخدم, اسم الحدث الإطار الأصل هو اسم نوع.على قوائم أنا أيضا استخراج العنصر المحدد.

هذا الحل فقط يستمع نقرات من الضوابط المستمدة من ButtonBase (زر ToggleButton, ...) واختيار التغييرات في الضوابط المستمدة من محدد (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 و خلق منفصلة مسجل اسمه 'تفاعل' تسجيل تفاعل المستخدم.فئة 'سجل' هنا هو مجرد بلدي ثابت المجمع 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 الأوامر ، كل أوامر مخصصة يمكن أن ثم سجل الإجراءات المتخذة.يمكنك أيضا تسجيل الدخول بالطريقة الأمر بدأ.

ولعل مايكروسوفت أتمتة واجهة المستخدم ل WPF يمكن أن تساعد ؟ في إطار أتمتة واجهة المستخدم الخاصة بك, ربما أنها يمكن أن تستخدم لتسجيل الأشياء لك...

ونحن استخدام أتمتة إطار السيارات-اختبار واجهة المستخدم لدينا في WPF.

تنويه:أنا أعمل في الشركة التي تبيع هذا المنتج ، ليس هذا فقط ولكن أنا مطور على هذا المنتج خاص :) .

إذا كنت مهتما في منتج تجاري لتوفير هذا ثم Runtime الاستخبارات (وظيفية إضافة إلى Dotfuscator ) أن يحقن تتبع الاستخدام الوظيفي إلى الخاص بك .صافي التطبيقات المتاحة.ونحن نقدم ليس فقط التنفيذ الفعلي تتبع وظائف ولكن جمع البيانات ومعالجتها وظيفة الإبلاغ كذلك.

كان هناك في الآونة الأخيرة نقاش حول الأعمال من برنامج المنتدى على هذا الموضوع كما نشر في الموجود هنا: http://discuss.joelonsoftware.com/default.asp?biz.5.680205.26 .

للحصول على لمحة مستوى عال من الاشياء انظر هنا: http://www.preemptive.com/runtime-intelligence-services.html .

بالإضافة إلى ذلك أنا أعمل حاليا على كتابة بعض أكثر من الناحية الفنية الموجهة الوثائق ونحن ندرك أن منطقة بالتأكيد يمكننا تحسين, واسمحوا لي أن أعرف إذا كان أي شخص مهتم في إخطاره عندما كنت قد أكملت ذلك.

لم تطويرها باستخدام WPF..ولكن أود أن نفترض أن نفس معظم التطبيقات الأخرى التي تريد الحفاظ على واجهة المستخدم رمز خفيفة قدر الإمكان..عدد من أنماط التصميم يمكن استخدامها في هذا مثل واضح MVC و الواجهة.أنا شخصيا دائما في محاولة للحفاظ على الكائنات السفر بين واجهة المستخدم BL طبقات خفيفة قدر الإمكان ، وحفظ لهم إلى الأوليات إذا أنا يمكن أن.

هذا يساعدني على التركيز على تحسين واجهة المستخدم طبقة دون مخاوف من أي شيء يحدث مرة واحدة أنا رمي بلدي (البدائية) البيانات مرة أخرى..

اتمنى فهمت سؤالك بشكل صحيح, و آسف أنا لا يمكن أن تقدم المزيد من المساعدة السياقية مع WPF.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top