Greg
Greg

Reputation: 2690

Code behind works but MVVM doesnt

I have been messing with something that works in the code behind but when I try and bind to a MVVM , nothing displays. First I will show the code behind, then MVVM ( same xaml ). I want to use MVVM and not code behind.

Code Behind (works):

var loadOp = ctx.Load<GateBlox.Web.Models.Structure>(ctx.GetStructuresQuery());
        loadOp.Completed += (s, e) => { _treeView.ItemsSource = loadOp.Entities.Where(struc => !struc.StructureParentFK.HasValue); };

XAML

<Grid x:Name="LayoutRoot">
    <sdk:TreeView x:Name='_treeView' DataContext='{StaticResource ViewModel}'>
        <sdk:TreeView.ItemTemplate>
            <sdk:HierarchicalDataTemplate ItemsSource='{Binding Children}'>
                <TextBlock Text='{Binding StructureName}' />
            </sdk:HierarchicalDataTemplate>
        </sdk:TreeView.ItemTemplate>
    </sdk:TreeView>
</Grid>

MVVM (doesnt bind)

private LoadOperation<Structure> _loadStructures;
private StructureContext _structureContext;

private IEnumerable<Structure> _structures;
public IEnumerable<Structure> Structures
{
   get { return this._structures; }
   set { this._structures = value; RaisePropertyChanged("Structures"); }
}

public StructuresViewModel()
{
 if (!DesignerProperties.IsInDesignTool)
  {
      _structureContext = new StructureContext();

      _loadStructures = _structureContext.Load(_structureContext.GetStructuresQuery().Where (p=> !  p.StructureParentFK.HasValue));
  _loadStructures.Completed += new EventHandler(_loadStructures_Completed);
   }
}

void _loadStructures_Completed(object sender, EventArgs e)
{
 this.Structures = _loadStructures.Entities;
}

Upvotes: 1

Views: 571

Answers (3)

AbdouMoumen
AbdouMoumen

Reputation: 3854

You are not setting the ItemsSource for your TreeView. I think your xaml should look something like this:

<Grid x:Name="LayoutRoot">
  <sdk:TreeView x:Name='_treeView' DataContext='{StaticResource ViewModel}'
                ItemsSource="{Binding Structures}">
    <sdk:TreeView.ItemTemplate>
      <sdk:HierarchicalDataTemplate ItemsSource='{Binding Children}'>
         <TextBlock Text='{Binding StructureName}' />
      </sdk:HierarchicalDataTemplate>
    </sdk:TreeView.ItemTemplate>
  </sdk:TreeView>
</Grid>

Hope this helps :)

Upvotes: 0

Greg
Greg

Reputation: 2690

I almost have it working now. I took a different approach and went with a HeirarchicalDataTemplate. At the moment the data is showing but not correctly: The child1 record is shwoing up as a parent as well. Parent1(level1) Parent2(level1) Child1(level2) Child1(level1)

<navigation:Page x:Class="GateBlox.Views.Structure"
             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"
             mc:Ignorable="d"
             xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
             d:DesignWidth="640"
             d:DesignHeight="480"
             Title="Structure Page"
             xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
             xmlns:viewmodel="clr-namespace:GateBlox.ViewModels">

<UserControl.Resources>
    <viewmodel:StructuresViewModel x:Key='ViewModel'>
    </viewmodel:StructuresViewModel>
</UserControl.Resources>

<Grid x:Name="LayoutRoot"
      DataContext='{StaticResource ViewModel}'>
    <Grid.Resources>
        <sdk:HierarchicalDataTemplate x:Key="ChildTemplate"
                                      ItemsSource="{Binding Path=Parent}">
            <TextBlock FontStyle="Italic"
                       Text="{Binding Path=StructureName}" />
        </sdk:HierarchicalDataTemplate>
        <sdk:HierarchicalDataTemplate x:Key="NameTemplate"
                                      ItemsSource="{Binding Path=Children}"
                                      ItemTemplate="{StaticResource ChildTemplate}">
            <TextBlock Text="{Binding Path=StructureName}"
                       FontWeight="Bold" />
        </sdk:HierarchicalDataTemplate>
    </Grid.Resources>
    <sdk:TreeView x:Name='treeView'
                  Width='400'
                  Height='300'
                  ItemsSource='{Binding Structures}'
                  ItemTemplate='{StaticResource NameTemplate}'>
    </sdk:TreeView>
</Grid>

using System;
using System.Collections.ObjectModel;
using GateBlox.Web.Models;
using System.ServiceModel.DomainServices.Client;
using GateBlox.Web.Services;
using GateBlox.Helpers;
using System.ComponentModel;
using System.Collections.Generic;


namespace GateBlox.ViewModels
{
public class StructuresViewModel : ViewModelBase
{
    private LoadOperation<Structure> _loadStructures;
    private StructureContext _structureContext;


    private ObservableCollection<Structure> _structures;
    public ObservableCollection<Structure> Structures
    {
        get { return this._structures; }
        set { this._structures = value; RaisePropertyChanged("Structures"); }
    }

    public StructuresViewModel()
    {
        if (!DesignerProperties.IsInDesignTool)
        {
            _structureContext = new StructureContext();

            _loadStructures = _structureContext.Load(_structureContext.GetStructuresQuery());
            _loadStructures.Completed += new EventHandler(_loadStructures_Completed);
        }
    }

    void _loadStructures_Completed(object sender, EventArgs e)
    {
        this.Structures = IEnumerableConverter.ToObservableCollection(_loadStructures.Entities);
    }
}

}

Upvotes: 0

Oppositional
Oppositional

Reputation: 11211

Have your checked that you are not getting a binding expression error in the output? You are binding the items source of the data template to a property named Children, but your view model exposes a data source named Structures.

Also, in your working example, you are setting the ItemsSource of the TreeView, but in your MVVM XAML you are setting the ItemsSource of your data template. Is there an inconsistency between what ItemsSource you need to set/bind to?

You might also consider using a collection data source that implements the INotifyCollectionChanged interface (ObservableCollection or expose the binding source as a ICollectionView that uses a PagedCollectionView).

I recommend you take a look at this information about data binding in MVVM, as it provides excellent guidance on setting up data sources in your view models.

Upvotes: 1

Related Questions