Silverlight MVVM标题详细信息

时间:2009-03-13 06:24:13

标签: silverlight mvvm header detail

假设我有一个OrderModel和一个OrderViewModel。我在ViewModel和Model上都有供应商,订单日期等属性,并且它们是相互关联的。看到这方面的例子并且似乎足够直截了当,尽管在编写setter / getter方面有些重复。

现在我如何处理OrderDetails?在我的模型中,我会有一个List。

OrderDetail是否有OrderDetailViewModel?如果是这样,那么OrderViewModel是如何提供的呢?作为ObservableCollection?如果是这样,你如何保持与原始列表同步?

这是我没有看到一个体面的例子。如果有人可以指出我,我会很感激。我嘲笑MVVM的概念,但我开始认为它是一个很大的开销。为什么不让ViewModel处理模型部分。在日常的LOB应用程序中,两者之间真的有很大差异,以保证真正的MVVM似乎需要的所有代码吗?

3 个答案:

答案 0 :(得分:1)

看起来这就是您所需要的:http://jonas.follesoe.no/SpeakingAtMSDNLiveNextMonth.aspx

谷歌上的翻译将此作为谈话的摘要:

Silverlight 2于今年秋季发布,为希望创建基于的富Internet应用程序(RIA)的开发人员奠定了良好的基础。净。在本次会议中,我们深入了解了Silverlight 2中的开发以及选择Silverlight 2作为以数据为中心的业务应用程序平台的好处。本次会议将讨论通过安全的WCF服务进行数据访问,如何使用模型 - 视图 - 模型模式(MVVM)构建代码,如何编写代码,设计人员可以使用以及为开发人员提供easy-Blend技巧。该会话将围绕潜水日志应用程序构建,其中代码将在演示后可用。

然而,同时Jonas已经在这里讨论过MVVM:

http://jonas.follesoe.no/YouCardRevisitedImplementingTheViewModelPattern.aspx

答案 1 :(得分:1)

您可以使用类似的东西来保持ObservableCollections在模型和视图模型之间保持同步:

/// <summary>
/// Keeps one collection synchronised with another.
/// </summary>
/// <typeparam name="Source">The type of the source items.</typeparam>
/// <typeparam name="Destination">The type of the destination items.</typeparam>
public class CollectionSync<Source, Destination>
{
    private readonly Func<Source, Destination> _destItemFactory;
    private readonly Action<Destination>       _destItemRemover;

    private readonly IList<Destination> _destList;
    private readonly IList<Source>      _sourceList;

    /// <summary>
    /// Initializes a new instance of the <see cref="CollectionSync&lt;Source, Destination&gt;"/> class.
    /// </summary>
    /// <param name="sourceList">The source list.</param>
    /// <param name="destList">The destination list.</param>
    /// <param name="destItemFactory">Factory method which creates a Destination for a given Source.</param>
    /// <param name="destItemRemover">Method called when a Destination is removed.</param>
    public CollectionSync(IList<Source> sourceList,
                          IList<Destination> destList,
                          Func<Source, Destination> destItemFactory,
                          Action<Destination> destItemRemover)
    {
        _destItemFactory = destItemFactory;
        _destItemRemover = destItemRemover;
        _sourceList = sourceList;
        _destList = destList;

        ((INotifyCollectionChanged) _sourceList).CollectionChanged += SourceCollection_CollectionChanged;

        PopulateWithAllItems();
    }

    private void PopulateWithAllItems()
    {
        foreach (Source sourceItem in _sourceList)
            _destList.Add(_destItemFactory(sourceItem));
    }

    private void SourceCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs args)
    {
        switch (args.Action)
        {
            case NotifyCollectionChangedAction.Add:
                OnItemsAdded(args.NewStartingIndex, args.NewItems);
                break;
            case NotifyCollectionChangedAction.Remove:
                OnItemsRemoved(args.OldStartingIndex, args.OldItems);
                break;
            case NotifyCollectionChangedAction.Reset:
                OnItemsReset();
                break;
            case NotifyCollectionChangedAction.Move:
            case NotifyCollectionChangedAction.Replace:
                throw new NotImplementedException();
        }
    }

    private void OnItemsReset()
    {
        _destList.Clear();
        PopulateWithAllItems();
    }

    private void OnItemsRemoved(int index, ICollection items)
    {
        int itemCount = items.Count;
        for (int i = 0; i < itemCount; i++)
        {
            Destination removed = _destList[index];
            _destList.RemoveAt(index);
            if (_destItemRemover != null)
                _destItemRemover(removed);
        }
    }

    private void OnItemsAdded(int index, IList items)
    {
        int itemIndex = index;
        foreach (Source item in items)
        {
            // Add to Items collection
            _destList.Insert(itemIndex, _destItemFactory(item));
            itemIndex++;
        }
    }
}

获取Order / OrderDetails示例,在Order视图模型中,您将连接两个ObservableCollections,如下所示:

_modelToViewModelSync = new CollectionSync<IOrderDetail, OrderDetailViewModel>(
    orderDetailModels,                 // the list of your order details models
    OrderDetails,                      // the list of order details view models exposed by the Order view model
    x => new OrderDetailViewModel(x),  // factory method to create a view model
    null);                             // do something here if you care when your view models are removed

答案 2 :(得分:0)

当谈到“我是否需要另一个视图模型”这个问题时,我的答案是这样的:如果您所有的视图都在显示模型数据,那么直接绑定到订单没有任何害处。为此创建ViewModel将非常多余。需要创建ViewModel的时间是在“订单详细信息”屏幕中有逻辑或状态需要表示的时间。您可以在此时创建ViewModel,而不是将其添加到模型中。

就保持这些项目同步而言,与GraemeF类似,我创建了一个Binder类,它使用反射将两个值绑定在一起。它使我的模型和视图模型属性保持同步,并且它可以用于使其他事物保持同步,就像这个特定的集合一样。创建这样的绑定器有一些开销,但一旦完成,您可以以功能方式指定数据关联,这非常好。