0

This is my first foray into Hierarchical data and am having a bit of a problem.

In Silverlight 4, I am trying to get a list of isolated storage folders to display in a TreeView. Nothing displays at all. My Treeview is completely blank. What am I missing? I am getting data and it is correct.

Any help would be appreciated.

XAML

 <sdk:TreeView x:Name="FolderTreeView" Grid.Column="0" Margin="0,0,3,0" ItemsSource="{Binding _Folders}">
            <sdk:TreeView.ItemTemplate>
                <sdk:HierarchicalDataTemplate ItemsSource="{Binding Path=Folders}">
                    <TextBlock Margin="0" Text="{Binding Name, Mode=OneWay}"/>
                </sdk:HierarchicalDataTemplate>
            </sdk:TreeView.ItemTemplate>
        </sdk:TreeView>

CS

internal class Folder
{
    public Folder() { Folders = new List<Folder>(); }
    public string Name { get; set; }
    public List<Folder> Folders { get; set; }
}

private List<Folder>  _Folders = new List<Folder>();
public OpenFileDialog()
{
    InitializeComponent();

    ifs = IsolatedStorageFile.GetUserStoreForApplication();
    var folder = new Folder
    {
        Name = "Root",
        Folders = (from c in ifs.GetDirectoryNames()
            select new Folder
            {
                Name = c,
                Folders = LoadFolders(c)
            }).ToList()
    };
    _Folders.Add(folder);
    FolderTreeView.DataContext = new { _Folders };
}

private List<Folder>LoadFolders(string folderName)
{
    if(folderName == null)
        return null;
    return (from c in ifs.GetDirectoryNames(folderName + "\\*.*")
        select new Folder
        {
            Name = c,
            Folders = LoadFolders(c)
        }).ToList();
}

Thanks

2 Answers2

1

A few things

<sdk:TreeView x:Name="FolderTreeView" Grid.Column="0" Margin="0,0,3,0" 
              ItemsSource="{Binding _Folders}">

you can't bind to private members.

You need to use ObservableCollections instead of Lists. The binding manager effectively listens for the CollectionChanged events fired by ObservableCollection and notifies the bound controls.

You'll want to implement INotifyPropertyChanged and raise PropertyChanged notifications in your property setters.

Finally, have you set the DataContext for the Treeview?

Also, look in your Output debug window for errors relating to binding.

Edit, ok try:

FolderTreeView.DataContext =  this;

and wrap _Folders in a property

public ObservableCollection <Folder> Folders
    {
    get
       {
       return _Folders;
       }
    set
       {
       _Folders = value;
       OnPropertyChanged("Folders");
       }
   }

change your binding to

<sdk:TreeView x:Name="FolderTreeView" Grid.Column="0" Margin="0,0,3,0" 
              ItemsSource="{Binding Folders}">

I've changed things quite a bit,

    public class Folder : INotifyPropertyChanged
        {

        public Folder(string folderName) 
            {
            Name = folderName;
            Folders = new ObservableCollection<Folder>();
            var _ifs = IsolatedStorageFile.GetUserStoreForApplication();

            if (folderName != null)
                {
                Folders = new ObservableCollection<Folder>(
                        (from c in _ifs.GetDirectoryNames(folderName + "\\*.*")
                         select new Folder(folderName + "\\" + c)
                   ));
                }
            else
                {
                Folders = new ObservableCollection<Folder>(
                       (from c in _ifs.GetDirectoryNames()
                        select new Folder(folderName + "\\" + c)
                  ));
                }
            }


        public string Name { get; set; }

        private ObservableCollection<Folder> _Folders; 
        public ObservableCollection<Folder> Folders 
            {
            get { return _Folders; }
            set { _Folders = value; OnPropertyChanged("RootFolder"); }
            }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
            {
            if (PropertyChanged != null)
                {
                PropertyChanged(this,
                    new PropertyChangedEventArgs(propertyName));
                }
            }
        #endregion
    }



public partial class OpenFileDialog : UserControl
    {      
    public OpenFileDialog()
        {
        InitializeComponent();

        RootFolder = new Folder (null);
        RootFolders = new ObservableCollection<Folder>();
        RootFolders.Add(RootFolder);

        FolderTreeView.DataContext = this;
        }


    private Folder _RootFolder;
    public Folder RootFolder
        {
        get { return _RootFolder; }
        set { _RootFolder = value; }
        }


    private ObservableCollection<Folder> _RootFolders;
    public ObservableCollection<Folder> RootFolders
        {
        get { return _RootFolders; }
        set { _RootFolders = value; }
        }

    }

xaml

 <sdk:TreeView x:Name="FolderTreeView"  Margin="0,0,3,0" ItemsSource="{Binding RootFolders}">
    <sdk:TreeView.ItemTemplate>
        <sdk:HierarchicalDataTemplate ItemsSource="{Binding Path=Folders}">
            <StackPanel>
            <TextBlock Margin="0" Text="{Binding Name, Mode=OneWay}"/>
            </StackPanel>
        </sdk:HierarchicalDataTemplate>
    </sdk:TreeView.ItemTemplate>
</sdk:TreeView>
A Aiston
  • 717
  • 5
  • 12
  • Thanks for your reply. I am setting the DataContext above (i.e., FolderTreeView.DataContext = new { _Folders }). Changed all "List" to "ObservableCollection" and my top-level ObservableCollection to public. No change. – Greg Osborne Apr 09 '13 at 16:05
  • Did have an exception in the output window. "System.Windows.Data Error: Cannot get 'Folders' value". What do I need to do to correct this? – Greg Osborne Apr 09 '13 at 16:15
  • Again, thanks. This made no difference. Still got the same exception in output window. – Greg Osborne Apr 09 '13 at 16:25
  • Sorry ... no change, although now the exception is Cannot get "RootFolder" value. – Greg Osborne Apr 09 '13 at 17:02
  • Sorry, was binding the tree view to a folder, not an observable collection. – A Aiston Apr 09 '13 at 17:06
  • No change. Here is the entire exception, if it can help – Greg Osborne Apr 09 '13 at 17:11
  • System.Windows.Data Error: Cannot get 'RootFolders' value (type 'System.Collections.ObjectModel.ObservableCollection`1[IFSDialog.Windows.OpenFileDialog+Folder]') from 'IFSDialog.Windows.OpenFileDialog' (type 'IFSDialog.Windows.OpenFileDialog'). BindingExpression: Path='RootFolders' DataItem='IFSDialog.Windows.OpenFileDialog' (HashCode=5253358); target element is 'System.Windows.Controls.TreeView' (Name='FolderTreeView'); target property is 'ItemsSource' (type 'System.Collections.IEnumerable').. System.MethodAccessException: Attempt by method – Greg Osborne Apr 09 '13 at 17:12
  • 'System.Windows.CLRPropertyListener.get_Value()' to access method 'IFSDialog.Windows.OpenFileDialog.get_RootFolders()' failed. – Greg Osborne Apr 09 '13 at 17:13
  • changed folder constructor call to select new Folder(folderName + "\\" + c) – A Aiston Apr 09 '13 at 17:14
  • This made no difference. I tried Binding directly to RootFolders instead of to the DataContext (i.e., ItemsSource=RootFolders), and then I began receiving Cannot get 'Folders' value and Cannot get 'Name' value exceptions. – Greg Osborne Apr 09 '13 at 17:32
  • Strange. I am binding directly to other controls on the same window (ListBox and ComboBox, although they are using DataTemplate vs HierarchicalDataTemplate) – Greg Osborne Apr 09 '13 at 17:37
  • Hmmm, strange, this source works for me. Have you made your Folder class public? – A Aiston Apr 09 '13 at 17:43
0

Ok...problem solved. Don't understand why though.

I had the ChildWindow set as internal scope instead of public scope because I didn't want the window itself to be viewed external of my Silverlight class library. If anyone can answer why this would stop Hierarchical data binding but not standard data binding I would like to know.