Reputation: 133
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
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
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