locked
MVVM: Creating design time sample data for an ICollectionView on a ViewModel RRS feed

  • Question

  • I am beginning to explore generating sample data in Expression Blend 4 from ViewModels and setting the design time DataContext to the generated xaml.

    The issue I'm running into is that my ViewModel only exposes an ICollectionView. Is there anyway to infer or specify the source collection type so that Blend is able to generate sample data?

    <UserControl
    	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:Example"
    	mc:Ignorable="d"
    	x:Class="Example.Widget"
    	d:DataContext="{d:DesignData Source=/SampleData/WidgetViewModelSampleData}">
    	
    	<UserControl.DataContext>
    		<local:WidgetViewModel/>
    	</UserControl.DataContext>
    
    	<ListBox ItemsSource="{Binding WidgetView}" />		
    
    </UserControl>
    public class WidgetViewModel : ViewModelBase
    {
            private ObservableCollection<Widget> _widgets = new ObservableCollection<Widget>();
        	public ICollectionView WidgetView
        	{
    	        get;
            	set;
        	}        
    
        	public WidgetViewModel()
        	{
        	    	WidgetView = CollectionViewSource.GetDefaultView( _widgets );
        	}        
    }

    The sample data it generates using Create sample data |  Create Sample Data from Class... does not appear to allow adding items to WidgetView in any way.

    <Example:WidgetViewModel xmlns:Example="clr-namespace:Example"/>

    Is this possible without refactoring my ViewModel?


    Thursday, February 9, 2012 11:27 PM

All replies

  • Is there a reason you're exposing an ICollectionView instead of exposing the ObservableCollection?

    Friday, February 10, 2012 12:20 AM
  • Yes, the ViewModel is using the ICollectionView to set and track the selection of the CurrentItem, as well as perfoming Sorting, Grouping and Filtering.

    Friday, February 10, 2012 12:33 AM
  • If you don't need the CollectionViewSource in your ViewModel, I would suggest keeping it in the XAML. Here's a working example of a ListBox displaying sample data created from a class. If you have any questions, let me know.

    Model:

    public class Model
    {
        public string StringProperty { get; set; }
        public bool BoolProperty { get; set; }
    }

    ViewModel:

    public class ViewModel
    {
        public ObservableCollection<Model> Models { get; set; }
    
        public ViewModel()
        {
            // Insert code required on object creation below this point.
            this.Models = new ObservableCollection<Model>();
        }
    }

    XAML:

    <UserControl
    	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:System_ComponentModel="clr-namespace:System.ComponentModel;assembly=System.Windows" mc:Ignorable="d"
    	x:Class="SilverlightApplication36.MainPage"
    	Width="640" Height="480"
    	d:DataContext="{d:DesignData /SampleData/ViewModelSampleData.xaml}">
    
    	<UserControl.Resources>
    		<DataTemplate x:Key="ModelTemplate">
    			<StackPanel>
    				<CheckBox IsChecked="{Binding BoolProperty, Mode=TwoWay}"/>
    				<TextBlock Text="{Binding StringProperty}"/>
    			</StackPanel>
    		</DataTemplate>
    		<CollectionViewSource x:Key="modelCollection"
    			Source="{Binding Models}">
    			<CollectionViewSource.SortDescriptions>
    				<System_ComponentModel:SortDescription Direction="Ascending" PropertyName="StringProperty"/>
    			</CollectionViewSource.SortDescriptions>
    		</CollectionViewSource>
    	</UserControl.Resources>
    
    	<Grid x:Name="LayoutRoot" Background="White">
    		<ListBox ItemTemplate="{StaticResource ModelTemplate}" ItemsSource="{Binding Mode=OneWay}" DataContext="{StaticResource modelCollection}"/>
    	</Grid>
    </UserControl>

    • Proposed as answer by Brian Hilstrom Friday, February 10, 2012 3:19 PM
    • Unproposed as answer by blenddev Friday, February 10, 2012 4:03 PM
    Friday, February 10, 2012 3:18 PM
  • I understand that exposing the ObservableCollection would allow me to generate sample data. The question was is it possible to generate the data form an ICollectionView without refactoring my ViewModel to expose the ObservableCollection.

    Friday, February 10, 2012 4:03 PM
  • Not to my knowledge, no. The XAML file does not have knowledge of the code you used to assign the view of the CollectionViewSource.
    Monday, February 13, 2012 2:03 PM
  • Hey BlendDev,

    Did you ever come up with a solution to this problem? I'm trying to do the exact same thing and found your post while looking for a solution.

    You would think there would be a solution to this MVVM pattern as it is how the PRISM 4.0 book recommends implementing the VM.


    Tuesday, March 20, 2012 10:20 PM
  • No I did not. It does not appear to be possible (at least according to Brian from MSFT.)
    Tuesday, March 20, 2012 10:26 PM
  • You can do something like this considering the class CollectionViewSource which is almost always put into the XAML of the view as a source for a datagrid etc.

    CollectionViewSource cvs = this.FindResource("CVSNameInXAML") as CollectionViewSource;
    var stuff = GetCollection();
    cvs.source = stuff;

    Your GetCollection method can be an IENUMERABLE<ofSometype> which inlclduds ObservableCollections (preferred) but even LINQ bindings which just return IENUMERABLES are ok.  E.G.

    var stuff = customers.where(p=>p.lastname="Smith");
    cvs.source = stuff.ToArray();


    JP Cowboy Coders Unite!

    Tuesday, March 20, 2012 11:31 PM
  • This abstracted CVS layer then has built-in filtering, sorting etc...  All without affecting underlying datasource.

    JP Cowboy Coders Unite!

    Tuesday, March 20, 2012 11:32 PM
  • considering the class CollectionViewSource which is almost always put into the XAML of the view as a source for a datagrid etc.

    I'm not sure I understand where your code would exist in my original example. I have an ICollectionView as a property on my ViewModel which is the DataContext of a UserControl. The UserControl contains a ListBox whose ItemsSource is bound directly to the DataContext. There is no CollectionViewSource in the XAML.

    Could you modify the original example to include your changes?

    Wednesday, March 21, 2012 1:22 PM
  • There is only a trick I've found to works in such a situation, my viewmodel usually expose the ICollectionView as readonly property and I've found no way to use design time data until I did a "not so good but working workaround"

    In my ViewModel I declare the bindable property as IEnumerable       

            public IEnumerable Logs
            {
                get { return _logs; }
                set { this.Set(p => p.Logs, valueref _logs); }
            }
     
            private IEnumerable _logs;

    Now I can simple initialize it in VM Constructor

      

                _Logs = newObservableCollection<LogMessageViewModel>();             CvsLogs = newCollectionViewSource();             CvsLogs.Source = _Logs;             CvsLogs.Filter += CvsLogsFilter;             Logs = CvsLogs.View;

    I can also use DesignTimeData using an ObservableCollection

     <vm:RawLoggerViewModel.Logs>
            <coll:ObservableCollection x:TypeArguments="vm:LogMessageViewModel">
                <vm:LogMessageViewModel >
                    <vm:LogMessageViewModel.Log>
                        <infrastructure:LogMessage Logger="Logger name 1 " Level="INFO" />
                    </vm:LogMessageViewModel.Log>
                </vm:LogMessageViewModel>

    It works at the only limitation of having your VM expose an IEnumerable and not an ICollectionView

    Gian Maria

      


    Ricci Gian Maria. (http://www.codewrecks.com)

    Monday, July 23, 2012 12:43 PM