Хобрук: Ваш путь к мастерству в программировании

ListBox DataBound to ObservableCollection в Windows Phone MVVM не обновляется после добавления

У меня есть ObservableCollection в ViewModel, который добавляет новые записи при нажатии кнопки ApplicationBar в View. ListBox, который привязан к этому ObservableCollection, не показывает новую / обновленную запись, он показывает элементы коллекции при загрузке приложения. ViewModel действительно реализует INotifyPropertyChanged, и я вызываю NotifyPropertyChanged, когда элемент добавляется в набор ObservableCollection (или).

ViewModel - на основе того, что считывается с сервера, новые элементы добавляются в наблюдаемую коллекцию.

public class MainViewModel : INotifyPropertyChanged
{
    private ObservableCollection<SubsViewModel> _itemsUnread;
    public ObservableCollection<SubsViewModel> UnreadItems
    {
        get
        {
            return _itemsUnread;
        }
        set
        {
            _itemsUnread = value;
            NotifyPropertyChanged("Updated");
        }
    }

   void reader_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        switch (e.PropertyName)
        {
            case "Updated":

                Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {
                        UnreadItems.Clear();

                        foreach (ItemViewModel subs in ItemsAll)
                        {
                                ....
                                UnreadItems.Add(subs);
                        }
                    }
                );

                IsDataUpdated = true;

                NotifyPropertyChanged(e.PropertyName);

                break;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName)
    {
        if (null != this.PropertyChanged)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

view - устанавливает datacontext и itemsource

            <ListBox x:Name="SecondListBox" Margin="0,0,-12,0" ItemsSource="{Binding UnreadItems, Mode=TwoWay}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Margin="0,0,0,7">
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding ItemTitle}" TextWrapping="NoWrap" Margin="12,0,0,0" Style="{StaticResource PhoneTextLargeStyle}"/>
...

    public MainPage()
    {
        _mainView = new MainViewModel();
        InitializeComponent();

        // Set the data context of the listbox control to the sample data
        DataContext = _mainView;
        this.Loaded += new RoutedEventHandler(MainPage_Loaded);
    }

Любое добавление / обновление наблюдаемой коллекции в viewModel не отражается в списке. Я прочитал кучу мест, где notifypropertychanged - это решение, но у меня уже есть notifypropertychanged, и я все еще вижу проблему. Есть идеи, что мне не хватает?

Из предложения @ compoenet_tech путем добавления нового элемента при нажатии кнопки ApplicationBar. Я вижу, что в списке отображается новый элемент

SubsViewModel newitem = new SubsViewModel();
newitem.itemTitle = "test";
newitem.itemCount = test;
_itemssUnread.Add(newitem); test++;

Итак, выполнение Add () вне Dispatcher Invoke действительно работает. Но теперь проблема в том, что я получаю новый список из веб-службы с помощью обратного вызова, и именно здесь я добавляю записи в коллекцию unreaditems. что я не могу (??) делать вне диспетчера.

(web service) =callback=> ViewModel =observablecollection=> View

как viewmodel получает уведомление об обновлении коллекции за пределами обратного вызова, когда мне не нужно использовать вызов диспетчера? (или) использовать вызов диспетчера и не допускать сбоев из-за перекрестной ссылки.

Спасибо


  • В установщике свойств UnreadItems вы вызываете NotifyPropertyChanged для именованного свойства Update, вы должны поднять его для UnreadItems. По крайней мере, я думаю, что проблема в этом. 21.12.2011
  • Теперь я понимаю, почему вы вызываете это с помощью Update, возможно, проблема в том, что вы обрабатываете событие изменения свойства, и оно не достигает пользовательского интерфейса. 21.12.2011

Ответы:


1
  1. Перед использованием создайте экземпляр коллекции Observable. В конструкторе MainViewModel напишите следующий код вроде

    общедоступная MainViewModel () {_itemsUnread = новая ObservableCollection (); }

  2. Функцию reader_PropertyChanged реализовывать не требуется.

  3. При вызове NotifyPropertyChanged используйте Имя свойства как параметр, например

    общедоступные ObservableCollection UnreadItems {получить {return _itemsUnread; } установить {_itemsUnread = значение; NotifyPropertyChanged («Непрочитанные элементы»); }}

21.12.2011
  • 1. Да, собранный инициализируется таким же образом. 2. reader_PropertyChanged - это обратный вызов от WebService, который получает новый список элементов. 21.12.2011
  • На мой взгляд, также реализуйте 3-й шаг и попробуйте. 22.12.2011

  • 2

    Пара замечаний:

    1) Согласно MSDN, ObservableCollection уже реализует INotificatCollectionChanged для Silverlight, поэтому вам не придется его повторно реализовывать.

    2) Этот код в сеттере:

            NotifyPropertyChanged("Updated");
    

    есть некоторые проблемы:

    a) он будет выполняться только при изменении всего объекта коллекции, а не при изменении элементов в коллекции.

    б) Если a реализован так, как вы хотите, то строковым параметром должно быть свойство, измененное на UnreadItems.

    Обновить

    Я также подозреваю (отмечено в комментариях ниже), что добавление элементов в Invoke приводит к потере уведомлений. Я рекомендую изменить код, чтобы добавлять элементы напрямую, а не в оператор Invoke.

    20.12.2011
  • Да, я понимаю две вышеупомянутые вещи. они были добавлены, чтобы попытаться решить проблему, но этого не произошло. Я добавил NotifyPropertychanged, когда установлен unreadItems, на случай, если я назначу ему новую коллекцию. Но здесь дело обстоит не так. 21.12.2011
  • ^^ Я имел в виду, что он не работал без явного вызова NotifyPropertyChanged (). 21.12.2011
  • @VasiS: хорошо. Вы проверили, действительно ли элементы добавляются в базовую коллекцию? Кроме того, пробовали ли вы добавлять элементы непосредственно в коллекцию, а не через Invoke (мне интересно, не проглатывается ли где-нибудь уведомление об изменении свойства)? 21.12.2011
  • Да, коллекция unreadItems действительно содержит обновленные и новые элементы. 21.12.2011
  • Вы правы, добавляя новый элемент при нажатии кнопки ApplicationBar. Я вижу, что в списке отображается новый элемент SubsViewModel newitem = new SubsViewModel(); newitem.itemTitle = "test"; newitem.itemCount = test; _itemssUnread.Add(newitem); test++; 21.12.2011
  • @component_tech элементы в настоящее время добавляются в уведомление об изменении свойства из модели (которая считывает веб-источник). Если я не использую диспетчер, он вылетает. 21.12.2011
  • @VasiS: Хорошо, я обновил свой ответ рекомендацией переместить добавление за пределы оператора Invoke. 21.12.2011
  • @component_tech, я получаю новый список из веб-сервиса с помощью обратного вызова, где я добавляю записи в коллекцию unreaditems. что я не могу (??) делать вне диспетчера. (веб-сервис) = callback = ›ViewModel = observablecollection =› Просмотр. как viewmodel получает уведомление об обновлении коллекции вне обратного вызова? 21.12.2011
  • извините, я продолжаю называть ваше имя component_tech :) 21.12.2011
  • есть идеи о том, как я могу удалить Диспетчер в этом сценарии? 21.12.2011

  • 3

    Свойство UnreadItems должно быть инициализировано в конструкторе с помощью

    UnreadItems = новый ObservableCollection ();

    20.12.2011
  • Он сказал, что с самого начала видит исходные значения, поэтому он уже сделал это где-то еще в своем коде. 21.12.2011
  • Да, он инициализируется в конструкторе MainViewModel. Я не копировал здесь код. 21.12.2011
  • Новые материалы

    Создание кнопочного меню с использованием HTML, CSS и JavaScript
    Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

    Внедрите OAuth в свои веб-приложения для повышения безопасности
    OAuth — это широко распространенный стандарт авторизации, который позволяет приложениям получать доступ к ресурсам от имени пользователя, не раскрывая его пароль. Это позволяет пользователям..

    Классы в JavaScript
    class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

    Как свинг-трейдеры могут использовать ИИ для больших выигрышей
    По мере того как все больше и больше профессиональных трейдеров и активных розничных трейдеров узнают о возможностях, которые предоставляет искусственный интеллект и машинное обучение для улучшения..

    Как построить любой стол
    Я разработчик программного обеспечения. Я люблю делать вещи и всегда любил. Для меня программирование всегда было способом создавать вещи, используя только компьютер и мое воображение...

    Обзор: Машинное обучение: классификация
    Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

    Разработка расширений Qlik Sense с qExt
    Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..