Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
119 views
in Technique[技术] by (71.8m points)

c# - ViewModel contains collection of another ViewModel

In all tutorial about MVVM I read that View should not know about Model, hence ViewModel layer is introduced.

If so in situation like: we have Shelf which contains 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) 
        }
    }
}

Like I mention in code comment above, it okey that one ViewModel create instances of another ViewModel? I can image case where we have Storage with collection of Shelf, hence we end up with cascading reference to ModelView: StoreViewModel contains ObservableCollection<ShelfViewModel> which cotains collection of ObservableCollection<PackViewModel>.

Another problem with arise with that solution is that how to populate newly introduced PackViewModel with reference to Pack class? We must somehow pass unique identifier to PackViewModel instance.

I don't want hide that this question is related to my other question Shoud view layer know about model classes (entities)?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Like I mention in code comment above, it okey that one ViewModel create instances of another ViewModel?

Yes. In this case PackViewModel is just a wrapper around Pack. You typically use such a wrapper when you don't want to expose or bind to the model type directly or when the model type doesn't implement the INotifyPropertyChanged interface for example.

This is perfectly fine. You will indeed end up with more classes, but each class has its own responsibility. You could for example extend the wrapper class with properties that are specific to the UI, i.e. properties that are obly there for the view to bind to.

Another problem with arise with that solution is that how to populate newly introduced PackViewModel with reference to Pack class? We must somehow pass unique identifier to PackViewModel instance

You could just inject the wrapper class with the wrapped object when you create it:

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

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

Given a collection of Pack objects that you may have received from some kind of repository or service, you could then easily create wrapper objects, e.g.:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...