C# 使用可观察集合MVVM绑定Pivot控件(windows phone 8)

C# 使用可观察集合MVVM绑定Pivot控件(windows phone 8),c#,silverlight,mvvm,windows-phone-8,inotifypropertychanged,C#,Silverlight,Mvvm,Windows Phone 8,Inotifypropertychanged,我是WP8和MVVM的新手。我创建了wp8应用程序,一旦用户登录,它就会请求不同的数据位。我只是无法动态创建我的pivots标头,我不知道这是因为我在绑定中做了一些事情,INotifyPropertyChanged,两者都做了,还是其他什么 以下是我迄今为止所做的工作: 我在App.cs中定义了一个全局MainViewModel,它将存储登录时返回的所有数据 登录成功并且数据加载到MainViewModel后,我将其重定向到包含Pivot控件的测试页面,并尝试动态创建Pivot项 这是我的测试页

我是WP8和MVVM的新手。我创建了wp8应用程序,一旦用户登录,它就会请求不同的数据位。我只是无法动态创建我的pivots标头,我不知道这是因为我在绑定中做了一些事情,INotifyPropertyChanged,两者都做了,还是其他什么

以下是我迄今为止所做的工作:

我在App.cs中定义了一个全局MainViewModel,它将存储登录时返回的所有数据

登录成功并且数据加载到MainViewModel后,我将其重定向到包含Pivot控件的测试页面,并尝试动态创建Pivot项

这是我的测试页面的xaml,即MainPivotPage.xaml,我的MainPivotViewModel被初始化,因为它被定义为本地资源,并被设置为Pivot控件的datacontext,我不知道是否正确,但我正在分配“名称”属性设置为数据透视项的标题,数据透视项是存储在我的可观察集合数据透视中的对象。属性名是我在名为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>
您可能会注意到,这一个是从BaseModel继承的。这与BaseViewModel中的代码完全相同,但我希望将两者分开。我不确定我的Pivot类是否需要这个事件,但我尝试了不同的场景,并暂时保留了它

我不知道我做错了什么,但无论我怎么做,我都无法将“Name”属性显示为标题文本。我很确定MainPivotViewModel在被分配为本地资源时已经初始化,因为它正确地调用了构造函数,然后初始化了可观察的集合,但就到此为止了

但它完全没有显示任何东西


我注意到的另一件事是,当我在BaseViewModel类的OnPropertyChanged方法中的“Set”中放置断点时,eventHandler始终为null,无论我假设哪种情况不应该是这样,但我看不出我做错了什么

我有很多关于stackoverflow和其他的文章,我只是看不出我做错了什么?有人有什么想法吗


谢谢。

我觉得这一切都很好,所以我认为调用构造函数时App.MainViewModel.Pivots为null或空(因此Pivot控件为空),并且在实例化MainPivotViewModel后,您最终在MainViewModel中创建了一个新的Pivots实例

您是否尝试在MainPivotViewModel.Pivots的getter中放置断点以确认存在某些项?

问题已解决

我的代码一直都是正确的,但XAML不是

我猜是陡峭而痛苦的学习曲线!无论如何,在找到一篇关于stackoverflow的文章后,我找到了一个解决方案,这基本上表明我编写xaml的方式并不合适

老实说,我不明白为什么它不能按定义的方式工作,但简而言之,我必须使用HeaderTemplate和ItemTemplate,以便在绑定到ViewModel时正确显示数据


这是帖子:

不,你的答案是错误的,你的代码是错误的

错误1:

    set
    {
        if (_pivots != value) this.SetProperty(ref this._pivots, value);
    }
在这里,无论您是否更改属性或变量,绑定都将丢失

错误2:从ItemsControl派生的所有UIElements都忽略INotifyPropertyChanged,因为它不会仅更新DataContext中的ItemsSource

工作示例

    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;
    }
publicobservableCollection LstLog{get;set;}
私有ObservableCollection lstContent=新ObservableCollection();
公共可观测收集内容
{
得到
{
LstLog.Add(“get”);
返回内容;
}
设置
{
LstLog.Add(“set”);
_内容=价值;
}
}
公共主窗口()
{
LstLog=新的ObservableCollection();
初始化组件();
this.DataContext=this;
}
私有无效添加\单击(对象发送者,路由目标)
{
增加内容(“增加值”);
}
私有无效新建\u单击(对象发送者,路由目标e)
{
_lstContent=新的ObservableCollection();
}
私有无效新绑定单击(对象发送方,路由目标)
{
_lstContent=新的ObservableCollection();
listObj.ItemsSource=lstContent;
}
私有void NewProp_单击(对象发送方,路由目标)
{
LstContent=新的ObservableCollection();
}
私有void NewPropBind_单击(对象发送方,路由目标)
{
LstContent=新的ObservableCollection();
listObj.ItemsSource=LstContent;
}
还有用户界面

<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 Bind
则绑定将丢失,直到您像在
New Bind
New Prop Bind>中一样更新它

希望这将澄清XAML列表事件反复出现的问题


PS:这在WPF中,但在WP8和windows应用商店应用程序中工作相同。

您是否在任何地方设置页面的
DataContext
?您好,是的,它在上面的xaml中设置。它只是不可见,但如果你滚动,你会看到它已设置。你有一个可观察的
Pivot
s集合。这些是你自己的班级吗?如果是这样,它们看起来像什么?嗨,Matt,我刚刚在原始帖子中添加了类。当你使用ObservableCollection时,你需要更改集合的内容,而不是集合本身,如果(_pivots!=value)this.SetProperty(ref this._pivots,value)c
    set
    {
        if (_pivots != value) this.SetProperty(ref this._pivots, value);
    }
    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;
    }
<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>