TreeListView IsExpanded Problems

5 posts, 0 answers
  1. Glenn
    Glenn avatar
    3 posts
    Member since:
    Sep 2013

    Posted 01 Jul 2014 Link to this post

    I'm trying to set up my view model items with an IsExpanded property that I can use to expand & collapse their row programmatically. We previously did this with a TreeView pretty easily, but ended up needing the extra columns of a TreeListVIew so now we're trying to port over functionality to a TreeListView. Unfortunately I'm having problems getting rows to expand programmatically with a virtualized TreeListView.

    I first tried using the IsExpandedBinding on the TreeListView itself:

    IsExpandedBinding="{Binding IsExpanded, Mode=TwoWay}"

    This successfully allowed my items to listen to when the user expanded/collapsed the item's row by clicking in the UI, but failed to ever propagate changes back to the UI when I modified my item's IsExpanded property programmatically.

    My next attempt was to modify my TreeListView's TreeListViewRow's Style to binding the row's IsExpanded property directly to my item's IsExpanded property. This method almost works. The part where this fails is that my TreeListView uses virtualization, and any items not currently visible fail to update when their IsExpanded property gets modified via the binding.

    So my questions are, does the IsExpandedBinding really support TwoWay? If so, what might we be doing wrong? If not, how can I get the row's IsExpanded binding to function when the TreeListView is virtualized?

    Thanks!
  2. Glenn
    Glenn avatar
    3 posts
    Member since:
    Sep 2013

    Posted 02 Jul 2014 in reply to Glenn Link to this post

    I was able to find a sample app on the forums where IsExpandedBinding worked with full TwoWay support. I then realized that our implementation of our items' IsExpanded property is via a DependencyProperty. When I changed the property to a simple field-based property + a PropertyChanged event, the TreeListView started responding to our changes, including non-visible rows.

    I'm not sure why the TreeListView would fail to pick up on our DependencyProperty changes. I managed to repro the problem in the sample app by making IsSelected a DependencyProperty there as well. Even when I make sure it has BindsTwoWayByDefault, changes to the IsSelected in code fail to update the UI.
  3. UI for WPF is Visual Studio 2017 Ready
  4. Nick
    Admin
    Nick avatar
    593 posts

    Posted 04 Jul 2014 Link to this post

    Hi Glenn,

    This seems a bit strange. Can you share the sample you have so we can examine it, and if there is indeed a problem fix it? 

    Thank you in advance. 

    Regards,
    Nik
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
  5. Glenn
    Glenn avatar
    3 posts
    Member since:
    Sep 2013

    Posted 04 Jul 2014 in reply to Nick Link to this post

    Sure thing! Here is the modified Club.cs file from the sample IsExpandedBinding_RadGridView_WPF solution:


    using System.ComponentModel;
    using Telerik.Windows.Data;

    namespace RadGridView_WPF_AR_32
    {
    using System.Windows;

    /// <summary>
        /// A football club.
        /// </summary>
        public class Club : DependencyObject, INotifyPropertyChanged
    {
    public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register(
      "IsSelected",
      typeof(bool),
      typeof(Club),
      new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

            public event PropertyChangedEventHandler PropertyChanged;

            private string name;
            private RadObservableCollection<Player> players;
            private string country;
            //private bool isSelected;

            public string Country
            {
                get { return this.country; }
                set
                {
                    if (value != this.country)
                    {
                        this.country = value;
                        this.OnPropertyChanged("Country");
                    }
                }
            }

            private int number;
            public int Number
            {
                get
                {
                    return this.number;
                }
                set
                {
                    if (this.number != value)
                    {
                        this.number = value;
                        this.OnPropertyChanged("Number");
                    }
                }
            }

            public string Name
            {
                get { return this.name; }
                set
                {
                    if (value != this.name)
                    {
                        this.name = value;
                        this.OnPropertyChanged("Name");
                    }
                }
            }

            public bool IsSelected
            {
                /*get { return this.isSelected; }
                set
                {
                    if (value != this.isSelected)
                    {
                        this.isSelected = value;
                        this.OnPropertyChanged("IsSelected");
                    }
                }*/

    get
    {
    return (bool)this.GetValue(IsSelectedProperty);
    }

    set
    {
    this.SetValue(IsSelectedProperty, value);
    }
            }


            public RadObservableCollection<Player> Players
            {
                get
                {
                    if (null == this.players)
                    {
                        this.players = new RadObservableCollection<Player>();
                    }

                    return this.players;
                }
            }

            public Club()
            {

            }

            public Club(string name, string country, int number, bool isSelected)
            {
                this.name = name;
                this.country = country;
                this.number = number;
                this.IsSelected = isSelected;
            }

            public Club(string name, RadObservableCollection<Player> players, string country, int number, bool isSelected)
                : this(name, country, number, isSelected)
            {
                this.players = players;
            }

            protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
            {
                PropertyChangedEventHandler handler = this.PropertyChanged;
                if (handler != null)
                {
                    handler(this, args);
                }
            }

            private void OnPropertyChanged(string propertyName)
            {
                this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
            }

            public override string ToString()
            {
                return this.Name;
            }

            public static RadObservableCollection<Club> GetClubs()
            {
                RadObservableCollection<Club> clubs = new RadObservableCollection<Club>();
                Club club;

                // Liverpool
                club = new Club("Liverpool", "England", 1, true);
                club.Players.Add(new Player("Pepe Reina", "Spain", 1 ));
                club.Players.Add(new Player("Jamie Carragher", "England", 7 ));
                club.Players.Add(new Player("Steven Gerrard", "England", 4 ));
                club.Players.Add(new Player("Fernando Torres", "Spain", 90 ));
                clubs.Add(club);

                // Manchester Utd.
    club = new Club("Manchester Utd.", "England", 2, true);
                club.Players.Add(new Player("Edwin van der Sar", "Netherlands", 2 ));
                club.Players.Add(new Player("Rio Ferdinand", "England", 34 ));
                club.Players.Add(new Player("Ryan Giggs", "Wales", 7 ));
                club.Players.Add(new Player("Wayne Rooney", "England", 9 ));
                clubs.Add(club);

                // Chelsea
                club = new Club("Chelsea", "England", 3, true);
                club.Players.Add(new Player("Petr Čech", "Czech Republic", 3));
                club.Players.Add(new Player("John Terry", "England", 45));
                club.Players.Add(new Player("Frank Lampard", "England", 45));
                club.Players.Add(new Player("Nicolas Anelka", "France", 23));
                clubs.Add(club);

                // Arsenal
                club = new Club("Arsenal", "England", 4, true);
                club.Players.Add(new Player("Manuel Almunia", "Spain", 48));
                club.Players.Add(new Player("Gaël Clichy", "France", 21));
                club.Players.Add(new Player("Cesc Fàbregas", "Spain", 22));
                club.Players.Add(new Player("Robin van Persie", "Netherlands", 23));
                clubs.Add(club);
                return clubs;
            }
        }
    }
  6. Nick
    Admin
    Nick avatar
    593 posts

    Posted 08 Jul 2014 Link to this post

    Hello Glenn,

    Judging by the snippet you sent, you are still bound to a CLR property. The binding mechanism does not know that the set and get actions use a Dependency property to get or set the value, therefore you cannot expect the bindings to be updated without a PropertyChanged notification. 

    Hope this makes sense. 

    Regards,
    Nik
    Telerik
     
    Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
     
Back to Top
UI for WPF is Visual Studio 2017 Ready