-1

I have a ViewModel that has a property which is a ReadOnlyObservableCollection. Defined something like this:

public class MyViewModel
{
    private ObservableCollection<string> myProtectedCollection;

    public ReadOnlyObservableCollection<string> MyCollectionProperty { get; }

    public MyViewModel()
    {
        this.myProtectedCollection = new ObservableCollection<string>();
        this.MyCollectionProperty = new ReadOnlyObservableCollection<string>(this.myProtectedCollection);
        this.myProtectedCollection.Add("String1");
        this.myProtectedCollection.Add("String2");
        this.myProtectedCollection.Add("String3");
    }
}

I have then created a xaml file called TestData.xaml and set the build action to DesignData. In that I have this:

<local:MyViewModel 
    xmlns:local="clr-namespace:ScrapWpfApplication1"
    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <local:MyViewModel.MyCollectionProperty>
        <system:String>String 1</system:String>
        <system:String>String 2</system:String>
    </local:MyViewModel.MyCollectionProperty>
</local:MyViewModel>

Finally I have a MainWindow.xaml with the following:

<Window x:Class="ScrapWpfApplication1.MainWindow"
        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:ScrapWpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        d:DataContext="{d:DesignData Source=SampleData.xaml}">
    <ListBox ItemsSource="{Binding MyCollectionProperty}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Window>

The problem is that this is not showing my sample data in the Visual Studio designer. If I change the collection in my view model to be a ObservableCollection instead of a ReadOnlyObservableCollection then it works as expcted.

I guess that this is because the design time data system is creating a dummy ReadOnlyCollection but XAML is unable to populate it because it is readonly.

Is there any way to get the design type data system to work without making my view model's collection property writeable?

Martin Brown
  • 24,692
  • 14
  • 77
  • 122
  • 1
    XAML is using parameterless constructors, this is a amin reason, that your collection isn't created in `DesignData` See the answer from [this](https://stackoverflow.com/questions/49825594/how-to-fill-a-readonlyobservablecollection-in-xaml) article, maybe you find something helpful – Pavel Anikhouski Mar 19 '19 at 12:38

2 Answers2

1

Is there any way to get the design type data system to work without making my view model's collection property writeable?

Yes, you could create another view model class, to be used for design purposes only, with an ObservableCollection<T> property, and set the design time DataContext of the view to an instance of this one:

d:DataContext="{d:DesignInstance Type=local:DesignTimeViewModel, IsDesignTimeCreatable=True}
mm8
  • 163,881
  • 10
  • 57
  • 88
1

I've not seen a perfect answer to this. But this is what I have finally done.

Instead of trying to get the design data system to mock the readonly collection. I've created a new set of sample data just for the collection and made the MainWindow.xaml look at that instead.

So my TestData.xaml file changes to just this. In reality it has more in it but this is just a sample for this question so it looks fairly empty.

<local:MyViewModel 
    xmlns:local="clr-namespace:ScrapWpfApplication1"
    xmlns:system="clr-namespace:System;assembly=mscorlib">
</local:MyViewModel>

Secondly I created a second test data file called TestDataArray.xaml with an array in it. Being sure to set the build action to DesignData.

<x:Array Type="system:String"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    
    xmlns:local="clr-namespace:ScrapWpfApplication1"
    xmlns:system="clr-namespace:System;assembly=mscorlib">
    <system:String>String 1</system:String>
    <system:String>String 2</system:String>
</x:Array>

Finally I changed my MainWindow.xaml file to this. Note the change to the binding on

<Window x:Class="ScrapWpfApplication1.MainWindow"
        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:ScrapWpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        d:DataContext="{d:DesignData Source=SampleData.xaml}">
    <ListBox ItemsSource="{Binding}" DataContext="{Binding MyCollectionProperty}" d:DataContext="{d:DesignData Source=SampleDataArray.xaml}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Window>

This works for my particular scenario, but it would fall down if the sample data was being bound to a control and the ReadOnlyCollection was being read by something inside that control.

Martin Brown
  • 24,692
  • 14
  • 77
  • 122