我有一个使用MVVM设计模式和异步数据访问方法的大型WPF应用程序。它使用带有回调处理程序和IAsyncResult
接口的旧式异步代码...这是一个典型示例:
function.BeginInvoke(callBackMethod, asyncState);
然后,在视图模型中,我具有以下回调处理程序:
private void GotData(GetDataOperationResult<Genres> result)
{
UiThreadManager.RunOnUiThread((Action)delegate
{
if (result.IsSuccess) DoSomething(result.ReturnValue);
else FeedbackManager.Add(result);
});
}
RunOnUiThread
方法基本上如下:public object RunOnUiThread(Delegate method)
{
return Dispatcher.Invoke(DispatcherPriority.Normal, method);
}
此问题仅影响一种视图模型,该视图模型使用户可以编辑
Release
对象。在相关视图上,第一次加载数据库时,会请求填充ComboBox
的某些集合。让我们简化一下这句话,即只有一个集合称为Genres
。数据到达视图模型后,将按以下方式处理:private void GotGenres(GetDataOperationResult<Genres> result)
{
UiThreadManager.RunOnUiThread((Action)delegate
{
if (result.IsSuccess) Genres.AddEmptyItemBefore(result.ReturnValue);
else FeedbackManager.Add(result);
});
}
当存在集合并且在UI中选择了
Release
对象时,我有以下代码从集合中选择当前的Release.Genre
值:if (!Release.Genre.IsEmpty && Genres.ContainsItemWithId(Release.Genre.Id))
Release.Genre = Genres.GetItemWithId(Release.Genre);
在这一点上,我应该注意,这一切工作正常,并且这是引用视图模型中
Release.Genre
属性的唯一一行。我的特殊问题是,有时
Release.Genre
属性设置为null
,我无法知道如何或从何处。 >>编辑>>当我在属性设置器上放置一个断点时,null
值的真正线索,因为只有[Native to Managed Transition]
行。从Show External Code
窗口中选择Call Stack
选项时,我可以看到基本的异步代码调用:现在,我可以确认尝试解决此问题时发现的以下事实:
引用
Release.Genre
属性的一行未将其设置为null
。对Genres.AddEmptyItemBefore(result.ReturnValue)的调用未将其设置为
null
...这只是在添加“空” Genres
之后将结果集合添加到Genre
集合中。有时在调用Genres.AddEmptyItemBefore(result.ReturnValue)时或之后将
Release.Genre
属性设置为null
,但这不是因为它...在某些情况下单步执行时,执行已跳转(在无关的方式)到我在Release.Genre
属性设置器上设置的断点,其中value
输入参数为null
,但这不会每次都发生。从相关视图模型到
Release
视图模型时,通常会发生这种情况,但并非每次都发生。相关的视图模型没有对
Release.Genre
属性的引用。明确地说,我并不是要任何人从我提供的稀疏信息中调试我的问题。我也没有寻求有关进行异步数据调用的建议。相反,我实际上是在尝试寻找尚未想到的新方法。我知道某个地方的某些代码(几乎可以肯定是我的代码)将属性设置为
null
...我的问题是如何检测该代码在哪里?它似乎不在Release
视图模型中。我如何在没有更多线索的情况下继续调试此问题? 最佳答案
我通常使用平面文件,XML或数据库日志记录进行调试。我创建了那些Log类用于记录目的,以便可以从开发的每个应用程序中调用它。
对于数据库日志记录,您可以执行以下操作:
void WriteLog(string log){
// Your database insert here
}
也许您需要日期时间和其他支持信息,但这取决于开发人员。对于简单的平面文件日志记录是:
void WriteLog(string log){
using(TextWriter tx = new StreamWriter("./Log/" + DateTime.Now.ToString() + ".txt", false)){
tx.WriteLine(log);
}
}
您可以通过两种方式在应用程序中使用日志记录:
1:方法调用
WriteLog((Release.Genre == null).ToString());
if (!Release.Genre.IsEmpty && Genres.ContainsItemWithId(Release.Genre.Id))
Release.Genre = Genres.GetItemWithId(Release.Genre);
2:将其添加到您的Release.Genre设置(或获取)属性中
public class Release{
private Genre _genre=null;
public Genre Genre{
get{
WriteLog((_genre == null).ToString());
return _genre;
}
set{
WriteLog((_genre == null).ToString());
_genre = value;
}
}
}
这样,您可以尝试获取呼叫顺序,无论是否在呼叫之前,呼叫期间等地方将Release.Genre设置为其他状态。
请注意,我只是给出了建筑记录的一般形象。请期待错误。但是,开发日志活动以满足要求是开发人员的责任。
关于c# - 如何调试具有异步数据访问权限且没有调用堆栈的WPF应用程序?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15664558/