在关于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)?
有关答案 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));