2013-09-08 3 views
2

У меня есть WPF DataGrid, который привязан к ViewModel, и все отлично. Теперь я понимаю, что мне нужно загрузить намного больше данных в 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 (свойство, определенное в классе abstractViewModelBase), которое связано с свойством заголовка TabItem, вызвало правильное отображение имени файла в заголовке TabItem. Теперь я сделал asynchronious нагрузки, нагрузки данных в DataGrid штрафа, как вы ожидали бы сформировать код, указанный выше, однако,

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

не обновляет base.DisplayName вместо этого он молча (т.е. не бросает и Exeption в моем коде) вызывает System.ArgumentException с сообщением:

Сообщение = "Невозможно найти метод на экземпляре объекта".

Теперь я изменил base.DisplayName к **this**.DisplayName и это останавливает исключение, но до сих пор не обновлять TabItemHeader, почему это происходит и как это исправить?

Примечание. Я проверил Thread, на котором это выполняется, и это MainThread/UIThread, как ожидалось, что делает это довольно аномальным.

Обновление. Я использовал Snoop, чтобы получить крючок в том, что происходит со связыванием, когда я использую this.DisplayName, и привязка показывает {DisconnectedItem} (я нашел related question at MSDN). Однако я до сих пор в недоумении относительно того, что происходит здесь ...


правок Адрес Комментарии

DataContext моих приложений MainWindow является MainWindowViewModel; это содержит свойство

public ObservableCollection<WorkspaceViewModel> Workspaces { ... } 

который держит ViewModels я хочу, чтобы отобразить в каждом TabItem. У меня есть еще один ViewModel (так называемый ResourceDataViewModel ) which holds the DataGrid s and inherits from общественного 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; 
} 

Обратите внимание, что данные, которые поступают обратно из этих методов прекрасно. Эти методы сами по себе, по-видимому, не вызывают проблемы выше, но может быть и переключением контекста. Я нахожусь в настоящей потере здесь, поэтому любые идеи приветствуются.

+0

Итак, @svick любые идеи? – MoonKnight

+0

Ну, вы почти никогда не должны использовать методы async void, но я не думаю, что это исправит вашу проблему. – svick

+0

Почему вы никогда не должны их использовать? Они были предназначены для использования, не так ли? – MoonKnight

ответ

0

Я нашел решение этой проблемы, однако я не считаю, что это лучший подход и является более обходным решением. В 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"); 
    } 
} 

Это, кажется, остановить связывающую проблему, но задерживает отображение DisplayName на TabItem чуть-чуть.

Я приветствую любые другие решения, которые есть у кого-либо, и надеемся, что это поможет кому-то другому.

0

Вы пробовали настройки IsAsync свойства Binding класса True на соответствующих Binding объектов в интерфейсе? Это позволило мне решить подобную проблему.

+0

Спасибо за ваш ответ Шеридан, стоило попробовать, но это не помогло. : '[ – MoonKnight