0

I am trying to bind an ObservableCollection of objects to a TreeView. The object class is shown below

public partial class Layer_Properties : Window
{    
    //fields
    private string _routeName;
    private  List<Stop> _Stops_List = new List<Stop>();

    public string routeName   // property
    {
        get { return _routeName; }   // get method
        set { _routeName = value; }  // set method
    }

    public List<Stop> Stops_List   // property
    {
        get { return _Stops_List; }   // get method
        set { _Stops_List = value; }  // set method
    }

    public List<PolylineBarrier> polylineBarriers// property
    {
        get { return _polylineBarriers; }   // get method
        set { _polylineBarriers= value; }  // set method
    }

    public Layer_Properties(RouteTask asolveRouteTask, MapViewModel aMapViewModel)
    {      
        InitializeComponent();
        solveRouteTask = asolveRouteTask;
        _mapViewModel = aMapViewModel;

        this.Loaded += async (o, e) =>
        {
            await Task.Run(() => getnetworkDatasetProprties(solveRouteTask));
            routeGUID = Convert.ToString(Guid.NewGuid());
            dateTime_label.IsEnabled = false;
            dateTime_ComboBox.IsEnabled = false;
            this.dateTime_ComboBox.Value = DateTime.UtcNow;
            Use_Time_Windows_chkbox.IsEnabled = false;
            Use_Time_Windows_chkbox.IsEnabled = false;
            Use_Time_Windows_chkbox.IsEnabled = false;
            PreserveFirstStop_chkbox.IsChecked = true;
            PreserveLastStop_chkbox.IsChecked = true;
            PreserveFirstStop_chkbox.IsEnabled = false;
            PreserveLastStop_chkbox.IsEnabled = false;

            Layer_Properties item = null;
            if (_mapViewModel.LayersPool.Count <= 1)
            {
                item = _mapViewModel.LayersPool[_mapViewModel.LayersPool.Count - 1];
            }
            else
            {
                item = _mapViewModel.LayersPool[_mapViewModel.LayersPool.Count - 2];
            }

            if (item != null)
            {
                item.routeName = IndexedFilename("Route", item.routeName);
            }
        };
    }

Part of the mapviewmodel is shown below:

public class MapViewModel : INotifyPropertyChanged
{
    public MapViewModel()
    {
    }

    //test 09062020
    public ObservableCollection<Layer_Properties> LayersPool
    {
        get { return layersPool; }
        set
        {
            layersPool = value;
            NotifiyPropertyChanged("LayersPool");
        }
    }

    private ObservableCollection<Layer_Properties> layersPool= new 
    ObservableCollection<Layer_Properties>();

    void NotifiyPropertyChanged(string property)
    {
        if (LayersPoolChanged != null)
            LayersPoolChanged(this, new PropertyChangedEventArgs(property));
    }

    public event PropertyChangedEventHandler LayersPoolChanged;
    //endtest
}

Part of the xaml is shown below:

<Window x:Class="GIS_App.MainWindow"
    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"
    xmlns:esri="http://schemas.esri.com/arcgis/runtime/2013"
    xmlns:local="clr-namespace:GIS_App"
    mc:Ignorable="d"
    Title="MainWindow" Height="732" Width="1399" Closing="Window_Closing">

<Window.Resources>
    <local:MapViewModel x:Key="MapViewModel"/>
    <ImageBrush  x:Key="NetworkAnalystWindow" ImageSource="/icons/NetworkAnalystWindow.png" Stretch="UniformToFill"/>
    <ImageBrush  x:Key="AddNetworkElement" ImageSource="/icons/AddNetworkElement_btn.png" Stretch="UniformToFill"/>
    <ImageBrush  x:Key="solveRoute" ImageSource="/icons/solve_btn.png" Stretch="UniformToFill"/>
    <ImageBrush  x:Key="solvePremiumRoute" ImageSource="/icons/solvePremium_btn.png" Stretch="UniformToFill"/>
    <ImageBrush  x:Key="RouteDirections" ImageSource="/icons/directions_btn.png" Stretch="UniformToFill"/>
    <ImageBrush  x:Key="AddTrafficLayer" ImageSource="/icons/AddTrafficLayer.png" Stretch="UniformToFill"/>
    <ContextMenu x:Key="cmButton">
        <MenuItem Name ="Draw_Sketch" Header="Draw Sketch" Click="btn_Click"/>
        <MenuItem Name ="Save_Sketch" Header="Save Sketch" Click="btn_Click"/>
        <MenuItem Name ="Delete_Sketch" Header="Delete Sketch" Click="btn_Click" IsEnabled="True"/>
        <MenuItem Name ="Remove_Selected_Vertex" Header="Remove Selected Vertex" Click="btn_Click" IsEnabled="True"/>
        <MenuItem Name ="Cancel" Header="Cancel" Click="btn_Click" IsEnabled="True"/>
        <Separator />
        <MenuItem Header="Address Geocoding" Click="btn_Click" IsEnabled="True"/>
    </ContextMenu>
    <ContextMenu x:Key="treeViewMenu">
        <MenuItem Name ="Delete_TreeViewElement" Header="Delete" Click="btn_Click"/>
        <MenuItem Name ="Delete_All_TreeViewElements" Header="Delete All" Click="btn_Click"/>
        <MenuItem Name ="Open_Attribute_Table" Header="Open_Attribute_Table" Click="btn_Click" IsEnabled="True"/>
    </ContextMenu>
</Window.Resources>

<Grid HorizontalAlignment="Left" Height="Auto" Margin="5,25,0,20" VerticalAlignment="Stretch" Width="155">

            <!-- hieracical binding -->
            <TextBlock Text="Hierarchical root binding}" Foreground="Red" Margin="10,20,0,0"/>
            <TreeView ItemsSource="{Binding LayersPool}" Margin="10" Height="200">
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding LayersPool}" DataType="{x:Type local:Layer_Properties}">
                        <TreeViewItem Header="{Binding routeName}"/>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>

i ve made numerous attempts to make it work but i cannot find a solution. What i want to achieve is create a treeview as follows:

Route_1
  Stops
    Stop1
    Stop2
    Stop3
  Polyline Barriers
    Barrier 1
Route_2
  Stops
    Stop1
    Stop2
  Polyline Barriers
    Barrier 1
    Barrier2

Edit I suspect there might be an issue with binding since LayersPool observablecollection is a mapviewmodel collection. Any help will be welcome.

ASh
  • 34,632
  • 9
  • 60
  • 82
sotokan80
  • 49
  • 8

1 Answers1

0

I think you need to understand how TreeView binding works.

You can have a look here: wpf treeview binding and also here: https://www.wpf-tutorial.com/treeview-control/treeview-data-binding-multiple-templates/

Generally speaking, if each TreeViewItem ViewModel needs to do something specific (for example once the user click on it, then you need to create your own ViewModel specific class for each TreeViewItem.

You might create an AbstractViewModel as a base class for every TreeViewItem ViewModel that contains basically 2 properties.

  1. Children binded to ItemsSource in the HierarchicalDataTemplate that contains an ObservableCollection of current treeviewitem's leaves
  2. Name binded to your Text property of the TextBlock you placed in your DataTemplate to show the treeview item text.
trix
  • 878
  • 6
  • 14
  • yes i understand studying is everything but i spent much time trying to find a solution and i cannot understand why the above code doesnt work. it cant be so difficult to bind a list of object to a treeview. – sotokan80 Jun 09 '20 at 14:04