rbasniak
rbasniak

Reputation: 4984

Bound treeview partially refreshing

I made a shot app to exemplify my question:

Heres the window1.xaml

    <Window
        x:Class="TreeViewStepByStep.Window1"
        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:sys="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d"
        Width="400"
        Height="600">
        <Window.Resources />
        <Grid>
            <TreeView
                Margin="0,21,0,0"
                ItemsSource="{Binding Regions}"
                HorizontalAlignment="Left"
                Width="221">

                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate
                        ItemsSource="{Binding Type}">
                        <TextBlock
                            Text="{Binding Name}" />

                        <HierarchicalDataTemplate.ItemTemplate>
                            <HierarchicalDataTemplate
                                ItemsSource="{Binding Locations}">
                                <TextBlock
                                    Text="{Binding Name}" />

                                <HierarchicalDataTemplate.ItemTemplate>
                                    <DataTemplate>
                                        <TextBlock
                                            Text="{Binding}" />
                                    </DataTemplate>
                                </HierarchicalDataTemplate.ItemTemplate>

                            </HierarchicalDataTemplate>
                        </HierarchicalDataTemplate.ItemTemplate>

                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>

            </TreeView>



            <Button
                Content="Populate"
                Height="23"
                HorizontalAlignment="Left"
                Margin="227,21,0,0"
                Name="button2"
                VerticalAlignment="Top"
                Width="96"
                Click="button2_Click" />
            <Button
                Content="Add child"
                Height="23"
                HorizontalAlignment="Left"
                Margin="227,49,0,0"
                Name="button3"
                VerticalAlignment="Top"
                Width="96"
                Click="button3_Click" />
            <Button
                Content="Modify"
                Height="23"
                HorizontalAlignment="Left"
                Margin="227,106,0,0"
                Name="button4"
                VerticalAlignment="Top"
                Width="96"
                Click="button4_Click" />
            <Button
                Content="Add root level"
                Height="23"
                HorizontalAlignment="Left"
                Margin="227,135,0,0"
                Name="button5"
                VerticalAlignment="Top"
                Width="96"
                Click="button5_Click" />
        </Grid>
    </Window>

And here's the window1.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Collections.ObjectModel;

    namespace TreeViewStepByStep
    {
        /// <summary>
        /// Interaction logic for Window1.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            Collection<Region> regions;

            public Window1()
            {
                InitializeComponent();
            }

            private void button2_Click(object sender, RoutedEventArgs e)
            {
                Region sms = new Region("São Mateus do Sul")
                {
                    Type =
                    {
                        new Types("Placemarks")
                        {
                            Locations = 
                            { 
                                "Pine trees", 
                                "Barn", 
                                "Phantom city" 
                            }
                        },

                        new Types("Planning")
                        { 
                            Locations = 
                            { 
                                "Geada", 
                                "Por do sol" 
                            }
                        },
                    }
                };

                Region others = new Region("Outros")
                {
                    Type =
                    {
                        new Types("Placemarks")
                        {
                            Locations = 
                            { 
                                "Road", 
                                "Waterfall" 
                            }
                        },
                        new Types("Planning")
                        { 
                            Locations = 
                            { 
                                "Moon" 
                            }
                        },  
                    }
                };

                regions = new Collection<Region>() { sms, others };

                DataContext = new
                {
                    Regions = regions
                };
            }

            private void button3_Click(object sender, RoutedEventArgs e)
            {
                this.regions[1].Type.Add(new Types("New folder")
                                             { 
                                                Locations = 
                                                { 
                                                    "Test" 
                                                }
                                             }
                                        );
            }

            private void button4_Click(object sender, RoutedEventArgs e)
            {
                this.regions[0].Name = "Edited";
            }

            private void button5_Click(object sender, RoutedEventArgs e)
            {
                this.regions.Add(new Region("My new region"));
            }
        }

        public class Region
        {
            public Region(string name)
            {
                Name = name;
                Type = new ObservableCollection<Types>();
            }

            public string Name { get; set; }
            public ObservableCollection<Types> Type { get; set; }
        }

        public class Types
        {
            public Types(string name)
            {
                Name = name;
                Locations = new ObservableCollection<string>();
            }

            public string Name { get; private set; }
            public ObservableCollection<string> Locations { get; set; }
        }


    }

My TreeView is bound to a hierarchical model (the regions variable). When I click "Populate" it binds the TreeView to this variable. When I click "Add Child" it adds a child element to the bound variable and it reflects on the TreeView. So far so good.

The problem arises when I try to modify the name of an existing element or try to add a root level node ("Modify" and "Add Root Level" buttons). Shouldn't these modifications reflect on the TreeView as well since it's bound to the collection?

Upvotes: 1

Views: 192

Answers (2)

Tim Copenhaver
Tim Copenhaver

Reputation: 3302

As you have it now, the Collection will not notify the view when it is changed. You want to use an ObservableCollection instead of a normal Collection<T>. The ObservableCollection is coded to work with the UI and make sure the view is always updated with those changes through the CollectionChanged event. You use ObservableCollection with some of the others, but your Regions variable is a Collection.

Upvotes: 2

pchajer
pchajer

Reputation: 1584

You need to change the Collection type to ObservableCollection and needs to implement INotifyPropertyChanged on region class to send notification to View on edit.

C# Window Class:

ObservableCollection<Region> regions;

Region Class:

public class Region  : INotifyPropertyChanged
    { 
        public Region(string name) 
        { 
            Name = name; Type = new ObservableCollection<Types>(); 
        } 
        private string name;
                public string Name
        {
            get { return name; }
            set 
            { 
                name = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Name"));
            }
        }

        public ObservableCollection<Types> Type { get; set; }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged = (s, e) => { };

        #endregion
    }

Upvotes: 1

Related Questions