Observable collection not updated
Asked Answered
S

4

0

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

Shiller answered 14/11, 2013 at 15:20 Comment(3)
You've posted a lot of code there, but it's not clear from your question exactly what it is that's not working. Can you clarify?Asthmatic
Actually my view gets updated if I update any item in the observable collection in the viewmodel when I'm still in the view. But if I update the viewmodel from another view, hit back on my phone nothing happens. What am I doing wrong?Shiller
Are you updating the collection or an item in the collection?Tessietessier
T
1

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.

Tessietessier answered 14/11, 2013 at 20:38 Comment(1)
INotifyPropertyChanged is implemented and if you look at the InspectionMenuItem OnPropertyChanged is implemented. That code is implemented in my base class. The odd thing is that observable Collection updates the page. But not when I hit back on my phone.Shiller
S
0

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.

Sachi answered 15/11, 2013 at 8:29 Comment(3)
Implemented that method into my viewmodel and the event is fired when I replace an item in my collection with the correct action. But my gui is still not updated when I hit the back button on my phone. The viewmodel and datacontext has the updated item if I debug and set a breakpoint upon entering the view. Never had this problem when creating the items and binding directly in the xaml. But I have no choice in this solution, I have to add the content programmatically. I can solve it by deleting the content in the view and add it again but that feels like a bad solution.Shiller
When you navigate back again, try putting again the DataContext. Maybe the binding is deleted from the view and has to be restablished again.Sachi
Nope. Didn´t work. I added a click event on my view so I could update the Collection. The gui updates correctly, even if I hit back in the navigation and coming back to the view and trigger the event again. It´s only when I´m using the back button on my phone with an updated viewmodel these problems occur.Shiller
C
0

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

It worked in MY code

Ceto answered 16/11, 2013 at 7:20 Comment(0)
T
0

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.

Truffle answered 18/12, 2017 at 5:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.