1

我在一个绑定到 WPFView 的 MVVM 项目中有一个 ViewModel,该 WPFView 包含一个列表框,当您开始搜索时,数据会在其中异步加载。我的搜索返回的数据包含在不同日期购买的相同商品的价格。我需要按价格升序对列表框中的项目进行排序:一旦我的 BackgroundWorker 返回项目,这些项目就会异步添加到我的列表框中并按价格排序,让我在捕获时看到最优惠的价格。

我发现更好的解决方案是在我的 ViewModel 中有一个 ObservableCollection 并将它绑定到我的 ListBox 的 ItemsSource 我有一个启动异步搜索的 BackgroundWorker;我订阅了执行搜索的对象的 DataReceived EventHandler,并像这样通知 UI:

void sniper_DataReceived(object sender, TEventArgs e)
    {
        Action dispatchAction = () => this.Results.Add(e.T);
        _currentDispatcher.BeginInvoke(dispatchAction);
    }

通过调度程序

private readonly Dispatcher _currentDispatcher;

这对我来说似乎没问题,但没有按我的需要订购物品,所以我发现 CollectionViewSource 以一种简单的方式完全符合我的需要。

这就是问题所在:

如果我将列表框的 datacontext 设置为 CollectionViewSource,我的设计时功能会减少,我会一直在列表框中看到我的设计时数据,但在 Blend 的“数据”选项卡中丢失了 DataContext。

所以我做了一些我认为有点脏的事情:我用 ax:Name 属性命名了我的 ListBox,并在我的 MainWindow.xaml 中添加了一些代码,以便在运行时交换我命名的列表框的数据源,如下所示:

public MainWindow()
    {
        InitializeComponent();
        Closing += (s, e) => ViewModelLocator.Cleanup();

        #region CollectionViewSource Escamotage
        if (!ViewModelLocator.MainStatic.IsInDesignMode)
        {
            var cvs = new CollectionViewSource() { Source = ViewModelLocator.MainStatic.Results };
            cvs.SortDescriptions.Add(new SortDescription("LowestPrice", ListSortDirection.Ascending));
            this.TrainsListBox.ItemsSource = cvs.View; 
        }
        #endregion
    }

你认为它可以被认为是一种罪过吗?

4

1 回答 1

1

您可以将 collectionview 的源绑定到 observablecollecion。我的问题是:如果您使用的是 mvvm,为什么要以代码隐藏的方式执行所有这些操作?

ViewModel 构造函数:

 public PrimarySearchViewModel()
            {
                this.SearchResultsCVS = new CollectionViewSource();

                if (IsInDesignMode)
                {
                    DesignMode_CreateSearchResults();

                    // Code runs in Blend --> create design time data.
                }
                else
                {
                    //Messenger.Default.Register<IEnumerable<ReadmitPatientList>>(this, MessageTypes.EXECUTESEARCHREQUEST, RefreshSearchResults);
                    //Messenger.Default.Register<MessageTypes.EXECUTESEARCHREQUEST>>(this,ICollection<ReadmitPatientList>,RefreshSearchResults);
                    Messenger.Default.Register<Messages.DisplayReadmitPatientListMessage>(this, onReciveDisplayReadmitPatientListMessage);
                    Messenger.Default.Register<WavelengthIS.Core.Messaging.SaveNotification<QuestionairreViewModel>>(this, sn => ClearSearchResults());
                    // Code runs "for real": Connect to service, etc...
                }

            }

我通常使用设计时间服务来创建我的设计时间数据:但在这种情况下,我只是做了一个快速而肮脏的复制和粘贴:

private void DesignMode_CreateSearchResults()
            {
                this.SearchResults = new ObservableCollection<ReadmitPatientListViewModel>();

                this.SearchResults.Add(new ReadmitPatientListViewModel(new ReadmitPatientList()
                {
                    PatientID = 0000000,
                    PatientName = "Test Patient",
                    PatientDOB = Convert.ToDateTime("01/01/2010"),
                    OriginalAdmitDate = Convert.ToDateTime("01/01/2010 00:00:00"),
                    OriginalReason = "Becauselkahsdfkahsfkahsf",
                    OriginalVisitNumber = "0000000",
                    ReAdmitDate = Convert.ToDateTime("01/01/2010 00:00:00"),
                    ReAdmitReason = ";aasfkahsfashfa;lsfas",
                    ReAdmitVisitNumber = "9999999"
                }
                   ));
                this.SearchResults.Add(new ReadmitPatientListViewModel(new ReadmitPatientList()
                {
                    PatientID = 0000000,
                    PatientName = "Test Patient",
                    PatientDOB = Convert.ToDateTime("01/01/2010"),
                    OriginalAdmitDate = Convert.ToDateTime("01/01/2010 00:00:00"),
                    OriginalReason = "Becauselkahsdfkahsfkahsf",
                    OriginalVisitNumber = "0000000",
                    ReAdmitDate = Convert.ToDateTime("01/01/2010 00:00:00"),
                    ReAdmitReason = ";aasfkahsfashfa;lsfas",
                    ReAdmitVisitNumber = "9999999"
                }
                   ));
                this.SearchResults.Add(new ReadmitPatientListViewModel(new ReadmitPatientList()
                {
                    PatientID = 0000000,
                    PatientName = "Test Patient",
                    PatientDOB = Convert.ToDateTime("01/01/2010"),
                    OriginalAdmitDate = Convert.ToDateTime("01/01/2010 00:00:00"),
                    OriginalReason = "Becauselkahsdfkahsfkahsf",
                    OriginalVisitNumber = "0000000",
                    ReAdmitDate = Convert.ToDateTime("01/01/2010 00:00:00"),
                    ReAdmitReason = ";aasfkahsfashfa;lsfas",
                    ReAdmitVisitNumber = "9999999"
                }
                   ));

                SearchResultsCVS_Refresh();
            }
private void SearchResultsCVS_Refresh()
        {
            SearchResultsCVS.Source = this.SearchResults;
            SearchResultsCVS.SortDescriptions.Clear();

            SearchResultsCVS.SortDescriptions.Add(new System.ComponentModel.SortDescription("PatientLastName", System.ComponentModel.ListSortDirection.Ascending));

            SearchResultsCVS.View.Refresh();
        }

我使用 ViewModels 的 ObservableCollections。OC 的通知事件仅针对从集合中添加或删除的项目触发,通过使用实际列表项的 vm,如果需要,您可以获得项目属性的更改通知。

您还需要确保您的 ViewModelLocator 设置和定义正确。我现在发现了几篇关于人们使用 MVVMLight 但没有使用其中一些最强大功能的帖子。如果您按照设计使用它来使用它,它的工作原理就像它应该工作的那样......我可以证明这一点。

 <!--Global View Model Locator-->
                    <local:ViewModelLocator x:Key="Locator"
                                            d:IsDataSource="True" />

我相信 IsDataSource 属性会告诉 Blend 将其放在 DataTab 上......但我并没有为我的 Datamanipulations 使用那么多混合,所以我并不担心它。

于 2011-05-29T12:25:36.823 回答