ViewModel包含另一个ViewModel的集合

时间:2018-01-07 21:56:49

标签: c# wpf mvvm

在关于MVVM的所有教程中,我读到View不应该知道Model,因此引入了ViewModel层。

如果情况如此:我们Shelf包含Pack

namespace Storage.Model
{
    class Pack
    {
        public string Name { get; set; }
    }
}
<UserControl x:Class="Storage.View.Shelf" ... >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="20" />
            <RowDefinition Height="50" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <TextBlock Grid.Row="0" Text="{Binding Path=Name}"/>
        <TextBlock Grid.Row="1" Text="{Binding Path=Capability}"/>
        <ItemsControl Grid.Row="2" ItemsSource="{Binding Path=Packs}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border>
                        <TextBlock Text="{Binding Name}" /> 
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

    </Grid>
</UserControl>
// DataContext for Shelf 
namespace Storage.ViewModel
{
    public class ShelfViewModel
    {
        public string Name { get; set; }
        public string Capability { get; set; }
        // It's okay that ViewModel contains collection of another ViewModel?
        public ObservableCollection<PackViewModel> Packs { get; set; } 
    }
}
// DataContext for Pack
namespace Storage.ViewModel
{
    class PackViewModel
    {
        private Pack pack;
        public string Name 
        {
           get{ return pack.Name; }
           set{ ... }
        }

        public PackViewModel(int id)
        {
            // How to populate reference to Pack instance?
            pack = (new PackRepository()).getById(id) 
        }
    }
}

就像我在上面的代码注释中提到的那样,一个ViewModel创建另一个ViewModel的实例?我可以使用Storage的集合Shelf来形成案例,因此我们最终得到了对ModelView的级联引用:StoreViewModel包含ObservableCollection<ShelfViewModel>,其中包含{{1}的集合}。

该解决方案出现的另一个问题是如何使用ObservableCollection<PackViewModel>类填充新引入的PackViewModel?我们必须以某种方式将唯一标识符传递给Pack实例。

我不想隐藏这个问题与我的其他问题Shoud view layer know about model classes (entities)?

有关

1 个答案:

答案 0 :(得分:2)

  

就像我在上面的代码注释中提到的那样,一个ViewModel创建了另一个ViewModel的实例?

是。在这种情况下,PackViewModel只是Pack的包装。当您不想直接公开或绑定到模型类型时,或者当模型类型没有实现INotifyPropertyChanged接口时,通常会使用这样的包装器。

这很好。你最终会得到更多的课程,但每个班级都有自己的责任。例如,您可以使用特定于UI的属性扩展包装类,即视图要绑定到的属性。

  

该解决方案出现的另一个问题是如何参考Pack类填充新引入的PackViewModel?我们必须以某种方式将唯一标识符传递给PackViewModel实例

您可以在创建包装对象时注入包装类:

class PackViewModel
{
    private readonly Pack _pack;
    public PackViewModel(Pack pack)
    {
        _pack = pack;
    }

    public string Name
    {
        get { return _pack.Name; }
    }
}

鉴于您可能从某种存储库或服务收到的Pack个对象集合,您可以轻松创建包装器对象,例如:

var repo = PackRepository();
var packs = repo.GetPacks();
var wrapperObjects = packs.Select(pack => new PackViewModel(pack));