2012-03-07 13 views
9

WPF ईवेंट या बाइंडिंग डीबग करते समय आप किस विधि का उपयोग करते हैं?डब्ल्यूपीएफ घटनाओं को डिबग करना, बाइंडिंग

मैंने ब्रेकपॉइंट का उपयोग करने की कोशिश की, लेकिन ऐसा लगता है कि मेरे एक्सएएमएल या कोड के पीछे कुछ गलत है जो कभी ब्रेकपॉइंट को हिट नहीं करता है।

वहाँ देखने के लिए जब मैं WPF में कुछ क्लिक एक रास्ता है, क्या घटना संदेशों अप पॉपिंग कर रहे हैं या ऊपर पॉपिंग को समझने के लिए क्या गलत हुआ नहीं?

उत्तर

23
WPF अनुप्रयोगों के निर्माण के लगभग पूरे समय मैं प्रतिक्रियाशील और preventative समाधान की एक किस्म एकत्र किया सुनिश्चित करना है कि सब कुछ एक साथ ठीक से बांध के पिछले 3 वर्षों में

नोट: मैं तुम्हें एक त्वरित सारांश अब देना और फिर सुबह में वापस पोस्ट कोड नमूने/स्क्रीनशॉट के साथ (10 घंटे के समय में) होगा।

1) एक कनवर्टर कि डिबगर टूट जाता है जब Convert और ConvertBack निष्पादित किया जाता है बनाएँ:

ये मेरी सबसे प्रभावी उपकरण हैं। यह सुनिश्चित करने के लिए एक त्वरित और उपयोगी तरीका है कि आपके पास मूल्यों की अपेक्षा है। मैंने पहली बार इस चाल के बारे में Bea Stollnitz's blog post से सीखा।

DebugConverter.cs

public class DebugConverter : IValueConverter 
{ 

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (Debugger.IsAttached) 
      Debugger.Break(); 

     return Binding.DoNothing; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (Debugger.IsAttached) 
      Debugger.Break(); 

     return Binding.DoNothing; 
    } 

} 

2) एक TraceListener कि किसी भी त्रुटि को बीच में रोक बनाएँ। जब आप डीबगर संलग्न होते हैं तो यह विजुअल स्टूडियो आउटपुट विंडो में जो दिखाई देता है उसके समान होता है। बाध्यकारी ऑपरेशन के दौरान एक अपवाद फेंकने पर इस विधि का उपयोग करके मैं डीबगर को तोड़ने के लिए प्राप्त कर सकता हूं। यह PresentationTraceSources.TraceLevel सेट करने से बेहतर है क्योंकि यह पूरे एप्लिकेशन पर लागू होता है, प्रति बाध्यकारी नहीं।

DataBindingErrorLogger।सीएस

public class DataBindingErrorLogger : DefaultTraceListener, IDisposable 
{ 
    private ILogger Logger; 

    public DataBindingErrorLogger(ILogger logger, SourceLevels level) 
    { 
     Logger = logger; 

     PresentationTraceSources.Refresh(); 
     PresentationTraceSources.DataBindingSource.Listeners.Add(this); 
     PresentationTraceSources.DataBindingSource.Switch.Level = level; 
    } 

    public override void Write(string message) 
    { 
    } 

    public override void WriteLine(string message) 
    { 
     Logger.BindingError(message); 

     if (Debugger.IsAttached && message.Contains("Exception")) 
      Debugger.Break(); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     Flush(); 
     Close(); 

     PresentationTraceSources.DataBindingSource.Listeners.Remove(this); 
    } 

} 

प्रयोग

DataBindingErrorLogger = new DataBindingErrorLogger(Logger, SourceLevels.Warning); 

ऊपर में, ILogger एक NLog लॉग लेखक है। मेरे पास DefaultTraceListener का एक अधिक जटिल संस्करण है जो एक पूर्ण स्टैक ट्रेस की रिपोर्ट कर सकता है और वास्तव में अपवाद फेंक सकता है हालांकि यह आपको शुरू करने के लिए पर्याप्त होगा (जेसन बॉक के पास article on this extended implementation है यदि आप इसे स्वयं लागू करना चाहते हैं, हालांकि आपको वास्तव में कोड की आवश्यकता होगी इसे काम करें)।

3)Snoop WPF आत्मनिरीक्षण उपकरण का उपयोग अपने दृश्य में पहुंचने और अपनी डेटा ऑब्जेक्ट का निरीक्षण करने के लिए करें। स्नूप का उपयोग करके आप अपने दृश्य की तार्किक संरचना देख सकते हैं और विभिन्न स्थितियों का परीक्षण करने के लिए मूल्यों को अंतःक्रियात्मक रूप से बदल सकते हैं।

Snoop WPF

स्नूप WPF बिल्कुल जरूरी किसी भी WPF आवेदन की यात्रा समय के लिए है। इसकी कई विशेषताओं में से डेल्व कमांड आपको अपने दृश्य/दृश्य मॉडल पर ड्रिल करने और मूल्यों को अंतःक्रियात्मक रूप से ट्विक करने की अनुमति देता है। किसी संपत्ति में जाने के लिए, संदर्भ मेनू खोलने के लिए राइट-क्लिक करें और Delve कमांड का चयन करें; एक स्तर (अन-डेलव?) का बैक अप लेने के लिए शीर्ष-दाएं कोने में ^ एक छोटा बटन है। उदाहरण के लिए, DataContext संपत्ति में delving करने का प्रयास करें।

संपादित करें: मैं विश्वास नहीं कर सकता मैं सिर्फ यह देखा, लेकिन वहाँ स्नूप WPF विंडो में एक डाटा प्रसंग टैब है।

DataContext Tab

4)#DEBUG में INotifyPropertyChanged घटनाओं पर रनटाइम जाँच करता है। चूंकि डेटा बाइंडिंग सिस्टम अधिसूचित होने पर निर्भर करता है जब गुण बदल जाते हैं, यह आपके स्वच्छता के लिए महत्वपूर्ण है कि आप यह सूचित कर रहे हैं कि सही संपत्ति बदल गई है। कुछ प्रतिबिंब जादू के साथ आप कुछ गलत होने पर Debug.Assert कर सकते हैं।

PropertyChangedHelper.cs

public static class PropertyChangedHelper 
{ 
    #if DEBUG 
    public static Dictionary<Type, Dictionary<string, bool>> PropertyCache = new Dictionary<Type, Dictionary<string, bool>>(); 
    #endif 

    [DebuggerStepThrough] 
    public static void Notify(this INotifyPropertyChanged sender, PropertyChangedEventHandler eventHandler, string propertyName) 
    { 
     sender.Notify(eventHandler, new PropertyChangedEventArgs(propertyName), true); 
    } 

    [DebuggerStepThrough] 
    public static void Notify(this INotifyPropertyChanged sender, PropertyChangedEventHandler eventHandler, string propertyName, bool validatePropertyName) 
    { 
     sender.Notify(eventHandler, new PropertyChangedEventArgs(propertyName), validatePropertyName); 
    } 

    [DebuggerStepThrough] 
    public static void Notify(this INotifyPropertyChanged sender, PropertyChangedEventHandler eventHandler, PropertyChangedEventArgs eventArgs) 
    { 
     sender.Notify(eventHandler, eventArgs, true); 
    } 

    [DebuggerStepThrough] 
    public static void Notify(this INotifyPropertyChanged sender, PropertyChangedEventHandler eventHandler, PropertyChangedEventArgs eventArgs, bool validatePropertyName) 
    { 
     #if DEBUG 
     if (validatePropertyName) 
      Debug.Assert(PropertyExists(sender as object, eventArgs.PropertyName), String.Format("Property: {0} does not exist on type: {1}", eventArgs.PropertyName, sender.GetType().ToString())); 
     #endif 

     // as the event handlers is a parameter is actually somewhat "thread safe" 
     // http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx 
     if (eventHandler != null) 
      eventHandler(sender, eventArgs); 
    } 

    #if DEBUG 
    [DebuggerStepThrough] 
    public static bool PropertyExists(object sender, string propertyName) 
    { 
     // we do not check validity of dynamic classes. it is possible, however since they're dynamic we couldn't cache them anyway. 
     if (sender is ICustomTypeDescriptor) 
      return true; 

     var senderType = sender.GetType();  
     if (!PropertyCache.ContainsKey(senderType)) 
      PropertyCache.Add(senderType, new Dictionary<string,bool>()); 

     lock (PropertyCache) 
     { 
      if (!(PropertyCache[senderType].ContainsKey(propertyName))) 
      { 
       var hasPropertyByName = (senderType.GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static) != null); 
       PropertyCache[senderType].Add(propertyName, hasPropertyByName); 
      } 
     } 

     return PropertyCache[senderType][propertyName]; 
    } 
    #endif 

} 

HTH,

+0

कोई प्रश्न, मुझे एक चिल्लाओ दे। – Dennis

1

क्या आपके पास व्यू आउटपुट सक्रिय है। इससे कुछ बाध्यकारी त्रुटियां दिखाई देगी। प्रेजेंटेशनट्रेस स्रोत। ट्रेसलेवल = "हाई" अधिक जानकारी दिखाएगा। यह आपके ब्रेकपॉइंट पर पहुंचने से पहले एक त्रुटि को मार सकता है। इसे काम देखने के लिए केवल कन्स्ट्रक्टर में एक ब्रेक पॉइंट सेट करें।

1

पर एक "पास-थ्रू" कनवर्टर जोड़ा जा रहा है एक बाध्यकारी कभी कभी तुम कनवर्टर कभी वहाँ एक बाध्यकारी अद्यतन है जब कि खींच लिया हो जाएगी में एक को तोड़ने बिंदु डाल करने की अनुमति देकर मदद कर सकते हैं। यह आपको कन्वर्ट और कन्वर्टबैक मान पैरामीटर से बाइंडिंग के माध्यम से दोनों तरीकों से गुजरने वाले मानों को देखने की अनुमति देता है।

public class PassthroughConverter : IValueConverter { 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { 
     return value; // Breakpoint here. 
    } 
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { 
     return value; // Breakpoint here. 
    } 
} 

आप नाम से एक नियंत्रण का उपयोग तो अपने Window.xaml.cs में आप का उपयोग कर नियंत्रण पर बाइंडिंग की स्थिति की जांच कर सकते कर सकते हैं:

BindingExpression be = comboMyCombo.GetBindingExpression(ComboBox.IsEnabledProperty); 

को देख डीबगर में 'होना' मदद कर सकते हैं (कभी-कभी बाइंडिंग कुछ परिचालनों पर रीसेट/टूटा हो जाता है)।

संबंधित मुद्दे