none
TreeView Data Binding - Load On Demand

    Question

  •  I plan on loading the nodes on demand, i.e. lazy loading.  When the user clicks on a node, my presentation layer will send a request to my business logic, which in turn will send a request to my data layer.  With this request, my datalayer will return a table to my business logic, and my business logic will return a collection of objects (based on the rows in the table) to my presentation layer.  My presentation layer will then load those objects as children to the node that was selected by the end user.

    I'm sorry for such a noobish question but alas I am a noob with WPF.  So this is what you get.  I have a basic understanding of binding to an existing collection of collections of collections of collections, etc....... but what I dont understand is how to dynamically load the treeview on demand.

    I am currently trying to pick apart this example http://www.codeproject.com/KB/WPF/TreeViewWithViewModel.aspx, but have not had much success (none actually) in trying to make it work in my scenerio.

    I'm becoming very sad with my programming ability, because I really want to do my application as an .xbap instead of just a standard forms application (non-WPF), and I'm just treading water, sinking fast, and not making any progress at all.
    Compensating what I don't know yet, with what I do know now.
    Monday, February 16, 2009 4:29 AM

Answers

  • Hello Stuck,

       Take it easy. There are several ways to do a lazy loading.

       Each way may just fit one certain app architecture.

       Here is simple sample. 

       Important Notice. It is a demo, not a best practice for MVVM with TreeView.

        1. We define a Division class ( a simplified ViewMode class. When we click the View (a treeviewitem node) of the ViewMode, we add Team class to Division class

    public class Division : INotifyPropertyChanged   
        {  
            string m_name;  
     
            //Indicate whether the Division is selected.  
            bool m_IsSelected =false;  
     
            //Indicate wheter the Teams has been filled.  
     
            bool m_FilledCache =false;  
     
            ObservableCollection<Team> m_teamcollection = new ObservableCollection<Team>();  
     
            public Division(string name)  
            {  
                m_name = name;  
            }  
     
            public ObservableCollection<Team> Teams  
            {  
                get 
                {  
                    return m_teamcollection;  
                }  
            }  
     
            public string Name  
            {  
                get 
                {  
                    return m_name;  
                }  
                set 
                {  
                    if (value != null && value != m_name)  
                    {  
                        m_name = value;  
                        OnPropertyChanged("Name");  
                    }  
                }  
            }  
     
            public bool IsSelected  
            {  
                get 
                {  
                    return m_IsSelected;  
                }  
                set 
                {  
                    if (value == m_IsSelected)  
                    {  
                        return;  
                    }  
     
                    m_IsSelected = value;  
     
                    if (!m_FilledCache)  
                    {  
                        FillTheDivision();  
                        m_FilledCache = true;  
                    }  
     
                    OnPropertyChanged("IsSelected");  
                }  
            }  
     
            private void FillTheDivision()  
            {  
                //We call the businessLogic Method  
                foreach (Team tm in BusinessLayer.businesslogicLayMethod(this.Name))  
                {  
                    this.Teams.Add(tm);  
                }  
            }
        
            #region INotifyPropertyChanged Members  
     
            public event PropertyChangedEventHandler PropertyChanged;  
     
            /// <summary>  
            /// Raises this object's PropertyChanged event.  
            /// </summary>  
            /// <param name="propertyName">The property that has a new value.</param>  
            protected virtual void OnPropertyChanged(string propertyName)  
            {  
                  
                PropertyChangedEventHandler handler = this.PropertyChanged;  
                if (handler != null)  
                {  
                    var e = new PropertyChangedEventArgs(propertyName);  
                    handler(this, e);  
                }  
            }
            #endregion  
        } 


    About the Division class

         1. It has ObservableCollection of Team class. We add Team class instance to the collection dynamically.

         2. Has two bool fields.  IsSelected property is bound to the IsSelected property of a TreeViewItem later.

        


    Please mark the replies as answers if they help and unmark them if they provide no help
    • Edited by Hua Chen Thursday, February 19, 2009 6:44 AM Edit..
    • Marked as answer by Hua Chen Friday, February 20, 2009 9:17 AM
    Thursday, February 19, 2009 6:35 AM
  •  Hello Stuck,

       Continue...

       2. We define a Team class.
      
     public class Team:INotifyPropertyChanged  
        {  
            private string m_teamID;  
     
            public Team(string teamString)  
            {  
                m_teamID =teamString;  
            }  
     
            public string ID  
            {  
                get 
                {  
                    return m_teamID;  
                }  
                set 
                {  
                    if(value!=null)  
                    {  
                        m_teamID=value;  
                        OnPropertyChanged("ID");  
                    }  
                }  
            }
        
            #region INotifyPropertyChanged Members  
     
            public event PropertyChangedEventHandler  PropertyChanged;
            #endregion  
     
            protected virtual void OnPropertyChanged(string propertyName)  
            {  
                //this.VerifyPropertyName(propertyName);  
     
                PropertyChangedEventHandler handler = this.PropertyChanged;  
                if (handler != null)  
                {  
                    var e = new PropertyChangedEventArgs(propertyName);  
                    handler(this, e);  
                }  
            }  
        } 

    3.  A fake BusinessLayer  

     public class BusinessLayer  
        {  
            /// <summary>  
            ///  In a real app the method should ask the DataAccess Layer to search the DataSource.  
            /// </summary>  
            /// <param name="DivisionName"></param>  
            /// <returns></returns>  
            public static List<Team> businesslogicLayMethod(string DivisionName)  
            {  
                List<Team> team = new List<Team>();  
     
                team.Add(new Team("11111" + DivisionName));  
                team.Add(new Team("22222" + DivisionName));  
                team.Add(new Team("33333" + DivisionName));  
                team.Add(new Team("44444" + DivisionName));  
                team.Add(new Team("55555" + DivisionName));  
                team.Add(new Team("66666" + DivisionName));  
                team.Add(new Team("77777" + DivisionName));  
                team.Add(new Team("88888" + DivisionName));  
     
                return team;  
            }  
        } 

    4.  An init top level data source


    public
     class AllDivisionViewModel : ObservableCollection<Division>  
        {  
            public AllDivisionViewModel()  
            {  
                Add(new Division("MyDivision1"));  
                Add(new Division("MyDivision2"));  
                Add(new Division("MyDivision3"));  
                Add(new Division("MyDivision4"));  
                Add(new Division("MyDivision5"));  
                Add(new Division("MyDivision6"));  
                Add(new Division("MyDivision7"));  
                Add(new Division("MyDivision8"));  
            }  
        } 

    Please add the following Using syntax

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using System.Collections.ObjectModel;  
    using System.ComponentModel;  
    using System.Diagnostics; 

     
    Please mark the replies as answers if they help and unmark them if they provide no help
    • Marked as answer by Hua Chen Friday, February 20, 2009 9:17 AM
    Thursday, February 19, 2009 6:43 AM
  • Hello Stuck,

       5.  We define a HierarchicalDataTemplate for the Division

     <HierarchicalDataTemplate DataType="{x:Type localViewMode:Division}" 
                                      ItemsSource = "{Binding Path=Teams}">  
                <TextBlock Text="{Binding Path=Name}"></TextBlock> 
     </HierarchicalDataTemplate> 

     
      6. We define a HierarchicalDataTemplate for the Team.
     
      <HierarchicalDataTemplate DataType="{x:Type localViewMode:Team}">  
                                        
                <TextBlock Text="{Binding Path=ID}"></TextBlock> 
      </HierarchicalDataTemplate> 

    7. We define a style for item devision

      
    <Style x:Key="DevisionItemStyle" TargetType="{x:Type TreeViewItem}">  
          
                <Setter Property="HorizontalContentAlignment" Value="Stretch" /> 
           
                <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" /> 
                <Style.Triggers> 
                    <MultiTrigger> 
                        <MultiTrigger.Conditions> 
                            <Condition Property="IsSelected" Value="False" /> 
                            <Condition Property="IsMouseOver" Value="False" /> 
                        </MultiTrigger.Conditions> 
                        <Setter Property="Background" Value="#EEEEEEEE" /> 
                    </MultiTrigger> 
                </Style.Triggers> 
     </Style> 

    In the style we bind the IsSelected property of TreeViewItem to IsSelected property of Division class.

    8. Show a TreeView

     
     <Grid> 
              
            <TreeView> 
                <TreeViewItem DataContext="{StaticResource TreeViewData}" Name="RootTreeViewItem" ItemsSource="{Binding}" ItemContainerStyle="{StaticResource DevisionItemStyle}">  
                      
                </TreeViewItem> 
            </TreeView> 
              
        </Grid> 

    Please mark the replies as answers if they help and unmark them if they provide no help
    • Marked as answer by Hua Chen Friday, February 20, 2009 9:17 AM
    Thursday, February 19, 2009 6:55 AM
  • Hello Stuck, 

        Here is all the definitions in two files. We can run the window

     Window

    <Window x:Class="MVVMTreeViewDelayLoad.Window1" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:local="clr-namespace:MVVMTreeViewDelayLoad" 
        xmlns:localViewMode="clr-namespace:MVVMTreeViewDelayLoad.ViewModel" 
        Title="Window1" Height="300" Width="300">  
          
        <Window.Resources> 
              
            <localViewMode:AllDivisionViewModel x:Key="TreeViewData">  
                  
            </localViewMode:AllDivisionViewModel> 
              
            <HierarchicalDataTemplate DataType="{x:Type localViewMode:Division}" 
                                      ItemsSource = "{Binding Path=Teams}">  
                <TextBlock Text="{Binding Path=Name}"></TextBlock> 
            </HierarchicalDataTemplate> 
              
            <HierarchicalDataTemplate DataType="{x:Type localViewMode:Team}">  
                                        
                <TextBlock Text="{Binding Path=ID}"></TextBlock> 
            </HierarchicalDataTemplate> 
     
            <Style x:Key="DevisionItemStyle" TargetType="{x:Type TreeViewItem}">  
          
                <Setter Property="HorizontalContentAlignment" Value="Stretch" /> 
           
                <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" /> 
                <Style.Triggers> 
                    <MultiTrigger> 
                        <MultiTrigger.Conditions> 
                            <Condition Property="IsSelected" Value="False" /> 
                            <Condition Property="IsMouseOver" Value="False" /> 
                        </MultiTrigger.Conditions> 
                        <Setter Property="Background" Value="#EEEEEEEE" /> 
                    </MultiTrigger> 
                </Style.Triggers> 
            </Style> 
     
        </Window.Resources> 
          
        <Grid> 
              
            <TreeView> 
                <TreeViewItem DataContext="{StaticResource TreeViewData}" Name="RootTreeViewItem" ItemsSource="{Binding}" ItemContainerStyle="{StaticResource DevisionItemStyle}">  
                      
                </TreeViewItem> 
            </TreeView> 
              
        </Grid> 
          
    </Window> 
     

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using System.Collections.ObjectModel;  
    using System.ComponentModel;  
    using System.Diagnostics;  
     
    namespace MVVMTreeViewDelayLoad.ViewModel  
    {  
        public class AllDivisionViewModel : ObservableCollection<Division>  
        {  
            public AllDivisionViewModel()  
            {  
                Add(new Division("MyDivision1"));  
                Add(new Division("MyDivision2"));  
                Add(new Division("MyDivision3"));  
                Add(new Division("MyDivision4"));  
                Add(new Division("MyDivision5"));  
                Add(new Division("MyDivision6"));  
                Add(new Division("MyDivision7"));  
                Add(new Division("MyDivision8"));  
            }  
        }  
        public class Team:INotifyPropertyChanged  
        {  
            private string m_teamID;  
     
            public Team(string teamString)  
            {  
                m_teamID =teamString;  
            }  
     
            public string ID  
            {  
                get 
                {  
                    return m_teamID;  
                }  
                set 
                {  
                    if(value!=null)  
                    {  
                        m_teamID=value;  
                        OnPropertyChanged("ID");  
                    }  
                }  
            }
        
            #region INotifyPropertyChanged Members  
     
            public event PropertyChangedEventHandler  PropertyChanged;
            #endregion  
     
            protected virtual void OnPropertyChanged(string propertyName)  
            {  
                //this.VerifyPropertyName(propertyName);  
     
                PropertyChangedEventHandler handler = this.PropertyChanged;  
                if (handler != null)  
                {  
                    var e = new PropertyChangedEventArgs(propertyName);  
                    handler(this, e);  
                }  
            }  
        }  
     
        public class Division : INotifyPropertyChanged   
        {  
            string m_name;  
     
            //Indicate whether the Division is selected.  
            bool m_IsSelected =false;  
     
            //Indicate wheter the Teams has been filled.  
     
            bool m_FilledCache =false;  
     
            ObservableCollection<Team> m_teamcollection = new ObservableCollection<Team>();  
     
            public Division(string name)  
            {  
                m_name = name;  
            }  
     
            public ObservableCollection<Team> Teams  
            {  
                get 
                {  
                    return m_teamcollection;  
                }  
            }  
     
            public string Name  
            {  
                get 
                {  
                    return m_name;  
                }  
                set 
                {  
                    if (value != null && value != m_name)  
                    {  
                        m_name = value;  
                        OnPropertyChanged("Name");  
                    }  
                }  
            }  
     
            public bool IsSelected  
            {  
                get 
                {  
                    return m_IsSelected;  
                }  
                set 
                {  
                    if (value == m_IsSelected)  
                    {  
                        return;  
                    }  
     
                    m_IsSelected = value;  
     
                    if (!m_FilledCache)  
                    {  
                        FillTheDivision();  
                        m_FilledCache = true;  
                    }  
     
                    OnPropertyChanged("IsSelected");  
                }  
            }  
     
            private void FillTheDivision()  
            {  
                //We call the businessLogic Method  
                foreach (Team tm in BusinessLayer.businesslogicLayMethod(this.Name))  
                {  
                    this.Teams.Add(tm);  
                }  
            }
        
            #region INotifyPropertyChanged Members  
     
            public event PropertyChangedEventHandler PropertyChanged;  
     
            /// <summary>  
            /// Raises this object's PropertyChanged event.  
            /// </summary>  
            /// <param name="propertyName">The property that has a new value.</param>  
            protected virtual void OnPropertyChanged(string propertyName)  
            {  
                  
                PropertyChangedEventHandler handler = this.PropertyChanged;  
                if (handler != null)  
                {  
                    var e = new PropertyChangedEventArgs(propertyName);  
                    handler(this, e);  
                }  
            }
            #endregion  
        }  
     
        public class BusinessLayer  
        {  
            /// <summary>  
            ///  In a real app the method should ask the DataAccess Layer to search the DataSource.  
            /// </summary>  
            /// <param name="DivisionName"></param>  
            /// <returns></returns>  
            public static List<Team> businesslogicLayMethod(string DivisionName)  
            {  
                List<Team> team = new List<Team>();  
     
                team.Add(new Team("11111" + DivisionName));  
                team.Add(new Team("22222" + DivisionName));  
                team.Add(new Team("33333" + DivisionName));  
                team.Add(new Team("44444" + DivisionName));  
                team.Add(new Team("55555" + DivisionName));  
                team.Add(new Team("66666" + DivisionName));  
                team.Add(new Team("77777" + DivisionName));  
                team.Add(new Team("88888" + DivisionName));  
     
                return team;  
            }  
        }  
    }  
     

    If you have any question please let me know.

    Thanks.


    Please mark the replies as answers if they help and unmark them if they provide no help
    • Marked as answer by Hua Chen Friday, February 20, 2009 9:17 AM
    Thursday, February 19, 2009 7:00 AM

All replies

  • Hello Stuck,

       Take it easy. There are several ways to do a lazy loading.

       Each way may just fit one certain app architecture.

       Here is simple sample. 

       Important Notice. It is a demo, not a best practice for MVVM with TreeView.

        1. We define a Division class ( a simplified ViewMode class. When we click the View (a treeviewitem node) of the ViewMode, we add Team class to Division class

    public class Division : INotifyPropertyChanged   
        {  
            string m_name;  
     
            //Indicate whether the Division is selected.  
            bool m_IsSelected =false;  
     
            //Indicate wheter the Teams has been filled.  
     
            bool m_FilledCache =false;  
     
            ObservableCollection<Team> m_teamcollection = new ObservableCollection<Team>();  
     
            public Division(string name)  
            {  
                m_name = name;  
            }  
     
            public ObservableCollection<Team> Teams  
            {  
                get 
                {  
                    return m_teamcollection;  
                }  
            }  
     
            public string Name  
            {  
                get 
                {  
                    return m_name;  
                }  
                set 
                {  
                    if (value != null && value != m_name)  
                    {  
                        m_name = value;  
                        OnPropertyChanged("Name");  
                    }  
                }  
            }  
     
            public bool IsSelected  
            {  
                get 
                {  
                    return m_IsSelected;  
                }  
                set 
                {  
                    if (value == m_IsSelected)  
                    {  
                        return;  
                    }  
     
                    m_IsSelected = value;  
     
                    if (!m_FilledCache)  
                    {  
                        FillTheDivision();  
                        m_FilledCache = true;  
                    }  
     
                    OnPropertyChanged("IsSelected");  
                }  
            }  
     
            private void FillTheDivision()  
            {  
                //We call the businessLogic Method  
                foreach (Team tm in BusinessLayer.businesslogicLayMethod(this.Name))  
                {  
                    this.Teams.Add(tm);  
                }  
            }
        
            #region INotifyPropertyChanged Members  
     
            public event PropertyChangedEventHandler PropertyChanged;  
     
            /// <summary>  
            /// Raises this object's PropertyChanged event.  
            /// </summary>  
            /// <param name="propertyName">The property that has a new value.</param>  
            protected virtual void OnPropertyChanged(string propertyName)  
            {  
                  
                PropertyChangedEventHandler handler = this.PropertyChanged;  
                if (handler != null)  
                {  
                    var e = new PropertyChangedEventArgs(propertyName);  
                    handler(this, e);  
                }  
            }
            #endregion  
        } 


    About the Division class

         1. It has ObservableCollection of Team class. We add Team class instance to the collection dynamically.

         2. Has two bool fields.  IsSelected property is bound to the IsSelected property of a TreeViewItem later.

        


    Please mark the replies as answers if they help and unmark them if they provide no help
    • Edited by Hua Chen Thursday, February 19, 2009 6:44 AM Edit..
    • Marked as answer by Hua Chen Friday, February 20, 2009 9:17 AM
    Thursday, February 19, 2009 6:35 AM
  •  Hello Stuck,

       Continue...

       2. We define a Team class.
      
     public class Team:INotifyPropertyChanged  
        {  
            private string m_teamID;  
     
            public Team(string teamString)  
            {  
                m_teamID =teamString;  
            }  
     
            public string ID  
            {  
                get 
                {  
                    return m_teamID;  
                }  
                set 
                {  
                    if(value!=null)  
                    {  
                        m_teamID=value;  
                        OnPropertyChanged("ID");  
                    }  
                }  
            }
        
            #region INotifyPropertyChanged Members  
     
            public event PropertyChangedEventHandler  PropertyChanged;
            #endregion  
     
            protected virtual void OnPropertyChanged(string propertyName)  
            {  
                //this.VerifyPropertyName(propertyName);  
     
                PropertyChangedEventHandler handler = this.PropertyChanged;  
                if (handler != null)  
                {  
                    var e = new PropertyChangedEventArgs(propertyName);  
                    handler(this, e);  
                }  
            }  
        } 

    3.  A fake BusinessLayer  

     public class BusinessLayer  
        {  
            /// <summary>  
            ///  In a real app the method should ask the DataAccess Layer to search the DataSource.  
            /// </summary>  
            /// <param name="DivisionName"></param>  
            /// <returns></returns>  
            public static List<Team> businesslogicLayMethod(string DivisionName)  
            {  
                List<Team> team = new List<Team>();  
     
                team.Add(new Team("11111" + DivisionName));  
                team.Add(new Team("22222" + DivisionName));  
                team.Add(new Team("33333" + DivisionName));  
                team.Add(new Team("44444" + DivisionName));  
                team.Add(new Team("55555" + DivisionName));  
                team.Add(new Team("66666" + DivisionName));  
                team.Add(new Team("77777" + DivisionName));  
                team.Add(new Team("88888" + DivisionName));  
     
                return team;  
            }  
        } 

    4.  An init top level data source


    public
     class AllDivisionViewModel : ObservableCollection<Division>  
        {  
            public AllDivisionViewModel()  
            {  
                Add(new Division("MyDivision1"));  
                Add(new Division("MyDivision2"));  
                Add(new Division("MyDivision3"));  
                Add(new Division("MyDivision4"));  
                Add(new Division("MyDivision5"));  
                Add(new Division("MyDivision6"));  
                Add(new Division("MyDivision7"));  
                Add(new Division("MyDivision8"));  
            }  
        } 

    Please add the following Using syntax

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using System.Collections.ObjectModel;  
    using System.ComponentModel;  
    using System.Diagnostics; 

     
    Please mark the replies as answers if they help and unmark them if they provide no help
    • Marked as answer by Hua Chen Friday, February 20, 2009 9:17 AM
    Thursday, February 19, 2009 6:43 AM
  • Hello Stuck,

       5.  We define a HierarchicalDataTemplate for the Division

     <HierarchicalDataTemplate DataType="{x:Type localViewMode:Division}" 
                                      ItemsSource = "{Binding Path=Teams}">  
                <TextBlock Text="{Binding Path=Name}"></TextBlock> 
     </HierarchicalDataTemplate> 

     
      6. We define a HierarchicalDataTemplate for the Team.
     
      <HierarchicalDataTemplate DataType="{x:Type localViewMode:Team}">  
                                        
                <TextBlock Text="{Binding Path=ID}"></TextBlock> 
      </HierarchicalDataTemplate> 

    7. We define a style for item devision

      
    <Style x:Key="DevisionItemStyle" TargetType="{x:Type TreeViewItem}">  
          
                <Setter Property="HorizontalContentAlignment" Value="Stretch" /> 
           
                <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" /> 
                <Style.Triggers> 
                    <MultiTrigger> 
                        <MultiTrigger.Conditions> 
                            <Condition Property="IsSelected" Value="False" /> 
                            <Condition Property="IsMouseOver" Value="False" /> 
                        </MultiTrigger.Conditions> 
                        <Setter Property="Background" Value="#EEEEEEEE" /> 
                    </MultiTrigger> 
                </Style.Triggers> 
     </Style> 

    In the style we bind the IsSelected property of TreeViewItem to IsSelected property of Division class.

    8. Show a TreeView

     
     <Grid> 
              
            <TreeView> 
                <TreeViewItem DataContext="{StaticResource TreeViewData}" Name="RootTreeViewItem" ItemsSource="{Binding}" ItemContainerStyle="{StaticResource DevisionItemStyle}">  
                      
                </TreeViewItem> 
            </TreeView> 
              
        </Grid> 

    Please mark the replies as answers if they help and unmark them if they provide no help
    • Marked as answer by Hua Chen Friday, February 20, 2009 9:17 AM
    Thursday, February 19, 2009 6:55 AM
  • Hello Stuck, 

        Here is all the definitions in two files. We can run the window

     Window

    <Window x:Class="MVVMTreeViewDelayLoad.Window1" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:local="clr-namespace:MVVMTreeViewDelayLoad" 
        xmlns:localViewMode="clr-namespace:MVVMTreeViewDelayLoad.ViewModel" 
        Title="Window1" Height="300" Width="300">  
          
        <Window.Resources> 
              
            <localViewMode:AllDivisionViewModel x:Key="TreeViewData">  
                  
            </localViewMode:AllDivisionViewModel> 
              
            <HierarchicalDataTemplate DataType="{x:Type localViewMode:Division}" 
                                      ItemsSource = "{Binding Path=Teams}">  
                <TextBlock Text="{Binding Path=Name}"></TextBlock> 
            </HierarchicalDataTemplate> 
              
            <HierarchicalDataTemplate DataType="{x:Type localViewMode:Team}">  
                                        
                <TextBlock Text="{Binding Path=ID}"></TextBlock> 
            </HierarchicalDataTemplate> 
     
            <Style x:Key="DevisionItemStyle" TargetType="{x:Type TreeViewItem}">  
          
                <Setter Property="HorizontalContentAlignment" Value="Stretch" /> 
           
                <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}" /> 
                <Style.Triggers> 
                    <MultiTrigger> 
                        <MultiTrigger.Conditions> 
                            <Condition Property="IsSelected" Value="False" /> 
                            <Condition Property="IsMouseOver" Value="False" /> 
                        </MultiTrigger.Conditions> 
                        <Setter Property="Background" Value="#EEEEEEEE" /> 
                    </MultiTrigger> 
                </Style.Triggers> 
            </Style> 
     
        </Window.Resources> 
          
        <Grid> 
              
            <TreeView> 
                <TreeViewItem DataContext="{StaticResource TreeViewData}" Name="RootTreeViewItem" ItemsSource="{Binding}" ItemContainerStyle="{StaticResource DevisionItemStyle}">  
                      
                </TreeViewItem> 
            </TreeView> 
              
        </Grid> 
          
    </Window> 
     

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using System.Collections.ObjectModel;  
    using System.ComponentModel;  
    using System.Diagnostics;  
     
    namespace MVVMTreeViewDelayLoad.ViewModel  
    {  
        public class AllDivisionViewModel : ObservableCollection<Division>  
        {  
            public AllDivisionViewModel()  
            {  
                Add(new Division("MyDivision1"));  
                Add(new Division("MyDivision2"));  
                Add(new Division("MyDivision3"));  
                Add(new Division("MyDivision4"));  
                Add(new Division("MyDivision5"));  
                Add(new Division("MyDivision6"));  
                Add(new Division("MyDivision7"));  
                Add(new Division("MyDivision8"));  
            }  
        }  
        public class Team:INotifyPropertyChanged  
        {  
            private string m_teamID;  
     
            public Team(string teamString)  
            {  
                m_teamID =teamString;  
            }  
     
            public string ID  
            {  
                get 
                {  
                    return m_teamID;  
                }  
                set 
                {  
                    if(value!=null)  
                    {  
                        m_teamID=value;  
                        OnPropertyChanged("ID");  
                    }  
                }  
            }
        
            #region INotifyPropertyChanged Members  
     
            public event PropertyChangedEventHandler  PropertyChanged;
            #endregion  
     
            protected virtual void OnPropertyChanged(string propertyName)  
            {  
                //this.VerifyPropertyName(propertyName);  
     
                PropertyChangedEventHandler handler = this.PropertyChanged;  
                if (handler != null)  
                {  
                    var e = new PropertyChangedEventArgs(propertyName);  
                    handler(this, e);  
                }  
            }  
        }  
     
        public class Division : INotifyPropertyChanged   
        {  
            string m_name;  
     
            //Indicate whether the Division is selected.  
            bool m_IsSelected =false;  
     
            //Indicate wheter the Teams has been filled.  
     
            bool m_FilledCache =false;  
     
            ObservableCollection<Team> m_teamcollection = new ObservableCollection<Team>();  
     
            public Division(string name)  
            {  
                m_name = name;  
            }  
     
            public ObservableCollection<Team> Teams  
            {  
                get 
                {  
                    return m_teamcollection;  
                }  
            }  
     
            public string Name  
            {  
                get 
                {  
                    return m_name;  
                }  
                set 
                {  
                    if (value != null && value != m_name)  
                    {  
                        m_name = value;  
                        OnPropertyChanged("Name");  
                    }  
                }  
            }  
     
            public bool IsSelected  
            {  
                get 
                {  
                    return m_IsSelected;  
                }  
                set 
                {  
                    if (value == m_IsSelected)  
                    {  
                        return;  
                    }  
     
                    m_IsSelected = value;  
     
                    if (!m_FilledCache)  
                    {  
                        FillTheDivision();  
                        m_FilledCache = true;  
                    }  
     
                    OnPropertyChanged("IsSelected");  
                }  
            }  
     
            private void FillTheDivision()  
            {  
                //We call the businessLogic Method  
                foreach (Team tm in BusinessLayer.businesslogicLayMethod(this.Name))  
                {  
                    this.Teams.Add(tm);  
                }  
            }
        
            #region INotifyPropertyChanged Members  
     
            public event PropertyChangedEventHandler PropertyChanged;  
     
            /// <summary>  
            /// Raises this object's PropertyChanged event.  
            /// </summary>  
            /// <param name="propertyName">The property that has a new value.</param>  
            protected virtual void OnPropertyChanged(string propertyName)  
            {  
                  
                PropertyChangedEventHandler handler = this.PropertyChanged;  
                if (handler != null)  
                {  
                    var e = new PropertyChangedEventArgs(propertyName);  
                    handler(this, e);  
                }  
            }
            #endregion  
        }  
     
        public class BusinessLayer  
        {  
            /// <summary>  
            ///  In a real app the method should ask the DataAccess Layer to search the DataSource.  
            /// </summary>  
            /// <param name="DivisionName"></param>  
            /// <returns></returns>  
            public static List<Team> businesslogicLayMethod(string DivisionName)  
            {  
                List<Team> team = new List<Team>();  
     
                team.Add(new Team("11111" + DivisionName));  
                team.Add(new Team("22222" + DivisionName));  
                team.Add(new Team("33333" + DivisionName));  
                team.Add(new Team("44444" + DivisionName));  
                team.Add(new Team("55555" + DivisionName));  
                team.Add(new Team("66666" + DivisionName));  
                team.Add(new Team("77777" + DivisionName));  
                team.Add(new Team("88888" + DivisionName));  
     
                return team;  
            }  
        }  
    }  
     

    If you have any question please let me know.

    Thanks.


    Please mark the replies as answers if they help and unmark them if they provide no help
    • Marked as answer by Hua Chen Friday, February 20, 2009 9:17 AM
    Thursday, February 19, 2009 7:00 AM