Переключение WPF ListBox ItemsSource из ObservableCollection <T>в CollectionViewSource во время выполнения в MVVM - PullRequest
1 голос
/ 22 мая 2011

У меня есть 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 атрибутом ax: 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
    }

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

1 Ответ

1 голос
/ 29 мая 2011

Вы можете связать источник своего коллекционного обзора с наблюдаемой коллекцией. Мой вопрос: если вы используете mvvm, почему вы делаете все это в том, что похоже на codebehind?

Конструктор 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...
                }

            }

Обычно я использую сервис designtime для создания моих данных Designtime: но в этом случае я просто быстро и просто скопировал и вставил:

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 срабатывает только для элементов, добавленных или удаленных из коллекции. Используя vm фактического элемента списка, вы получите уведомление об изменении свойств элементов, если это необходимо.

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

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

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

...