【问题标题】:Silverlight MVVM header detailSilverlight MVVM 标头详细信息
【发布时间】:2010-10-13 02:26:32
【问题描述】:

假设我有一个 OrderModel 和一个 OrderViewModel。我在 ViewModel 和 Model 上都有供应商、订单日期等属性,它们是链接在一起的。看过这方面的例子,看起来很简单,尽管在编写 setter/getter 方面有些重复。

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

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

这是我没有看到一个像样的例子的地方。如果有人可以指点我,我将不胜感激。我喜欢 MVVM 的概念,但我开始觉得它的开销太大了。为什么不让 ViewModel 也处理模型部分。在日常的 LOB 应用程序中,两者之间真的有那么大的区别来保证真正的 MVVM 似乎需要的所有代码吗?

【问题讨论】:

    标签: mvvm silverlight header detailsview


    【解决方案1】:

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

    谷歌上的翻译将此作为演讲的摘要:

    Silverlight 2 于今年秋季发布,为想要基于此创建富 Internet 应用程序 (RIA) 的开发人员奠定了良好的基础。网。在本次会议中,我们将深入探讨 Silverlight 2 的发展以及选择 Silverlight 2 作为以数据为中心的业务应用程序平台的好处。本次会议将涵盖通过安全 WCF 服务进行数据访问、如何使用模型-视图-视图模型模式 (MVVM) 构建代码、如何编写代码、设计人员可以使用以及为开发人员提供易于混合的技巧等内容.会议将围绕潜水日志应用程序构建,演示后代码将可用。

    但与此同时,Jonas 已经在这里谈到了 MVVM:

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

    【讨论】:

      【解决方案2】:

      你可以使用这样的东西来保持模型和视图模型之间的 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
      

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          猜你喜欢
          • 2012-08-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-12-12
          • 2016-08-16
          • 1970-01-01
          • 2011-01-30
          相关资源
          最近更新 更多