0

Hi I have a Category class where I am downloading data from API and displaying in Pivot, now for index 0 of Pivot the data loads, I have added a Pivot selection changed event when user flips to other PivotItems and data get loaded. But the issue is the ItemsSource is not updating. If I do like this pivot.itemssource=""; and pivot.itemssource=mylist; I have to change the pivot.selectedIndex to current index also, in this case the flip is not smooth, it first goes to 0 index because of pivot.itemssource=""; and then come to actual place. Please help me getting a solution for this so that it binds and update automatically. My classes are below:

Category.xaml

<Grid x:Name="LayoutRoot" >

        <controls:Pivot Margin="0,53,0,28" x:Name="CategoryList" Foreground="White" SelectionChanged="Pivot_SelectionChanged" ItemsSource="{Binding Constants.categoryDetails}" >
            <controls:Pivot.HeaderTemplate>
                <DataTemplate>
                    <TextBlock x:Name="PivotTitle" Text="{Binding name}"></TextBlock>
                </DataTemplate>
            </controls:Pivot.HeaderTemplate>
            <!--Panorama item one-->
            <controls:Pivot.ItemTemplate>
                <DataTemplate>
                    <Grid>
                       <ListBox x:Name="subCatList" ItemsSource="{Binding subcategories}" ScrollViewer.VerticalScrollBarVisibility="Visible">
                            <ListBox.ItemTemplate>
                                    <DataTemplate>
                                        <Border BorderThickness="2" BorderBrush="White">
                                            <Grid Width="420" Height="70" Background="#85000000">
                                                <TextBlock Text="{Binding name}"  FontFamily="Verdana" FontSize="35" Margin="10,10,64,5" TextWrapping="Wrap" ></TextBlock>
                                            </Grid>
                                        </Border>
                                    </DataTemplate>
                                </ListBox.ItemTemplate>
                       </ListBox>
                     </Grid>
                </DataTemplate>
            </controls:Pivot.ItemTemplate>
        </controls:Pivot>


    </Grid>



    <!--Panorama-based applications should not show an ApplicationBar-->

</phone:PhoneApplicationPage>

Category.cs

namespace MyApp.Views
{
    public partial class Category : PhoneApplicationPage
    {
                     List<WebClient> webclientsList = new List<WebClient>();
                     private int selectedIndex=0;
                    private ListBox subCatList;
                    public readonly DependencyProperty ListVerticalOffsetProperty;
                    public Category()
        {
            InitializeComponent();
            for (int i = 0; i < Constants.catList.Length; i++)
            {
                       WebClient wb = new WebClient();
                       CategoriesClass ct = new CategoriesClass();
                       ct.name = Constants.catList[i];
                       webclientsList.Add(wb);
                       Constants.categoryDetails.Add(ct);
            }
                  loadCategory();

        }

        private void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            selectedIndex = CategoryList.SelectedIndex;
            if (Constants.categoryDetails[selectedIndex].subcategories==null) {
                loadCategory();

            }
            else{

            }
        }

        private void loadCategory()
        {

            try
            {

                String Url = Constants.BASE_URL + "/get-category-data/?client_key=" + Constants.CLIENT_KEY;

                webclientsList[selectedIndex].DownloadStringCompleted += new DownloadStringCompletedEventHandler(webClientCategoryDownload);
                webclientsList[selectedIndex].DownloadStringAsync(new Uri(Url));

            }
            catch (Exception e)
            {
                Console.WriteLine("Error Occured"+e.StackTrace);
            }
        }

        void webClientCategoryDownload(object sender, DownloadStringCompletedEventArgs e)
        {
            try
            {
                if (e.Error != null)
                {
                    Console.WriteLine("Error geting category");
                    return;

                }

                CategoryClass ctClass = new CategoryClass();
                ctClass = JsonConvert.DeserializeObject<CategoryClass>(e.Result);



                if (ctClass.name!=null)
                {
                    Console.WriteLine("Category Loaded");
                    Constants.categoryDetails[selectedIndex].categoryDetails = ctClass;
                    Constants.categoryDetails[selectedIndex].subcategories = new ObservableCollection<SubCategories>();
                    foreach (var its in ctClass.categories)
                    {
                        foreach(var chi in its.children){

                            Constants.categoryDetails[selectedIndex].subcategories.Add(chi);
                        }

                    }


                    CategoryList.ItemsSource = "";
                    CategoryList.SelectedIndex = selectedIndex;
                    CategoryList.ItemsSource = Constants.categoryDetails;

                    for(int i=0;i<Constants.categoryDetails.Count;i++){

                        foreach (var x2 in Constants.categoryDetails[selectedIndex].subcategories)
                        {
                            Console.WriteLine("SubCategory is :"+x2.name);
                        }
                    }

                }
                else {

                    Console.WriteLine("Categories Doesnt Exists ");
                }

            }
            catch (Exception e1)
            {
                Console.WriteLine("Exception Occured:"+e1.StackTrace);
            }
        }

        private void Facebook_login(object sender, RoutedEventArgs e)
        {
            NavigationService.Navigate(new Uri("/Views/Login.xaml", UriKind.Relative));
        }

     }
}
jimpanzer
  • 3,470
  • 4
  • 44
  • 84
Artist404
  • 395
  • 4
  • 17

2 Answers2

0

First of all try to set

 pivot.itemssource=null;

And then

 pivot.itemssource=myList;

But it's wrong way.

If you want to become a good Windows Phone developer, you must to know what is MVVM.

First of all, you must read and UNDERSTAND this article

Then try to understand how to use existing mvvm toolkit, for example MVVM Light or Caliburn.Micro.

You should have a good understanding of how to work with MVVM and then you can solve your problem yourself.

Hope it's help.

Also check this useful question.

And this,this, this and this

Community
  • 1
  • 1
jimpanzer
  • 3,470
  • 4
  • 44
  • 84
  • I have read the article about MVVM, I am able to understand the functionality of MVVM, now when I update the collection it doesnt update in view, the Inotifyproperty is not updating, please help. – Artist404 Apr 29 '13 at 06:18
  • Anyways, I got a solution on my own... Thanks @jimpanzer for your help – Artist404 Apr 29 '13 at 13:27
  • 1
    @Artist404 You should add your own solution as answer and mark it as accepted solution. See [FAQ](http://stackoverflow.com/about) and [Help Center > Answering](http://stackoverflow.com/help/self-answer). – Sampo Sarrala - codidact.org Aug 05 '13 at 09:22
0

Below are the steps I followed for MVVM use in my project.

Install MVVM from silverlight
http://www.galasoft.ch/mvvm/installing/  Dont know the exact link but I think its available here.

Now restart your visual studio.

Go to Right click on your project and add new Items to your project.
Now add Model View Locator inside ViewModel  folder. (It will be good practice to keep these file 

into a new folder like ViewModel, View, Model)

Now you have created a viewlocator which handles all the process like cleaning for a viewmodel.

Now in the same folder create a modelview for your requirement edit like below, and also you are 

free to add more parameters acc to your requirement.

using GalaSoft.MvvmLight;
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using MyProject.Model;
namespace MyProject.ViewModel
{

    public class ProductViewModel : INotifyPropertyChanged
    {
         private ObservableCollection<ProductsClass> productData;

         public ObservableCollection<ProductsClass> ProductData
        {
            get
            {
                return productData;
            }

            set {
                productData = value;
                RaisePropertyChanged("ProductData");
            }
        }


         public ProductViewModel(ObservableCollection<ProductsClass> productData)
        {
            ProductData = productData;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;

        if (handler != null)

             {

                 handler(this, new PropertyChangedEventArgs(propertyName));

             }


    }





        /// <summary>
        /// Initializes a new instance of the ProductViewModel class.
        /// </summary>
        public ProductViewModel()
        {
            ////if (IsInDesignMode)
            ////{
            ////    // Code runs in Blend --> create design time data.
            ////}
            ////else
            ////{
            ////    // Code runs "for real": Connect to service, etc...
            ////}
        }

        ////public override void Cleanup()
        ////{
        ////    // Clean own resources if needed

        ////    base.Cleanup();
        ////}
    }
}



Now we have created our modelview, we have to mention something for this in our locator as 

follows(Make the necessary changes only):








namespace Myproject.ViewModel
{

    public class ViewModelLocator
    {





    private static MainViewModel _main;



        /// <summary>
        /// Initializes a new instance of the ViewModelLocator class.
        /// </summary>
        private static ProductViewModel _viewModelProduct;



        public ViewModelLocator()
        {


            CreateMain();

            CreateViewModelProduct();


        }



        /// <summary>
        /// Gets the Main property.
        /// </summary>
        public static MainViewModel MainStatic
        {
            get
            {
                if (_main == null)
                {
                    CreateMain();
                }

                return _main;
            }
        }

        /// <summary>
        /// Gets the Main property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
            "CA1822:MarkMembersAsStatic",
            Justification = "This non-static member is needed for data binding purposes.")]
        public MainViewModel Main
        {
            get
            {
                return MainStatic;
            }
        }

        /// <summary>
        /// Provides a deterministic way to delete the Main property.
        /// </summary>
        public static void ClearMain()
        {
            _main.Cleanup();
            _main = null;
        }

        /// <summary>
        /// Provides a deterministic way to create the Main property.
        /// </summary>
        public static void CreateMain()
        {
            if (_main == null)
            {
                _main = new MainViewModel();
            }
        }

        /// <summary>
        /// Cleans up all the resources.
        /// </summary>
        public static void Cleanup()
        {
            ClearMain();

            ClearViewModelProduct();

        }



        //Product model declaration

        /// <summary>
        /// Gets the ViewModelPropertyName property.
        /// </summary>
        public static ProductViewModel ProductViewModelStatic
        {
            get
            {
                if (_viewModelProduct == null)
                {
                    CreateViewModelProduct();
                }

                return _viewModelProduct;
            }
        }

        /// <summary>
        /// Gets the ViewModelPropertyName property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
            "CA1822:MarkMembersAsStatic",
            Justification = "This non-static member is needed for data binding purposes.")]
        public ProductViewModel ViewModelProduct
        {
            get
            {
                return ProductViewModelStatic;
            }
        }



        /// <summary>
        /// Provides a deterministic way to create the ViewModelPropertyName property.
        /// </summary>
        public static void CreateViewModelProduct()
        {
            if (_viewModelProduct == null)
            {
                _viewModelProduct = new ProductViewModel();
            }
        }

        /// <summary>
        /// Provides a deterministic way to delete the ViewModelPropertyName property.
        /// </summary>
        public static void ClearViewModelProduct()
        {
            //_main.Cleanup();
            _viewModelProduct = null;
        }


    }
}


Now inside your VIew create a variable like 

 private ProductViewModel pvm;

inside constructor add this:

 pvm = (ProductViewModel)Resources["pviewModel"];

Add this in your loaded method:

  Binding binding = new Binding("ProductData") { Source = pvm };


Like



 private void Product_Loaded(object sender, RoutedEventArgs e)
        {
            //Additional Code
            pvm.ProductData = Constants.productDet;
            //Additional Code          

            Binding binding = new Binding("ProductData") { Source = pvm };
        }


Now after adding some more code in your xaml file whenever you update anything in .cs it will 

automatically reflect in your view.


Make following in your xaml file:

DataContext="{Binding ViewModelProduct, Source={StaticResource Locator}}"
    Loaded="Product_Loaded"> at the top declaration



    <phone:PhoneApplicationPage.Resources>

        <viewModel:ProductViewModel x:Key="pviewModel" />

    </phone:PhoneApplicationPage.Resources>



Now the productsclass will be similar like this(its on u how u add parameters acc to ur requirement)





namespace Myproject.Model
{
    public class ProductsClass : INotifyPropertyChanged
    {
        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                if (name != value)
                {
                    name = value;
                    // NotifyPropertyChanged("Name");
                }
            }
        }


        private ProductClass productDetailsOverview;
        public ProductClass ProductDetailsOverview
        {
            get { return productDetailsOverview; }
            set
            {
                if (productDetailsOverview != value)
                {
                    productDetailsOverview = value;
                    NotifyPropertyChanged("ProductDetailsOverview");
                }
            }
        }


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

    }


    public class ProductClass 
    {

        public long product_start_offset { get; set; }
        public ObservableCollection<FiltersData> filters_data { get; set; }
        public long product_end_offset { get; set; }
        public long product_count { get; set; }
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }


and you can use ProductDetailsOverview in the itemssource to access any parameter like

ItemsSource="{Binding ProductDetailsOverview.product_list}
Artist404
  • 395
  • 4
  • 17