为什么这个 ViewModels 的 ObservableCollection 没有通过使用 DataTemplates 显示在 View 中?

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

我有一组模型(即格式 classes),我想将其加载到我的视图中(即 MainWindowView.xaml)。这些模型可以加载多次。

为了做到这一点,我开始为每个模型 class 创建一个 ViewModel 和一个 DataTemplate。例如,模型 class FormatContainerFormatContainerViewModel 作为视图模型:

 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");
            }
        }
    }
    }

此外,模型 FormatContainer 有一个 DataTemplate 作为视图,由 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>

因此,此资源字典(即FormatsView.xaml)被添加到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>

然后,这些 ViewModel 由服务 class(即 ViewModelsGeneratorService)在主视图模型(即 MainWindowViewModel)中实例化。

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

最后,这些视图模型通过 ContentControl 在 MainWindowView 中显示:

    <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>

不幸的是,包含内容 ViewModelsList 的 ContentControl 是空的,而 ViewModelLists 包含 53 个项目。 我错过了什么? 请问有人可以指点一下吗?

我已经检查了一些教程和讨论以检查我的代码(例如 Rachel, Gala, Marco 等),但我无法弄清楚我缺少什么..

此外,ContentControl 不显示子格式。当然,在未注释的情况下 ;-) 我还缺少什么?

一切顺利, 洛伦佐

P.S。我目前正在为 .NET 4.5 开发并使用 MVVM Light 框架。

P.P.S。 FormatContainer 是我的格式中唯一具有子格式的格式,其他格式只是更改它们的属性,因此它们的视图(例如,除了标签之外,格式可以显示组合框而不是列表框,and/or 而不是文本框等)。

集合受 ItemsControl 或其他基于列表的控件的约束,而不是 ContentControl

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

如果您想要一个不继承 ItemsControl(如 WrapPanel)的 ItemsPanel,您可以使用 ItemsPanelTemplate 属性 进行设置。

尝试在您的 viewModel 上实施 INotifyPropertyChanged 并添加 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");
        }
    }


}