MVVM +多级/嵌套数据绑定

时间:2012-12-23 16:25:25

标签: c# windows-phone-7 data-binding mvvm windows-phone-8

结构

场景是我有一个Pivot,每个项目都是某一天的菜单。在PivotItem里面我需要在菜单上显示菜肴,按类别分类(例如汤,甜点......)。

我已经用MVVM模型实现了这个。

因此,我有以下模型:

public class Menu{
    public string Date;
    public List<DishList> Categories;
}
public class DishList
{
    public string Category;
    public List<Dish> Dishes;
}
public class Dish
{
    public string Name;
    public string Price;
}

编辑:这里简化了这些,每个字段的实际结构如下:

    private string _date;

    //Get_Set
    public string Date
    {
        get
        {
            return _date;
        }
        set
        {
            if (value != _date)
            {
                _date = value;
            }
        }
    }

所以结构就像这样:一个PivotElement包含一个Menu-object。在里面,我展示了类别,一些DishLists。在Dishlist中,我展示了类别和不同的菜肴,每个菜单都有名称和价格。一个模型,使事情更清晰(在SkyDrive上的pdf文件); http://sdrv.ms/12IKlWd

我有以下viewmodel

public class MenuViewModel : INotifyPropertyChanged
{
    private ObservableCollection<Menu> _Menus;
}

应实现所需布局的视图(结构)如下:

<phone:Pivot 
        ItemsSource="{Binding Menus}">
        <phone:Pivot.HeaderTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Date}" />
            </DataTemplate>
        </phone:Pivot.HeaderTemplate>
        <phone:Pivot.ItemTemplate>
            <DataTemplate>
                <ItemsControl
                    ItemsSource="{Binding Categories}">   
                    <TextBlock
                        Text="{Binding Category}"/>
                    <ItemsControl
                        x:Name="Dishes"
                        ItemsSource="{Binding Dishes}">
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="300"/>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>

                                    <TextBlock 
                                        Grid.Column="1" 
                                        Text="{Binding Name}"/>
                                    <TextBlock 
                                        Grid.Column="2" 
                                        Text="{Binding Price}"/>
                                </Grid>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </ItemsControl>
            </DataTemplate>
        </phone:Pivot.ItemTemplate>
    </phone:Pivot>

正如您所看到的,存在嵌套数据绑定以获取所需的数据。

我在页面上执行的唯一代码是

DataContext = App.ViewModel;

问题

当我启动它时,我会在PivotItems标头中显示正确的数据,以及正确数量的PivotItems。不幸的是,就是这样;数据透视表的内容保持空白。因此,第一级数据绑定工作,但没有进一步。

我在想的方式

  • 第1级:每个PivotItem都链接到Menu类型的对象,标题为Menu.Date
  • 第二级:在PivotItem内部我将ItemsControl的ItemsSource设置为该Menu.Categories
  • 第3级:ItemsSource现在是Menu.Categories.Dishes

我已经搜索了很多,并且使用了Datacontext和ItemsSource以及不同类型的“{Binding ...}”,但我无法让它工作。我想在xaml中进行绑定,而不是在代码隐藏中进行绑定。

注释

  • 唯一的功能是显示数据。数据是固定的,并从文件加载一次。 这就是为什么我选择ItemsControl而不是ListBox,没有必要选择任何东西。
  • 这是我之前提问的MVVM方法:Databinding + Dynamic Pivot

1 个答案:

答案 0 :(得分:4)

首先,您尝试访问标题中的私有字段,这样就无法使用了。这些也必须是属性,而不是字段。

<TextBlock Text="{Binding Date}" />

private string Date;

接下来你绑定到Category,它也是私有的,而不是属性。

<TextBlock Text="{Binding Category}"/>

private string Category;

你绑定到需要属性的Categories字段。

<ItemsControl ItemsSource="{Binding Categories}">

public List<DishList> Categories;

即使您更正了这些问题,由于外部ItemsControl没有ItemTemplate,您仍然无法获得所需内容。

<ItemsControl ItemsSource="{Binding Categories}">   
  <TextBlock Text="{Binding Category}"/>
  ...
</ItemsControl>

已添加:您的新错误是因为DataTemplate只能有一个子元素,因此您需要使用像StackPanel这样的容器。

<ItemsControl ItemsSource="{Binding Categories}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding Category}"/>
        <ItemsControl x:Name="Dishes" ItemsSource="{Binding Dishes}">
          ...
        </ItemsControl>
      </StackPanel>
     </DataTemplate>
   </ItemsControl.ItemTemplate>
</ItemsControl>