代码之家  ›  专栏  ›  技术社区  ›  MoonKnight

导致异常的异步方法

  •  2
  • MoonKnight  · 技术社区  · 12 年前

    我有一个WPF DataGrid 它绑定到ViewModel,一切都很棒。我现在意识到我需要将更多的数据加载到 数据网格 比最初预期的要多。所以我用过 async 以使将该数据加载到Viewmodel容器中成为非UI阻塞。所以,在我的 ResourceDataViewModel : ViewModelBase 我有以下方法

    public async void LoadResourceFilesAsync(string fullFileName = null)
    {
        if (!String.IsNullOrEmpty(fullFileName))
            this.FullFileName = fullFileName;
        strategy = manager.InitialiseStrategy(this);
        if (strategy == null)
            return;
    
        ...
    
        // Get data asynchoniously.
        List<ResourceViewModel> resourceViewModelList = await strategy.LoadResourceFilesAsync();
        this.Resources = new TypedListObservableCollection<ResourceViewModel>(resourceViewModelList);
    
        // Setup event handlers.
        this.Resources.CollectionChanged += this.OnCollectionChanged;
        foreach (ResourceViewModel rvm in resourceViewModelList)
            rvm.PropertyChanged += this.OnResourceViewModelPropertyChanged;
    
        // Set the file name for View and ViewModel.
        this.FullFileName = strategy.FullFileName;
        base.DisplayName = Path.GetFileName(this.FullFileName); 
    
        ...
    }
    

    所以,在我做加载方法之前 异步 ,一切都很好;数据已加载 DisplayName (中定义的属性 abstract ViewModelBase 类)绑定到 TabItem header属性导致文件名显示在 标签项目 收割台正确。现在我已经使加载异步,数据加载到 数据网格 正如您从上面的代码中所期望的那样,

    base.DisplayName = Path.GetFileName(this.FullFileName); 
    

    不更新 base.DisplayName 相反,它 默默地 (即在我的代码中不抛出和exeption)导致 System.ArgumentException 带有消息:

    消息=“在对象实例上找不到方法。”

    现在,我变了 base.DisplayName(基本显示名称) **this**.DisplayName 这将停止异常,但仍然不会更新 标签项目 Header , 为什么会发生这种情况,我该如何解决?

    笔记我已经检查了执行此操作的线程,并且它是预期的MainThread/UIThread,这使得这非常不正常。

    使现代化当我使用Snoop时,我已经用它来了解绑定发生了什么 this.DisplayName 装订正在显示 {DisconnectedItem} (我发现了 related question at MSDN ). 然而,我仍然不知道这里发生了什么。。。


    编辑地址注释

    这个 DataContext 我的应用程序的主窗口是 MainWindowViewModel ; 这包含一个属性

    public ObservableCollection<WorkspaceViewModel> Workspaces { ... }
    

    其中包含我要在每个视图中显示的ViewModel 标签项目 。我有另一个ViewModel(称为ResourceDataViewModel ) which holds the 数据网格 s and inherits from public WorkspaceViewModel`,定义为

    public abstract class WorkspaceViewModel : ViewModelBase { ... }
    

    并处理所有MVVM的东西,比如 OnPropertyChanged 处理程序等 主窗口视图模型 将资源文件加载到的调用层次结构 TabControl 在主窗口中是:

    public void LoadResourceFiles(string fullFileName = null)
    {
        // Build and load the ViewModel in to the View.
        ResourceDataViewModel workspace = new ResourceDataViewModel(this);
        workspace.LoadResourceFilesAsync(fullFileName);
        ...
    }
    

    和在 ResourceDataViewModel 我有上面原始问题中显示的方法。然后,它从策略工厂获取策略,并异步加载数据——在本例中使用以下方法

    public async Task<List<ResourceViewModel>> LoadResourceFilesAsync()
    {
        // Do preliminary work here [build FileCultureDictionary etc.].
        ...
    
        // Build the resource data sets and return.
        List<Resource> buildResult = await BuildResourceDataAsync(FileCultureDictionary);
        return (from resource in buildResult
                  select new ResourceViewModel(resource)).ToList();
    }
    
    private async Task<List<Resource>> BuildResourceDataAsync(Dictionary<string, string> cultureDict)
    {
        // Now add the data.
        int fileIndex = 1;
        const int coreColumnIndex = 2;
        string[] strArr = null;
        List<string[]> strArrList = new List<string[]>();
    
        // Start building the data.
        Task<List<Resource>> task = Task.Factory.StartNew<List<Resource>>(() =>
            {
                // Do some work here...
                ...
                return resources;
            });
        return await task;
    }
    

    注意,从这些方法返回的数据 很好。 这些方法本身似乎并没有造成上述问题——无论上下文切换可能是什么。我在这里真的很不知所措,所以任何想法都是最受欢迎的。

    2 回复  |  直到 12 年前
        1
  •  0
  •   Sheridan    12 年前

    你试过设置 IsAsync 的财产 Binding 类到 True 关于相关 结合 用户界面中的对象?这为我解决了一个类似的问题。

        2
  •  0
  •   MoonKnight    12 年前

    我已经找到了解决这个问题的方法,但我认为这不是最好的方法,更像是一种变通方法。在我尝试使用的ViewModel中

    base.DisplayName = "XYZ";
    

    这不起作用。交换 this 对于 base 在上面防止了异常,但我仍然有异常( WPF library bug 我认为这就是这个问题的原因)。现在,尝试解决 DataContext 开关,我已经超越了 DisplayName 在里面 ViewModelBase 和在 ResourceDataViewModel 我有

    public override string DisplayName
    {
        get { return base.DisplayName; }
        protected set
        {
            if (base.DisplayName == value)
                return;
            base.DisplayName = value;
            OnPropertyChanged("DisplayName");
        }
    }
    

    这似乎停止了绑定问题,但延迟了 显示名称 TabItem 轻微地

    我欢迎任何人拥有的任何其他解决方案,并希望这能帮助其他人。