我有一个使用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/

10-13 04:13