Переключение WPF ListBox ItemsSource из ObservableCollection ‹T› в CollectionViewSource во время выполнения в MVVM

У меня есть ViewModel в проекте MVVM, который привязан к WPFView, который содержит список, в который данные загружаются асинхронно при запуске поиска. Данные, возвращаемые моим поиском, содержат цены на одни и те же товары, купленные в разные дни. Мне нужно, чтобы элементы в моем списке были упорядочены по возрастанию по цене: как только мой BackgroundWorker возвращает элементы, они асинхронно добавляются в мой список и упорядочиваются по цене, что позволяет мне видеть лучшую цену, как только она будет обнаружена.

Лучшее решение, которое я нашел, - это наличие ObservableCollection в моей ViewModel и привязка его к ItemsSource моего ListBox. У меня есть BackgroundWorker, который запускает асинхронный поиск; Я подписан на DataReceived EventHandler объекта, выполняющего поиск, и уведомляю пользовательский интерфейс следующим образом:

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

через диспетчера

private readonly Dispatcher _currentDispatcher;

Мне это кажется нормальным, но элементы не упорядочиваются так, как мне нужно, поэтому я обнаружил, что CollectionViewSource делает именно то, что мне нужно, простым способом.

Вот в чем проблема:

Если я установил для контекста данных своего списка значение CollectionViewSource, у меня меньше возможностей для разработки, я продолжаю видеть данные о времени разработки в своем списке, но теряю DataContext на вкладке «Данные» в Blend.

Итак, я сделал что-то, что, на мой взгляд, немного грязно: я назвал свой ListBox атрибутом x: Name и добавил немного кода в свой 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
    }

Как вы думаете, это можно считать грехом?


person JackNova    schedule 22.05.2011    source источник
comment
если это хорошо работает для вас и делает вас счастливым, я не понимаю, почему вы считаете это грехом;)   -  person AbdouMoumen    schedule 23.05.2011


Ответы (1)


Вы можете привязать источник вашего представления коллекции к наблюдаемой коллекции. У меня вопрос: если вы используете 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();
        }

Я использую ObservableCollections ViewModels. Событие уведомления OC запускается только для элементов, добавленных или удаленных из коллекции, используя виртуальную машину фактического элемента списка, вы получаете уведомление об изменении свойств элементов, если это необходимо.

Также вам необходимо убедиться, что ваш ViewModelLocator настроен и правильно определен. Я нашел несколько сообщений о людях, использующих MVVMLight, но не использующих некоторые из самых мощных его функций. Если вы используете его так, как он предназначен для использования, он работает так, как должен работать ... Я могу засвидетельствовать это.

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

Я считаю, что атрибут IsDataSource сообщает Blend, что нужно поместить его в DataTab ... Но я не использую blend для своих манипуляций с данными, поэтому меня это не беспокоит.

person ecathell    schedule 29.05.2011