2013-08-23 101 views
2

在我的第一个视图模型(重命名为MainViewModel)中,我有一个ActionViewModel列表。 在我的xaml我有一个列表框绑定到列表,在列表框中,我有一个模板绑定到来自ActionViewModel的属性。如何在更新子视图模型时更新父视图模型

到目前为止这么好,一切正常。 当选择其中一个列表项时,我导航到一个ActionViewModel并将其ID传递给它。 ActionViewModel从内存中的静态列表中检索信息,从该列表中MainViewModel还检索信息以创建actionviewmodels列表。

到目前为止仍然非常好,我可以编辑属性,所有的绑定工作正常,我很高兴。 通过单击保存按钮收集信息并将其存储在静态列表中。 当我点击后退按钮时,我会回到列表中,但不幸的是,显示的值仍然相同,有没有办法发送命令来重新加载列表中的项目?传递一个完整的viewmodel作为一个新的ActionViewModel的参考?或者一些属性告诉父母'你的列表中的这个视图模型已经更新'?

我相信上面的文字是有点混乱,所以这里是一些代码,以澄清了一点(希望)

MainViewModel.cs

private List<ActionViewModel> _actionViewModels; 
public List<ActionViewModel> ActionViewModels 
{ 
    get { return _actionViewModels; } 
    set { _actionViewModels = value; RaisePropertyChanged(() => ActionViewModels); } 
} 


private Cirrious.MvvmCross.ViewModels.MvxCommand<int> _navigateToAction; 
public System.Windows.Input.ICommand NavigateToAction 
{ 
    get 
    { 
     _navigateToAction = _navigateToAction ?? new Cirrious.MvvmCross.ViewModels.MvxCommand<int>((action) => NavigateToTheDesiredAction(action)); 
     return _navigateToAction; 
    } 
} 

private void NavigateToTheDesiredAction(int action) 
{ 
    ShowViewModel<ActionViewModel>(new { id = action }); 
} 

// Get DTOs from server or from cache and fill the list of ActionViewModels 
public async Task Load() 
{ 
    ActionService actionService = new ActionService(); 

    List<ActionViewModel> actionViewModels = new List<ActionViewModel>(); 

    MyActions = await actionService.GetMyActions(); 
    foreach (ActionDTO action in MyActions) 
    { 
     ActionViewModel actionViewModel = new ActionViewModel(); 
     await actionViewModel.Load(action.id); 
     actionViewModels.Add(actionViewModel); 
    } 

    ActionViewModels = actionViewModels; 
} 

ActionViewModel.cs

public int ID 
{ 
    get { return TheAction.id; } 
    set { TheAction.id = value; RaisePropertyChanged(() => ID); } 
} 

public string Title 
{ 
    get { return TheAction.Title; } 
    set { TheAction.Title = value; RaisePropertyChanged(() => Title); } 
} 

public async Task Load(int actionId) 
{ 
    ActionDTO TheAction = await actionService.GetAction(actionId); 
    this.ID = TheAction.id; 
    this.Title = TheAction.Title; 
} 

private Cirrious.MvvmCross.ViewModels.MvxCommand _save; 
public System.Windows.Input.ICommand Save 
{ 
    get 
    { 
     _save = _save ?? new Cirrious.MvvmCross.ViewModels.MvxCommand(PreSaveModel); 
     return _save; 
    } 
} 

private void PreSaveModel() 
{ 
    SaveModel(); 
} 

private async Task SaveModel() 
{ 
    ValidationDTO result = await actionService.SaveAction(TheAction); 
} 

ActionService.cs

public static List<ActionDTO> AllActions = new List<ActionDTO>(); 

public async Task<ActionDTO> GetAction(int actionId) 
{ 
    ActionDTO action = AllActions.FirstOrDefault(a => a.id == actionId); 
    if (action == null) 
    { 
     int tempActionId = await LoadAction(actionId); 
     if (tempActionId > 0) 
      return await GetAction(actionId); 
     else 
      return new ActionDTO() { Error = new ValidationDTO(false, "Failed to load the action with id " + actionId, ErrorCode.InvalidActionId) }; 
    } 
    return action; 
} 

private async Task<int> LoadAction(int actionId) 
{ 
    ActionDTO action = await webservice.GetAction(actionId); 
    AllActions.Add(action); 
    return action.id; 
} 

public async Task<ValidationDTO> SaveAction(ActionDTO action) 
{ 
    List<ActionDTO> currentList = AllActions; 
    ActionDTO removeActionFromList = currentList.FirstOrDefault(a => a.id == action.id); 
    if (removeActionFromList != null) 
     currentList.Remove(removeActionFromList); 

    currentList.Add(action); 
    AllActions = currentList; 
    return await webservice.SaveAction(action); 
} 

回答

2

我能想到的3种方式可以让你做到这一点。

  1. ActionService会发出某种通知时,数据的变化。一个简单的方法就是使用MvvmCross Messenger插件。这是CollectionService.cs的CollectABull服务工作中的mvvmcross视频的N + 1天路(更多信息观看http://mvvmcross.wordpress.com N = 13)

    这是我通常使用的方法。它具有较低的开销,使用WeakReference s(所以不会泄漏内存),它很容易扩展(任何对象都可以监听变化),并且它鼓励ViewModel和Model对象的松耦合

  2. 您可以实现一些类型为列表ViewModel上的Refresh API,并可从相应的查看事件(例如ViewDidAppearOnNavigatedToOnResume)调用此API。

    我通常不会使用这种方法来刷新已知数据,但我已经使用它来启用/禁用资源密集型对象 - 例如,定时器

    对于某些形状的模型数据(尤其是其变化频率),我可以想象这种方法可能比信使方法更有效。

  3. 您可以将INotifyPropertyChangedINotifyCollectionChanged的使用扩展回您的模型图层。

    我已经做了几次,它对我很好。

    如果您确实选择了此方法,请注意确保所有视图都使用WeakReference订阅来订阅更改事件,例如MvvmCross绑定中使用的订阅 - 请参阅WeakSubscription。如果你没有这样做,那么模型可能会导致视图在内存中保留,即使在UI已经移除它们之后。

+0

第一个解决方案对我来说是最好的解决办法,看着N = 12和N = YouTube上的13个教程这只是一个执行消息的行动事之后,它的工作就像一个魅力。 – TwanWV