2013-03-27 67 views
4

我是WP8的新手& MVVM。我創建了wp8應用程序,它在用戶登錄後請求各種數據位。我只是無法讓我的pivot標題動態創建,我不知道是否因爲我在綁定中做了某些事情, INotifyPropertyChanged,兩者或別的東西!使用Observable Collection MVVM綁定樞軸控件(windows phone 8)

這是我迄今所做的:

我得在App.cs定義的全局MainViewModel將存儲在用戶登錄時都返回的數據。

一旦登錄成功並且數據已被加載到MainViewModel中,我將其重定向到包含數據透視控件的測試頁面,並試圖動態創建數據透視項目。

這是我的測試頁的xaml,即MainPivotPage.xaml和我的MainPivotViewModel被初始化,因爲它被定義爲本地資源,並且設置爲數據透視控件的數據上下文,我不知道我是否在做這個權利,但我將「名稱」屬性分配給PivotItem的Header,這是存儲在我的可觀察集合Pivots中的對象。屬性Name是我在一個名爲Pivot的類中包含PivotId和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"> 
    <!--LayoutRoot is the root grid where all page content is placed--> 

    <phone:PhoneApplicationPage.Resources> 
     <viewModel:MainPivotViewModel x:Key="MainPivotViewModel" /> 
    </phone:PhoneApplicationPage.Resources> 

    <Grid x:Name="LayoutRoot" Background="Transparent"> 
     <!--Pivot Control--> 
     <phone:Pivot Title="My Search Options" x:Name="MainPivots" ItemsSource="{Binding Pivots}" DataContext="{StaticResource MainPivotViewModel}"> 
      <phone:PivotItem Header="{Binding Name}"> 
       <!--<Grid/>--> 
      </phone:PivotItem> 
     </phone:Pivot> 
    </Grid> 
</phone:PhoneApplicationPage> 

在創建MainPivotViewModel,我的支點觀察集合設置爲存儲在我的MainViewModel同樣觀察到的集合包含在登錄所有返回的數據。正如你可以看到我把它分配給屬性,而不是內部變量,以確保它會觸發INotifyPropertyChanged的(嗯...,我認爲)

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); 
     } 
    } 
} 

我使用的是包含在我的基地的SetProperty功能類並用於生成INotifyPropertyChanged事件,並允許我在不需要設置屬性名稱的情況下每次需要INotifyPropertyChanged事件時都這樣做。

這是我的基本視點代碼:

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)); 
     } 
    } 
} 

我的透視類看起來是這樣的:

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); } 
    } 
} 

您可能注意到,這個人是從BaseModel繼承。這與BaseViewModel中的代碼完全相同,但我希望將兩者分開。我不是事件,肯定這是我的Pivot類需要的,但我嘗試了不同的場景,現在就把它留下。

我不知道我在做什麼錯,但無論我嘗試什麼,我都無法使「名稱」屬性顯示爲標題的文本。我很確定MainPivotViewModel被初始化時,它被分配爲本地資源,因爲它正確地調用我的構造函數,然後初始化我的可觀察集合,但這就像它一樣。

但它絕對沒有顯示!

我注意到的另一件事是,當我在BaseViewModel類的OnPropertyChanged方法的「Set」中放置斷點時,eventHandler始終爲空,無論我認爲應該如何,但我可以'看看我做錯了什麼。

我有很多關於stackoverflow和其他人的文章,我只是不明白我做錯了什麼?任何人有任何想法?

謝謝。

+0

你是否在任何地方設置了你的頁面的'DataContext'? – 2013-03-27 07:12:26

+0

嗨,是的,它設置在上面的xaml中。這只是不可見,但如果你滾動,你會看到它被設置。 – Thierry 2013-03-27 13:00:22

+0

你有一個'Pivot'的ObservableCollection。這些是你自己的班級嗎?如果是這樣,他們看起來像什麼? – 2013-03-27 15:00:18

回答

3

問題已解決!!!

我的代碼一直都是正確的,但XAML不是!

陡峭而痛苦的學習曲線我猜!無論如何,我找到了一個關於stackoverflow的文章後找到了一個解決方案,它基本上向我展示了我編寫xaml的方式並不合適。

我會老實說,我不明白爲什麼這不符合它的定義方式,但總之,我必須使用HeaderTemplate和ItemTemplate才能在綁定到ViewModel時正確顯示數據!

下面是帖子:Databound pivot is not loading the first PivotItem in Windows Phone 8

1

這一切對我來說都很好,所以我在考慮在構造函數被調用時(因此Pivot控件是空的)App.MainViewModel.Pivots爲null或空,並且最終創建一個新的實例在MainPivotViewModel實例化後,您的MainViewModel中的樞軸。

您是否嘗試過在MainPivotViewModel.Pivots的getter中放置斷點以確認是否有一些項目?

+0

我已經在我的代碼中放入了各種斷點,並且我可以清楚地看到

a)MainPivotViewModel被初始化並且僅在我離開本地資源xaml定義時才被初始化。

b)可觀察集合Pivots被設置爲App.MainViewModel.Pivots

c)App.MainViewModel.Pivots包含數據。這個特定的集合包含3個樞軸返回。

如上所述,在單步執行代碼時,我發現var eventHandler = this.PropertyChanged;總是返回null。會不會是這樣,但爲什麼? – Thierry 2013-03-27 22:48:25

+0

我注意到的另一件事是當我遍歷代碼時,我的DataContext是通過xaml設置的,但是當我在後面的代碼中查看DataContext時,它是空的?這是爲什麼?此外,必須觸發某些東西,因爲它不會顯示標題的名稱,它會在數據透視的查看部分和標題中顯示MyTestApp.Models.Pivot。奇怪!這就像它正在做一個object.ToString(),而不是實際上試圖顯示該屬性......基於上面的xaml,你認爲它是正確的嗎? – Thierry 2013-03-27 23:29:31

2

沒有你的答案是錯的,你的代碼是錯誤的。

錯誤1:

set 
    { 
     if (_pivots != value) this.SetProperty(ref this._pivots, value); 
    } 

在這裏如果你更改屬性或變量的結合將會丟失它的DOS沒有關係。

錯誤2:從ItemsControl派生的所有UIElements忽略INotifyPropertyChanged,因爲它不會更新ItemsSource只是DataContext。

工作實例

public ObservableCollection<string> LstLog { get; set; } 
    private ObservableCollection<string> _lstContent = new ObservableCollection<string>(); 
    public ObservableCollection<string> LstContent 
    { 
     get 
     { 
      LstLog.Add("get"); 
      return _lstContent; 
     } 
     set 
     { 
      LstLog.Add("set"); 
      _lstContent = value; 
     } 
    } 
    public MainWindow() 
    { 
     LstLog = new ObservableCollection<string>(); 

     InitializeComponent(); 
     this.DataContext = this; 
    } 

    private void Add_Click(object sender, RoutedEventArgs e) 
    { 
     LstContent.Add("Value added"); 
    } 

    private void New_Click(object sender, RoutedEventArgs e) 
    { 
     _lstContent = new ObservableCollection<string>(); 
    } 

    private void NewBind_Click(object sender, RoutedEventArgs e) 
    { 
     _lstContent = new ObservableCollection<string>(); 
     listObj.ItemsSource = _lstContent; 
    } 

    private void NewProp_Click(object sender, RoutedEventArgs e) 
    { 
     LstContent = new ObservableCollection<string>(); 
    } 

    private void NewPropBind_Click(object sender, RoutedEventArgs e) 
    { 
     LstContent = new ObservableCollection<string>(); 
     listObj.ItemsSource = LstContent; 
    } 

和UI

<Grid DataContext="{Binding}"> 
    <Grid.RowDefinitions> 
     <RowDefinition /> 
     <RowDefinition /> 
     <RowDefinition Height="25" /> 
    </Grid.RowDefinitions> 

    <ItemsControl Grid.Row="0" Name="logObj" ItemsSource="{Binding Path=LstLog}"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding}"/> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
    <ItemsControl Grid.Row="1" Name="listObj" ItemsSource="{Binding Path=LstContent}"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding}"/> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
    <StackPanel Grid.Row="2" Orientation="Horizontal"> 
     <Button Name="Add" Content="Add" Click="Add_Click"/> 
     <Button Name="New" Content="New" Click="New_Click"/> 
     <Button Name="NewBind" Content="New Bind" Click="NewBind_Click"/> 
     <Button Name="NewProp" Content="New Prop" Click="NewProp_Click"/> 
     <Button Name="NewPropBind" Content="New Prop Bind" Click="NewPropBind_Click"/> 
    </StackPanel> 
</Grid> 

LstLog是剛纔看到的事件列表,如果你點擊add將更新兩個列表,但如果點擊NewNew Prop綁定丟失,直到您更新它,如在New BindNew Prop Bind

希望這將澄清XAML List事件經常發生的問題。

PS:這是在WPF中,但在WP8和Windows Store應用程序中工作相同。