简体   繁体   English

从ObservableCollection切换WPF ListBox ItemsSource <T> MVVM在运行时访问CollectionViewSource

[英]Switching a WPF ListBox ItemsSource from ObservableCollection<T> to CollectionViewSource at runtime in MVVM

I have a ViewModel in a MVVM project that is bound to a WPFView that contains a listbox where data is loaded asynchronously when you start a search. 我在MVVM项目中有一个ViewModel,它绑定到WPFView,后者包含一个列表框,在其中启动搜索时会异步加载数据。 The data that my search return contains prices for the same items bought in different days. 我的搜索返回的数据包含不同日期购买的相同商品的价格。 I need the items in my listbox to be ordered ascending by price: as soon my BackgroundWorker returns items, those are asynchronously added in my listbox and ordered by price, letting me to see the best price as soon it is caught. 我需要将列表框中的项目按价格升序排列:当我的BackgroundWorker返回项目时,这些项目将异步添加到我的列表框中并按价格进行排序,这样一来,我便可以立即查看到最佳价格。

The better solution I found is having an ObservableCollection in my ViewModel and bind it to the ItemsSource of my ListBox I have a BackgroundWorker that starts the asynch search; 我发现更好的解决方案是在ViewModel中有一个ObservableCollection并将其绑定到ListBox的ItemsSource。我有一个BackgroundWorker,它开始进行异步搜索; I'm subscribed to a DataReceived EventHandler of the object that does the search and I notify the UI like this: 我订阅了执行搜索的对象的DataReceived EventHandler,并这样通知UI:

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

through a Dispatcher 通过分派器

private readonly Dispatcher _currentDispatcher;

This seems ok to me but doesn't order the items as I need so I found thet CollectionViewSource does exactly what I need in a simple way. 这对我来说似乎可以,但是没有按我的需要订购商品,因此我发现CollectionViewSource可以用一种简单的方式完全满足我的需求。

Here it is the problem: 这是问题所在:

If I set the datacontext of my listbox to the CollectionViewSource I have less design time power, I keep seeing my design time data in my listbox but I lose the DataContext in the Data tab of Blend. 如果我将列表框的datacontext设置为CollectionViewSource,则我的设计时间功能较少,我会继续在列表框中看到设计时数据,但是在Blend的“数据”选项卡中丢失了DataContext。

So I did something that I think is a bit dirty: I named my ListBox with ax:Name attribute and added a bit of code behind in my MainWindow.xaml to swap the datasource of my named listbox at run time like this: 因此,我做了一些我认为有点肮脏的事情:我用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
    }

Do you think it can be considered a sin? 您是否认为这是一种罪过?

You can bind the source of your collectionview to the observablecollecion. 您可以将集合视图的源绑定到observablecollecion。 My question is: if you are using mvvm why are you doing all of this in what looks like codebehind? 我的问题是:如果您使用的是mvvm,为什么要按照代码隐藏的方式进行所有这些操作?

ViewModel constructor: 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...
                }

            }

I normally use a designtime service to create my Designtime Data: but in this case I just did a quick and dirty copy and paste: 我通常使用设计时服务来创建我的设计时数据:但是在这种情况下,我只是进行了快速而肮脏的复制和粘贴:

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

I use ObservableCollections of ViewModels. 我使用ViewModels的ObservableCollections。 OC's notification event only fires for items added or removed from the collection, by using a vm of the actual list item, you get change notification of the items properties if need be. OC的通知事件仅针对添加或从集合中删除的项目触发,通过使用实际列表项目的虚拟机,如果需要,您将获得项目属性的更改通知。

also you need to make sure you have your ViewModelLocator setup and defined right. 此外,您还需要确保已设置ViewModelLocator并正确定义了它。 I have found several posts now of people using MVVMLight but not using some of the most powerful features from it. 我现在发现了一些使用MVVMLight的人的帖子,但没有使用其中的一些最强大的功能。 If you use it as its designed to be used, it works like its supposed to work...I can attest to that. 如果您将其用作要使用的设计,它的工作原理应该与它的预期效果一样...我可以证明这一点。

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

I believe the IsDataSource attribute tells Blend to put it on the DataTab...But I dont use blend all that much for my Datamanipulations so I am not that worried about it. 我相信IsDataSource属性告诉Blend将其放在DataTab上...但是我对Datamanipulations并没有使用太多的blend,所以我对此并不担心。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 WPF MVVM ListBox / ComboBox ItemsSource不会从ViewModel更新UI - WPF MVVM ListBox/ComboBox ItemsSource won't update UI from ViewModel WPF - 使用ObservableCollection作为itemssource的列表框失效? - WPF - Invalidate a listbox which using as itemssource an ObservableCollection? 在WPF / MVVM中将ObservableCollection绑定到列表框时遇到问题 - Problem Binding a ObservableCollection to a ListBox in WPF/MVVM MVVM WPF ObservableCollection:错误附加项,ItemsSource绑定 - MVVM WPF ObservableCollection : Error addign items, ItemsSource binding WPF MVVM 将项目源绑定到不同 class 内的 ObservableCollection 并向其添加项目 - WPF MVVM Binding of itemssource to an ObservableCollection inside a different class and add items to it WPF ListBox.ItemsSource = ObservableCollection-加载时间很长 - WPF ListBox.ItemsSource = ObservableCollection - takes a long time to load 绑定ObservableCollection <ObservableCollection<T> &gt;到WPF ListBox - Binding ObservableCollection<ObservableCollection<T>> to WPF ListBox 列表框是否保留每个ItemsSource的CollectionViewSource? - Does ListBox keep the CollectionViewSource per ItemsSource? MVVM-如何将字符串的ObservableCollection绑定到ListBox WPF中 - MVVM-How to Binding ObservableCollection of Strings into ListBox WPF 使用ObservableCollection上的CollectionViewSource进行列表框实时排序 - Listbox live sort using CollectionViewSource on ObservableCollection
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM