kformeck
kformeck

Reputation: 1933

Custom WPF TreeView Binding

I am trying to bind a collection of custom objects to a tree view's ItemSource in WPF with no success.

Here is the MainWindow.xaml:

<Window 
    x:Class="AoiImageLift.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:AoiImageLift.UI.ViewModels"
    Height="500" 
    Width="500">
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>
    <TreeView ItemsSource="{Binding TreeViewViewModel.ProcessList}"/>
</Window>

Here is the App.xaml:

</Application>
    </Application.Resources>

        <!-- TreeView Style -->
        <Style TargetType="{x:Type TreeView}">
            <Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
            <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Visible"/>
            <Setter Property="SelectedValuePath" Value="Wafer"/>
            <Setter Property="ItemTemplate">
                <Setter.Value>
                    <HierarchicalDataTemplate ItemsSource="{Binding ProcessList}">
                        <HierarchicalDataTemplate.ItemTemplate>
                            <HierarchicalDataTemplate>
                                <TextBlock
                                    FontFamily="SegoeUI"
                                    Foreground="MidnightBlue"
                                    Text="{Binding Wafer}"/>
                            </HierarchicalDataTemplate>
                         </HierarchicalDataTemplate.ItemTemplate>
                        <TextBlock
                            Text="{Binding ProcessNumber}"
                            FontFamily="SegoeUI"
                            Foreground="MidnightBlue"/>
                     </HierarchicalDataTemplate>
                </Setter.Value>
             </Setter>
         </Style>
     </Application.Resources>
</Application>

Here is the MainWindowViewModel.cs:

public class MainWindowViewModel : ViewModel
{
    private WaferSelectionTreeViewViewModel treeViewViewModel;

    public MainWindowViewModel()
    {
        BackgroundWorker initThread = new BackgroundWorker();
        initThread.DoWork += (sender, e) =>
        {
            e.Result = new SingulationOneTable().GetWaferList();
        };
        initThread.RunWorkerCompleted += (sender, e) =>
        {
            TreeViewViewModel = new WaferSelectionTreeViewViewModel(
                (List<string>) e.Result);
        };
        initThread.RunWorkerAsync();
    }

    public WaferSelectionTreeViewViewModel TreeViewViewModel 
    {
        get { return treeViewViewModel; }
        set
        {
            treeViewViewModel = value;
            OnPropertyChanged("TreeViewViewModel");
        }
    }
}

FYI, this line of code...

e.Result = new SingulationOneTable().GetWaferList();

...simply returns a large list of strings. That list of strings is then passed into the constructor of the WaferSelectionTreeViewViewModel class.

Here is the WaferSelectionTreeViewViewModel.cs:

public class WaferSelectionTreeViewViewModel : ViewModel
{
    private ObservableCollection<Process> processList;

    public class TreeViewItemBase : ViewModel
    {
        private bool isSelected;
        public bool IsSelected
        {
            get { return isSelected; }
            set
            {
                if (value != isSelected)
                {
                    isSelected = value;
                    OnPropertyChanged("IsSelected");
                }
            }
        }
        private bool isExpanded;
        public bool IsExpanded
        {
            get { return isExpanded; }
            set
            {
                if (value != isExpanded)
                {
                    isExpanded = value;
                    OnPropertyChanged("IsExpanded");
                }
            }
        }
    }
    public class Process : TreeViewItemBase
    {
        private string name;
        public Process(string name)
        {
            this.name = name;
            this.Children = new ObservableCollection<string>();
        }

        public string Name { get { return name; } }
        public ObservableCollection<string> Children { get; set; }
    }

    public WaferSelectionTreeViewViewModel(List<string> waferList)
    {
        processList = new ObservableCollection<Process>();
        List<string> procList = new List<string>();
        foreach (string wafer in waferList)
        {
            procList.Add(wafer.Substring(0, 4));
        }

        IEnumerable<string> distintProcessList = procList.Distinct();
        foreach (string process in distintProcessList)
        {
            Process newProcess = new Process(process);
            List<string> wafersInProcess = waferList.FindAll(
                x => x.Substring(0, 4) == process);
            foreach (string waferInThisProcess in wafersInProcess)
            {
                newProcess.Children.Add(waferInThisProcess);
            }                
        }
    }

    public ObservableCollection<Process> ProcessList
    {
        get
        {
            return processList;
        }
        set
        {
            processList = value;
            OnPropertyChanged("ProcessList");
        }
    }
}

Can anyone figure out why the items are not showing up in the tree view??

Regards,

Kyle

Upvotes: 0

Views: 474

Answers (1)

Sphinxxx
Sphinxxx

Reputation: 13057

There are a couple of errors in your bindings. If you run your application from Visual Studio, you'll probably see one or more messages like this in the Output window:

System.Windows.Data Error: 40 : BindingExpression path error: (...)

Firstly, each root item is bound to a Process object from TreeViewViewModel.ProcessList and it's told to display a property called ProcessNumber, but there is no such property, at least not in the code you posted. So I'm guessing the process items are showing up in the TreeView, but they're blank.

Secondly, your HierarchicalItemTemplate says that the list of child items can be found in a property called ProcessList. But each root item is a Process, which doesn't have that property, so no child items are displayed. You probably mean:

<HierarchicalDataTemplate ItemsSource="{Binding Children}">

Now, Process.Children is a simple list of strings, so you don't need to include the <HierarchicalDataTemplate.ItemTemplate> part (and of course, strings don't have the Wafer property that template is looking for).

Upvotes: 1

Related Questions