Jonas K
Jonas K

Reputation: 95

Observable collection not updated

Im having some trouble in my windows phone project.

The items I create programatically and add to my view doesn´t seem to get updated when using observable collection. The viewmodel and datacontext is correct but nothing happens in the view.

View:

async void OnLoaded(object sender, RoutedEventArgs e)
    {

        if (InspectionMainMenu.Children.Count() > 0)
            return;
        await InspectionMainPageViewModel.Instance.LoadData();
        this.DataContext = InspectionMainPageViewModel.Instance;



        int nrOfGridRows = InspectionMainPageViewModel.Instance.MenuItems.Count / 2;

        //check if there is need to add another row
        if (InspectionMainPageViewModel.Instance.MenuItems.Count % 2 > 0)
            nrOfGridRows++;

        Grid grid1 = new Grid();
        grid1.Name = "grid1";
        grid1.Margin = new Thickness { Top = 0, Left = 0, Bottom = 12, Right = 0 };
        InspectionMainMenu.Children.Add(grid1); // Note: parentControl is whatever control you are added this to
        grid1.ColumnDefinitions.Add(new ColumnDefinition());
        grid1.ColumnDefinitions.Add(new ColumnDefinition ());
        //grid1.DataContext = InspectionMainPageViewModel.Instance.MenuItems;
        //Binding myBinding = new Binding("MenuItems");
        //myBinding.Source = InspectionMainPageViewModel.Instance;

        //grid1.SetBinding(Grid.DataContextProperty, myBinding);
        //Add the dynamic rows
        for (int i = 0; i < nrOfGridRows; i++)
        {
            grid1.RowDefinitions.Add(new RowDefinition());
        }

        int currentRow = 0;
        int currentColumn = 0;
        int currentItem = 0;
        foreach(InspectionMenuItem item in InspectionMainPageViewModel.Instance.MenuItems)
        {

            InspectionCategory menuBox = new InspectionCategory();
            menuBox.Title = item.Header;
            menuBox.BgColor = App.Current.Resources["Blue"].ToString();
            menuBox.SetValue(Grid.RowProperty, currentRow);
            menuBox.SetValue(Grid.ColumnProperty, currentColumn);
            menuBox.Margin = new Thickness { Top = 0, Left = 6, Bottom = 6, Right = 6 };
            menuBox.IconType = "/images/appicons/"+ item.IconName +"";
            menuBox.Tap += test2_Tap;
            grid1.Children.Add(menuBox);

            if (currentItem % 2 > 0)
                currentRow++;

            if (currentItem % 2 > 0)
                currentColumn = 0;
            else
                currentColumn = 1;

            currentItem++;

        }

    }

Model:

 public class InspectionMenuItem : ViewModelBase
{

    string _header;
    string _bgColor;
    string _iconName;
    bool _isRead;

    public int id { get; set; }
    /// <summary>
    /// Header.
    /// </summary>
    public string Header 
    {
        get
        {
            return _header;
        }
        set
        {
            _header = value;
            OnPropertyChanged("Header");

        }
    }
    /// <summary>
    /// BgColor.
    /// </summary>
    public string BgColor
     {
        get
        {
            return _bgColor;
        }
        set
        {
            _bgColor = value;
            OnPropertyChanged("BgColor");

        }
    }
    /// <summary>
    /// IconName
    /// </summary>
    public string IconName
    {
        get
        {
            return _iconName;
        }
        set
        {
            _iconName = value;
            OnPropertyChanged("IconName");

        }
    }


}

ViewModel:

  public class InspectionMainPageViewModel : ViewModelBase, INotifyPropertyChanged
{
    private static InspectionMainPageViewModel instance;
    private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

    private ObservableCollection<InspectionMenuItem> menuItems;
    private ObservableCollection<ProtocolItem> protocolItems;

    private string chassisNumber;

    /// <summary>
    /// Initializes a new instance of the <see cref="MainViewModel"/> class.
    /// </summary>
    public InspectionMainPageViewModel()
    {
        this.menuItems = new ObservableCollection<InspectionMenuItem>();
        this.protocolItems = new ObservableCollection<ProtocolItem>();
    }

    /// <summary>
    /// Gets the instance.
    /// </summary>
    public static InspectionMainPageViewModel Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new InspectionMainPageViewModel();
            }

            return instance;
        }
    }

    public ObservableCollection<InspectionMenuItem> MenuItems
    {
        get
        {
            return this.menuItems;
        }
    }

    public ObservableCollection<ProtocolItem> ProtocolItems
    {
        get
        {
            return this.protocolItems;
        }
    }

    public string  ChassisNumber
    {
        get
        {
            return this.chassisNumber;
        }
    }
    /// <summary>
    /// Gets or sets a value indicating whether this instance is data loaded.
    /// </summary>
    public bool IsDataLoaded
    {
        get;
        set;
    }

    public async Task LoadData()
    {
        if (this.IsDataLoaded)
        {
            return;
        }
        GetMenuItems();
        GetProtocolItems();

        SetDummyData();
       // this.news = await CRMService.GetNews();
        this.IsDataLoaded = true;
    }

    private void SetDummyData()
    {
        this.chassisNumber = "JN1HS36P8LW107899";
    }


    public void GetMenuItems()
    {
        this.menuItems.Add(new InspectionMenuItem { Header = "Kund", IconName = "user_128.png", BgColor = "Blue" });
        this.menuItems.Add(new InspectionMenuItem { Header = "Fordon", IconName = "car_128.png", BgColor = "Blue" });
        this.menuItems.Add(new InspectionMenuItem { Header = "Identifiering", IconName = "check_128.png", BgColor = "Blue" });
        this.menuItems.Add(new InspectionMenuItem { Header = "Anmärkning", IconName = "user_128.png", BgColor = "Blue" });
        this.menuItems.Add(new InspectionMenuItem { Header = "Test", IconName = "user_128.png", BgColor = "Blue" });
    }

    public void GetProtocolItems()
    {
        this.protocolItems.Add(new ProtocolItem { Header = "Spindelled", Summary = "Fastsättning bristfällig", ProtocolImageUri = "user_128.png" , State="Tidigare anmärkningar"});
        this.protocolItems.Add(new ProtocolItem { Header = "Färdbroms bromsskiva", Summary = "Risk för bromsbortfall", ProtocolImageUri = "user_128.png", State = "Tidigare anmärkningar" });
        this.protocolItems.Add(new ProtocolItem { Header = "Infästning bromssystem", Summary = "Sprickor", ProtocolImageUri = "user_128.png", State = "Tidigare anmärkningar" });
        this.protocolItems.Add(new ProtocolItem { Header = "Motor", Summary = "Topplocket sprucket", ProtocolImageUri = "user_128.png", State = "Anmärkningar" });
        this.protocolItems.Add(new ProtocolItem { Header = "Lysen", Summary = "Felvinklat halvljus", ProtocolImageUri = "user_128.png", State = "Anmärkningar" });
        this.protocolItems.Add(new ProtocolItem { Header = "Kylare", Summary = "Läckande kylare", ProtocolImageUri = "user_128.png", State = "Anmärkningar" });
    }


}

Any suggestions on how to solve this?

Best regards, Jonas

Upvotes: 0

Views: 2317

Answers (4)

Zahoor Ahmad
Zahoor Ahmad

Reputation: 11

As you say "But if I update the viewmodel from another view, hit back on my phone nothing happens."

Just confirm if you are creating new object of ViewModel in other view or not. If yes then you might be updating observable collection of this newly created instance.

Try making your viewModel singleton.

Upvotes: 0

techloverr
techloverr

Reputation: 2617

If you want this functionality, you should Imaplement INotifyPropertyChanged in ViewModel also

It worked in MY code

Upvotes: 0

Joshua Rogers
Joshua Rogers

Reputation: 3568

You have an Event called OnCollectionChanged try with that:

http://msdn.microsoft.com/en-us/library/ms668604(v=vs.110).aspx

You can watch when the an element is added to a collection or deleted, cleared...

 obsList.CollectionChanged += (sender, eventArgs) =>
                {
                    switch (eventArgs.Action)
                    {
                        case NotifyCollectionChangedAction.Remove:
                            foreach (var oldItem in eventArgs.OldItems)
                            {

                            }

                            break;
                        case NotifyCollectionChangedAction.Add:

                            break;
                    }
                };

when that happen, draw again your view.

Upvotes: 0

chustar
chustar

Reputation: 12465

The ObservableCollection should automatically update if you add or remove items from the collection.

If you modify the contents of the collection itself though, you would need to fire some events to notify the view that the element has changed. That is, the Model should implement INotifyPropertyChanged.

Upvotes: 1

Related Questions