2

我有一个DataGrid绑定到 ViewModel 的 WPF,一切都很好。我现在意识到我需要加载DataGrid比最初预期更多的数据。所以我习惯于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); 

    ...
}

所以,在我制作加载方法之前async,一切都很好;数据已加载,并且绑定到标题属性的DisplayName(类中定义的属性)导致文件名正确显示在标题中。现在我已经使加载异步,数据加载到罚款中,正如你所期望的那样,来自上面的代码,但是,abstract ViewModelBaseTabItemTabItemDataGrid

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

不更新base.DisplayName而是静默(即在我的代码中不抛出和异常)导致System.ArgumentException带有消息:

Message = "在对象实例上找不到方法。"

现在,我已更改base.DisplayName**this**.DisplayName,这停止了异常,但仍然没有更新TabItem Header为什么会发生这种情况,我该如何解决?

笔记。我已经检查了它正在执行的线程,它是预期的 MainThread/UIThread,这使得这非常反常。

更新。this.DisplayName当我使用并且绑定显示时,我使用 Snoop 来了解绑定发生的情况{DisconnectedItem}(我在 MSDN 找到了一个相关问题)。然而,我仍然对这里发生的事情感到茫然......


编辑地址评论

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

public ObservableCollection<WorkspaceViewModel> Workspaces { ... }

其中包含我想在每个TabItem. 我有另一个 ViewModel(称为 ResourceDataViewModel ) which holds theDataGrid s and inherits frompublic WorkspaceViewModel`,它被定义为

public abstract class WorkspaceViewModel : ViewModelBase { ... }

并处理所有 MVVM 东西,如OnPropertyChanged处理程序等。在MainWindowViewModel调用层次结构中,将资源文件加载到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;
}

请注意,从这些方法返回的数据很好。这些方法本身似乎不会导致上述问题 - 但是上下文切换可能是。我在这里真的很茫然,所以欢迎任何想法。

4

2 回答 2

0

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

base.DisplayName = "XYZ";

这是行不通的。在上面交换this可以base防止异常,但我仍然有异常(WPF 库错误,我认为这是导致此问题的原因)。现在,为了尝试解决这个DataContext问题,我已经覆盖了DisplayNameinViewModelBase和 inResourceDataViewModel我有

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

这似乎停止了绑定问题,但稍微延迟了DisplayName的显示。TabItem

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

于 2013-09-09T13:13:27.693 回答
0

您是否尝试过将类的IsAsync属性设置为 UI 中的相关对象?这为我解决了类似的问题。BindingTrueBinding

于 2013-09-09T12:19:06.080 回答