我如何更新父视图模型时,子视图模型更新 [英] How do I update the parent viewmodel when child viewmodel is updated

查看:229
本文介绍了我如何更新父视图模型时,子视图模型更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的第一个视图模型(更名为MainViewModel)我有ActionViewModels的列表。
在我的XAML中,我有这势必列表中的列表框,在列表框中我有一个结合从ActionViewModel属性的模板。



到目前为止这么好,一切正常。
当我选择导航至ActionViewModel并把它传递的ID的listItems中的一个。
的ActionViewModel检索内存中的静态列表从中MainViewModel也检索到的信息来创建actionviewmodels的列表信息。



到目前为止还是那么好,我可以编辑的属性,所有绑定都做工精细,我很高兴。
。使用点击保存按钮的信息被收集并存储在静态列表。
当我打后退按钮我回去的名单,但遗憾的是显示值仍存在一样,是有一些方法来发送一个命令来重新加载列表中的项目?要通过一个完整的视图模型作为参考到一个新的ActionViewModel?或者某些属性,它告诉父母这个视图模型在你的名单已更新?



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



MainViewModel.cs

 私人清单< ActionViewModel> _actionViewModels; 
公开名单< ActionViewModel> ActionViewModels
{
{返回_actionViewModels; }
集合{_actionViewModels =价值; RaisePropertyChanged(()=> ActionViewModels); }
}


私人Cirrious.MvvmCross.ViewModels.MvxCommand< INT> _navigateToAction;
公共System.Windows.Input.ICommand NavigateToAction
{
得到
{
_navigateToAction = _navigateToAction?新Cirrious.MvvmCross.ViewModels.MvxCommand&所述; INT>((动作)=> NavigateToTheDesiredAction(动作));
返回_navigateToAction;
}
}

私人无效NavigateToTheDesiredAction(INT行动)
{
ShowViewModel< ActionViewModel>(新{ID =动作});
}

//从服务器或从缓存中获取的DTO,并填写ActionViewModels
公共名单异步任务负载()
{
ActionService actionService =新ActionService();

名单,LT; ActionViewModel> actionViewModels =新的List< ActionViewModel>();

MyActions =等待actionService.GetMyActions();
的foreach(在MyActions ActionDTO行动)
{
ActionViewModel actionViewModel =新ActionViewModel();
等待actionViewModel.Load(action.id);
actionViewModels.Add(actionViewModel);
}

ActionViewModels = actionViewModels;
}



ActionViewModel.cs

 公众诠释ID 
{
{返回TheAction.id; }
集合{TheAction.id =价值; RaisePropertyChanged(()=和SEQ ID); }
}

公共字符串标题
{
{返回TheAction.Title; }
集合{TheAction.Title =价值; RaisePropertyChanged(()=>标题); }
}

公共异步任务负载(INT actionId)
{
ActionDTO TheAction =等待actionService.GetAction(actionId);
this.ID = TheAction.id;
this.Title = TheAction.Title;
}

私人Cirrious.MvvmCross.ViewModels.MvxCommand _save;
公共System.Windows.Input.ICommand节省
{
得到
{
_save = _save?新Cirrious.MvvmCross.ViewModels.MvxCommand(PreSaveModel);
返回_save;
}
}

私人无效PreSaveModel()
{
SaveModel();
}

私人异步任务SaveModel()
{
ValidationDTO结果=等待actionService.SaveAction(TheAction);
}



ActionService.cs

 公共静态列表< ActionDTO> AllActions =新的List< ActionDTO>(); 

公共异步任务< ActionDTO>的getAction(INT actionId)
{
ActionDTO行动= AllActions.FirstOrDefault(A => a.id == actionId);
如果(动作== NULL)
{
INT tempActionId =等待LoadAction(actionId);
如果(tempActionId大于0)
返回等待的getAction(actionId);
,否则
返回新ActionDTO(){错误=新ValidationDTO(假的,无法加载ID为动作+ actionId,ErrorCode.InvalidActionId)};
}
返回行动;
}

私人异步任务< INT> LoadAction(INT actionId)
{
ActionDTO行动=等待webservice.GetAction(actionId);
AllActions.Add(动作);
返回action.id;
}

公共异步任务< ValidationDTO> SaveAction(ActionDTO动作)
{
名单,LT; ActionDTO> currentList = AllActions;
ActionDTO removeActionFromList = currentList.FirstOrDefault(一个= GT; a.id == action.id);
如果(removeActionFromList!= NULL)
currentList.Remove(removeActionFromList);

currentList.Add(动作);
AllActions = currentList;
返回等待webservice.SaveAction(动作);
}


解决方案

有3种方式,我可以想到这将让你做到这一点。




  1. ActionService 可以发送出某种形式的通知时数据的变化。一个简单的方法来做到这一点是使用MvvmCross Messenger的插件。这是的 Col​​lectionService.cs在mvvmcross视频(更多信息的N +1天的看N的 HTTP: //mvvmcross.wordpress.com



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


  2. 您可以实现某种刷新的在名单上的API视图模型,并可以调用这从相应的View事件(如 ViewDidAppear 的OnNavigatedTo OnResume



    我一般不使用这种方法进行刷新已知的数据,但我已经用它的启用/禁用资源密集型的对象 - 例如计时器



    有关模型数据的特定形状(特别是它的改变频率),那么我可以想像场景中这种方法可能比信使的方法更有效。


  3. 您可以延长使用 INotifyPropertyChanged的 INotifyCollectionChanged 回到你的模型层。



    我这样做了几次,它的工作很适合我。



    如果你选择了这种方法,要小心,以确保所有的意见是赞同使用改变事件的WeakReference 订阅如在MvvmCross使用绑定 - 看的 WeakSubscription 。如果你不这样做,那么它可能是可能的模型引起浏览到内存本身甚至已取消他们的UI后仍然存在。



In my first view model (renamed to MainViewModel) I have a list of ActionViewModels. In my xaml i have a listbox which is bound to the list, in the listbox i have a template which binds to properties from the ActionViewModel.

So far so good and everything works. When selecting one of the listitems i navigate to an ActionViewModel and pass the id with it. The ActionViewModel retrieves information from a static list in memory from which the MainViewModel also retrieved the information to create the list of actionviewmodels.

So far still so good, i can edit the properties, all the bindings do work fine and i'm all happy. By clicking the save button the information is gathered and stored in the static list. When i hit the back button i go back to the list, but unfortunately the values showing there are still the same, is there some way to send a command to reload the items in the list? To pass a complete viewmodel as reference to a new ActionViewModel? Or some property which tells the parent 'this viewmodel in your list has been updated'?

I am sure the above text is a bit confusing, so here is some code to clarify it a bit (hopefully)

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);
}

解决方案

There are 3 ways I can think of that would allow you to do this.

  1. The ActionService could send out some sort of notification when data changes. One easy way to do this is to use the MvvmCross Messenger plugin. This is the way the CollectABull service works in CollectionService.cs in the N+1 days of mvvmcross videos (for more info watch N=13 in http://mvvmcross.wordpress.com)

    This is the approach I generally use. It has low overhead, uses WeakReferences (so doesn't leak memory), it is easily extensible (any object can listen for changes), and it encourages loose coupling of the ViewModel and Model objects

  2. You could implement some kind of Refresh API on the list ViewModel and could call this from appropriate View events (e.g. ViewDidAppear, OnNavigatedTo and OnResume).

    I don't generally use this approach for Refreshing known data, but I have used it for enabling/disabling resource intensive objects - e.g. timers

    For certain shape of model data (and especially how often it changes), then I can imagine scenarios where this approach might be more efficient than the messenger approach.

  3. You could extend the use of INotifyPropertyChanged and INotifyCollectionChanged back into your model layer.

    I've done this a few times and it's worked well for me.

    If you do choose this approach, be careful to ensure that all Views do subscribe to change events using WeakReference subscriptions such as those used in MvvmCross binding - see WeakSubscription. If you didn't do this, then it could be possible for the Model to cause Views to persist in memory even after the UI itself has removed them.

这篇关于我如何更新父视图模型时,子视图模型更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆