Lorenzo R.
Lorenzo R.

Reputation: 133

Why this ObservableCollection of ViewModels is not shown in View by using DataTemplates?

I have a collection of models (i.e. Format classes) which I would like to load on my view (i.e. MainWindowView.xaml). These models could be loaded more than once.

In order to do that, I started to create a ViewModel and a DataTemplate for each model class. For example, model class FormatContainer has FormatContainerViewModel as view model:

 namespace MyProject.ViewModels
    {

    public class FormatContainerViewModel : ViewModelBase
    {
        public FormatContainerViewModel(FormatContainer wrappedFormat)
        {
            _wrappedFormat = wrappedFormat; // Wrap model.

            SubFormats = GetSubFormatsViewModels(_wrappedFormat.SubFormats); // Get the collection of Formats contained into container and generate their ViewModels.

            FormatLabel = _wrappedFormat.Description; // Get wrapped format description.
        }

        private FormatContainer _wrappedFormat;

        private ObservableCollection<ViewModel> _subFormats;
        public ObservableCollection<ViewModel> SubFormats
        {
            get
            {
                return _subFormats;
            }
            set
            {
                Set(() => SubFormats, ref _subFormats, value);
                RaisePropertyChanged("SubFormats");
            }
        }

        private string _formatLabel;
        public string FormatLabel
        {
            get
            {
                return _formatLabel;
            }
            set
            {
                Set(() => FormatLabel, ref _formatLabel, value);
                RaisePropertyChanged("FormatLabel");
            }
        }
    }
    }

Additionally, model FormatContainer has a DataTemplate as view which is added by a Resourcedictionary:

 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:MyProject.ViewModels">


    <DataTemplate DataType="{x:Type local:FormatContainerViewModel}">
        <Border BorderBrush="Black" BorderThickness="1" Padding="20">
            <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition />
                </Grid.RowDefinitions>

                <!-- Show container description. -->
                <TextBlock Grid.Column="0" Grid.Row="0"  Text="{Binding FormatLabel}" VerticalAlignment="Center" Margin="5" />

                <!-- Show container sub formats. -->
                <!--<StackPanel Grid.Column="1" Grid.Row="0" Orientation="Horizontal" Margin="3,3,3,3">
                    <ContentControl Content="{Binding SubFormats}" HorizontalAlignment="Center" Margin="1" />
                </StackPanel-->>

            </Grid>
        </Border>
    </DataTemplate>

    <!-- other DataTemplates ... -->

    </ResourceDictionary>

Therefore, this resource dictionary (i.e. FormatsView.xaml) is added in App.xaml:

    <Application x:Class="MyProject.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:MyProject"
             xmlns:vm="clr-namespace:MyProject.ViewModels"
             StartupUri="MainWindowView.xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
            d1p1:Ignorable="d" xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006">
    <Application.Resources>
        <ResourceDictionary>
            <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:vm="clr-namespace:MyProject.ViewModels" />

            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/PanelsView.xaml" />
            </ResourceDictionary.MergedDictionaries>

        </ResourceDictionary>
    </Application.Resources>
</Application>

Then, these ViewModels are instantiated in the main view model (i.e. MainWindowViewModel) by a service class (i.e. ViewModelsGeneratorService).

ViewModelsGeneratorService tempGenerator = new ViewModelsGeneratorService(myFormats); // Use a service to convert current format objects to view models.
ViewModelsList = tempGenerator.ViewModelsList; // Populate view models obesrvable collections.

Finally, these view models are shown in MainWindowView by a ContentControl:

    <Window x:Class="MyProject.MainWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyProject"
        xmlns:interactivity="using:Microsoft.Expression.Interactivity"
        xmlns:core="using:Microsoft.Expression.Interactions.Core"
        mc:Ignorable="d"
        Title="MySoftware" Height="350" Width="525"
        DataContext="{Binding Main, Source={StaticResource Locator}}">
    <Grid>

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>

        <!-- ... -->

        <ContentControl Grid.Row="3" Content="{Binding ViewModelsList}" />

    </Grid>
</Window>

Unfortunately, the ContentControl with content ViewModelsList is empty, while ViewModelLists contains 53 items. What am I missing? Would someone provide a pointer, please?

I already checked some tutorial and discussion in order to check my code (e.g. Rachel, Gala, Marco, etc.), but I could not figure it out what i am missing..

Moveover, the ContentControl is not showing the sub formats. Of course, when uncommented ;-) What am I still missing here too?

All the best, Lorenzo

P.S. I am currently developing for .NET 4.5 and using MVVM Light framework.

P.P.S. FormatContainer is the only one of my formats which has sub formats, the others formats just change theyr properties and so their view (e.g. a format could show a combobox instead of a listbox in addition to the label, and/or instead of a textbox, etc.).

Upvotes: 2

Views: 70

Answers (2)

Luke Villanueva
Luke Villanueva

Reputation: 2070

Try implementing INotifyPropertyChanged on your viewModel and add PropertyChangedEventHandler

public class FormatContainerViewModel : ViewModelBase, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    //Add notifyPropertyChanged on your desired property
    //Example

    private ObservableCollection<ViewModel> _subFormats;
    public ObservableCollection<ViewModel> SubFormats
    {
        get
        {
            return _subFormats;
        }
        set
        {
            Set(() => SubFormats, ref _subFormats, value);
            RaisePropertyChanged("SubFormats");
            NotifyPropertyChanged("SubFormats");
        }
    }


}

Upvotes: 0

grek40
grek40

Reputation: 13458

Collections are bound by ItemsControl or other list based controls, not by ContentControl.

<ItemsControl ItemsSource="{Binding ViewModelsList}"/>

If you want an ItemsPanel that doesn't inherit ItemsControl (like WrapPanel), you can set it with the ItemsPanelTemplate property.

Upvotes: 2

Related Questions