绑定Pivot控件与Observable Collection MVVM (windows phone 8)
本文关键字:windows phone MVVM Collection Pivot 控件 Observable 绑定 | 更新日期: 2023-09-27 18:05:58
我是WP8的新手;MVVM。我创建了wp8应用程序,一旦用户登录,它就会请求各种数据。我只是不能让我的枢轴头得到动态创建,我不知道这是因为我做的东西在绑定,INotifyPropertyChanged,两者或其他东西!!
到目前为止我所做的是:
我在App.cs中定义了一个全局MainViewModel,它将存储登录时返回的所有数据。
一旦登录成功并且数据已加载到MainViewModel中,我将其重定向到包含Pivot控件的测试页面,并且我正在尝试动态创建Pivot项。
这是我的测试页面的示例,即MainPivotPage。xaml和我的MainPivotViewModel被初始化,因为它被定义为本地资源,并被设置为Pivot控件的数据上下文,我不知道我是否这样做是对的,但我将"Name"属性分配给pivotiitem的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时,我将Pivots可观察集合设置为存储在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事件的属性名称。
这是我的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));
}
}
}
我的Pivot类是这样的:
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类上,但我正在尝试不同的场景,并将其留在现在。
我不知道我做错了什么,但无论我怎么努力,我都不能得到"Name"属性显示为Header的文本。我很确定MainPivotViewModel是初始化的,当它被分配为一个本地资源,因为我正确地调用我的构造函数,然后初始化我的可观察集合,但这是到目前为止,它去。
但是它什么都没显示!
我注意到的另一件事是,当我在BaseViewModel类的OnPropertyChanged方法中设置断点时,eventHandler总是为空,无论我认为不应该是这种情况,但我看不出我做错了什么。
我在stackoverflow和其他网站上有很多文章,我就是看不出我做错了什么?有人有什么想法吗?
谢谢。
问题解决!
我的代码一直都是正确的,但XAML不是!
我猜是陡峭而痛苦的学习曲线!无论如何,在找到stackoverflow上的一篇文章后,我找到了一个解决方案,这篇文章基本上向我展示了我编写xaml的方式是不合适的。我将是诚实的,我不明白为什么这不能工作的方式,它被定义,但简而言之,我必须使用HeaderTemplate和ItemTemplate,以便在绑定到ViewModel正确显示数据!
这里是post:在Windows Phone 8中,数据绑定pivot没有加载第一个pivotiitem
不,你的答案是错误的,你的代码是错误的。
错误1:
set
{
if (_pivots != value) this.SetProperty(ref this._pivots, value);
}
在这里,如果你改变了属性或变量,绑定将会丢失。
错误2:所有来自ItemsControl的ui元素都忽略了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
,它会更新两个列表,但如果点击New
或New Prop
,绑定将丢失,直到你像New Bind
或New Prop Bind
一样更新它
希望这将澄清XAML列表事件反复出现的问题。
PS:这是在WPF中,但在WP8和windows商店应用程序中工作相同。
这一切对我来说都很好,所以我认为App.MainViewModel.Pivots在调用构造函数时为null或空(因此Pivot控件为空),并且在MainPivotViewModel实例化后,您最终会在MainViewModel中创建一个新的Pivots实例。
你有没有试过在MainPivotViewModel的getter中设置一个断点?确认有一些支点吗?