調試WPF事件或綁定時使用什麼方法?調試WPF事件,綁定
我試圖使用斷點,但它似乎是我的XAML或代碼後面,它從來沒有擊中斷點的錯誤。
有沒有辦法看到當我點擊WPF中的某些東西,什麼事件消息彈出或不彈出來明白出了什麼問題?
調試WPF事件或綁定時使用什麼方法?調試WPF事件,綁定
我試圖使用斷點,但它似乎是我的XAML或代碼後面,它從來沒有擊中斷點的錯誤。
有沒有辦法看到當我點擊WPF中的某些東西,什麼事件消息彈出或不彈出來明白出了什麼問題?
在過去3年建設WPF應用我已經收集到的各種反應和預防性解決方案,以確保一切結合在一起,幾乎正常專職的。
注意:
我會給你一個快速總結,然後在早上(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
截取的任何錯誤。這與您在連接調試器時在Visual Studio輸出窗口中看到的類似。使用這種方法,當綁定操作期間拋出異常時,我可以讓調試器中斷。這比設置PresentationTraceSources.TraceLevel
好,因爲它適用於整個應用程序,而不是每個綁定。
DataBindingErrorLogger。CS
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);
在上文中,是NLog日誌寫入器。我有一個更復雜的DefaultTraceListener
版本,它可以報告完整的堆棧跟蹤,並且實際上會拋出異常,但是這將足以讓您開始使用(如果您想自己實現,那麼Jason Bock有article on this extended implementation,儘管您需要代碼才能實際執行讓它工作)。
3)使用Snoop WPF自檢工具深入您的視圖並檢查您的數據對象。使用Snoop,您可以查看視圖的邏輯結構並以交互方式更改值以測試不同的條件。
史努比WPF是絕對必要任何WPF應用程序的迭代時間。在其衆多功能中,Delve命令允許您深入查看/查看模型並交互式地調整值。要深入查看屬性,請右鍵單擊以打開上下文菜單並選擇Delve命令;要恢復一個級別(未研究?),在右上角有一個小按鈕^。例如,嘗試深入研究DataContext
屬性。
編輯:我不能相信我只注意到這一點,但沒有在窺探WPF窗口數據上下文標籤。在#DEBUG
INotifyPropertyChanged
事件
4)運行時檢查。由於數據綁定系統依賴於在屬性發生變化時收到通知,因此您的理智很重要,即您正在通知正確的屬性已更改。有了一些反思魔法,你可以在出現問題時用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,
您是否已將視圖輸出激活。這將顯示一些綁定錯誤。 PresentationTraceSources.TraceLevel =「高」將顯示更多信息。它在到達斷點之前可能會發生錯誤。在構造函數中設置一個斷點,以查看其工作。
在綁定中添加「pass-through」轉換器有時可以幫助您在轉換器中放置一個斷點,以便在有綁定更新時將其拉出。它還允許您通過Convert和ConvertBack值參數的綁定來查看值傳遞的方式。
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);
看着「是」在調試器可以提供幫助(有時綁定會在某些操作中被重置/中斷)。
任何問題,給我留言。 – Dennis 2012-03-08 10:05:24