0
votes

I have started create a small test application for MVVM with Catel. I tryed to show a TreeView and create one ViewModel to display all the Items. But I get an Error.

<TreeView ItemsSource="{Binding ChildCollection}">
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding ChildCollection}">
            <local:TreeViewItem DataContext="{Binding}" />
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>nter code here

The TreeViewItem is only an TextBlock. But because it's an userControl, Catel should create the ViewModel for it. The following code of the ViewModel is simplified.

public class TreeViewItemVm : ViewModelBase
{
    public TreeViewItemVm(ModelBase model)
    {
        Model = model;

        if(model is Group)
            // Set Properties
        else if(model is Customer)
            // Set Properties
        else if(model is Product)
            // Set Properties
    }

    [Model]
    public ModelBase Model {get; set; }
    public string DisplayText {get; set; }
    public ObservableCollection<ModelBase> ChildCollection {get; set; }
    public Command OpenItemCommand { get; private set; }

On running this, I get the error

System.Windows.Data Error: 40 : BindingExpression path error: 'ChildCollection' property not found on 'object' ''Customer' ...

So HierarchicalDataTemplate ItemsSource="{Binding ChildCollection}" is looking on the Model instead of the ViewModel.

The Model should not implement the Command. So the answer here isn't specific enought. Is there a way to achive this? Or do I have to define it explicit for echt type with its own CustomControl, like it's done in this basic example. Or does anyone knows an Catel specific example?

1

1 Answers

1
votes
<TreeView ItemsSource="{Binding RootTreeViewItemVms}">
    <TreeView.Resources>
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate DataType={x:Type TreeViewItemVm} 
                                      ItemsSource="{Binding ChildCollection}">
                <TextBlock Text={Binding DisplayText} />
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    <TreeView.Resources>
</TreeView>

You should also have specific ViewModel types that inherit from a base TreeViewItemVm.

public abstract class TreeViewItemVm: ViewModelBase
{
    public TreeViewItemVm()
    {
        ChildCollection = new ObservableCollection<TreeViewItemVm>();
    }

    public ObservableCollection<TreeViewItemVm> ChildCollection {get; }
    public Command OpenItemCommand { get; private set; }
    public string DisplayText {get; set; }
}

public abstract class TreeViewItemVm<T> where T: ModelBase
{
    public TreeViewItemVm(T model)
    {
        Model = model;
    }

    public T Model {get;}
}

public class GroupTreeViewItemVm: TreeViewItem<Group>
{
    public GroupTreeViewItemVm(Group group): base(group)
    {
        // group specific stuff here
    }
}

etc....

If required you can make different HierarchicalDataTemplates for each specific ViewModel type.

edit

There is also a flaw in your TreeViewItemVm class.

public ObservableCollection<ModelBase> ChildCollection {get; set; }

should be

public ObservableCollection<TreeViewItemVm> ChildCollection {get; set; }