I am new to WP8 and MVVM. I created a wp8 application that requests various bits of data after a user logs in. I just can't get the Pivots header for dynamic creation, and I don't know if this is due to the fact that I'm doing something in a binding, INotifyPropertyChanged, both or something else !!
Here is what I have done so far:
I have a global MainViewModel defined in App.cs that will save all the data returned during login.
Once the login is successful and the data is loaded into the MainViewModel, I redirect it to the test page containing the Pivot Control, and I try to create Pivot Items dynamically.
This is xaml for my test page, i.e. MainPivotPage.xaml, and my MainPivotViewModel is initialized because it is defined as a local resource and set as a datacontext for the Pivot element, and I don’t know if I am doing this but I assign the Name property to the PivotItem header. which is an object stored in my observed Pivots collection. The property name is one of two properties that I have in a class called Pivot, which contains PivotId and Name.
<phone:PhoneApplicationPage x:Class="TestApp.Views.MainPivotPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:viewModel="clr-namespace:TestApp.ViewModels" mc:Ignorable="d" FontFamily="{StaticResource PhoneFontFamilyNormal}" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="{StaticResource PhoneForegroundBrush}" SupportedOrientations="Portrait" Orientation="Portrait" shell:SystemTray.IsVisible="True" Loaded="PhoneApplicationPage_Loaded"> <phone:PhoneApplicationPage.Resources> <viewModel:MainPivotViewModel x:Key="MainPivotViewModel" /> </phone:PhoneApplicationPage.Resources> <Grid x:Name="LayoutRoot" Background="Transparent"> <phone:Pivot Title="My Search Options" x:Name="MainPivots" ItemsSource="{Binding Pivots}" DataContext="{StaticResource MainPivotViewModel}"> <phone:PivotItem Header="{Binding Name}"> </phone:PivotItem> </phone:Pivot> </Grid> </phone:PhoneApplicationPage>
When the MainPivotViewModel is created, I set the Pivots observable collection to the same observable collection that is stored in my MainViewModel, which contains all the data returned at login. As you can see, I'm assigning it to a property, not an internal variable, to make sure it calls INotifyPropertyChanged (well ... I think)
public class MainPivotViewModel : BaseViewModel { private ObservableCollection<Pivot> _pivots = null; public MainPivotViewModel() { Pivots = App.MainViewModel.Pivots; } public ObservableCollection<Pivot> Pivots { get { return _pivots; } set { if (_pivots != value) this.SetProperty(ref this._pivots, value); } } }
I use the SetProperty function, which is contained in my base class and is used to generate the INotifyPropertyChanged event and allows me to do this without setting the property name every time I need the INotifyPropertyChanged event.
This is the code for my BaseView:
public class BaseViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null) { if (object.Equals(storage, value)) return false; storage = value; this.OnPropertyChanged(propertyName); return true; } protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { var eventHandler = this.PropertyChanged; if (eventHandler != null) { eventHandler(this, new PropertyChangedEventArgs(propertyName)); } } }
The My Pivot class is as follows:
public class Pivot: BaseModel { private int _pivotId; private string _name = string.Empty; public Pivot() { } public Pivot(int pivotId, string name) { PivotId = pivodId; Name = name; } public int PivotId { get { return _pivotId; } set { if (_pivotId != value) this.SetProperty(ref this._pivotId, value); } } public string Name { get { return _name; } set { if (_name != value) this.SetProperty(ref this._name, value); } } }
You may notice that this inherits from BaseModel. This is exactly the same code as in BaseViewModel, but I would like to keep these two separate. I'm not sure if this is necessary for my Pivot class, but I used a different script and left it for now.
I don’t know what I'm doing wrong, but no matter what I try, I can’t get the “Name” property, which will display as the title text. I am sure that MainPivotViewModel is initialized when it is assigned as a local resource, since I will correctly name my constructor, which then initializes my observable collection, but as much as possible.
But he shows absolutely nothing!
Another thing I noticed is when I set breakpoints in the OnPropertyChanged method in the BaseViewModel class, eventHandler is always null, whatever I assume should not be, but I can't see what I'm doing wrong .
I have a lot of articles on stackoverflow and others, and I just can't see what I'm doing wrong? Does anyone have any ideas?
Thanks.