ListBox, ListView et défilement automatique

J’alimente un contrôle ListBox avec un UserControl qui affiche une conversation, comme illustré sur la figure suivante :

image

L’idée c’est d’avoir 0% de code dans la vue, j’utilise donc le modèle MVVM mais le soucis c’est que lorsque le nombre d’éléments dépasse l’espace d’affichage de ma ListBox, aucun défilement automatique n’est effectué pour afficher le dernier élément.

Pour contourner ce problème est n’avoir toujours aucun code derrière ma vue, je suis parti sur la solution qui consiste à créer une ListBox personnalisée (qui dérive de la ListBox standard), d’implémenter une DependencyProperty qui appellera automatiquement la méthode ScrollIntoView de la ListBox .

class CustomListBox : ListBox
    {
        public static readonly DependencyProperty ScrollViewFromIndexProperty =
            DependencyProperty.Register(
            "ScrollViewFromIndex",
            typeof(int),
            typeof(CustomListBox), new PropertyMetadata(0, new PropertyChangedCallback(OnNewItemAdded))
            );

        public CustomListBox()
        {
            this.DefaultStyleKey = typeof(CustomListBox);
          
        }
        public int ScrollViewFromIndex
        {
            get { return (int)GetValue(ScrollViewFromIndexProperty); }
            set {
                SetValue(ScrollViewFromIndexProperty, (int)value);
                            
            }
        }
            
        private static void OnNewItemAdded(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
          
            int CurrentIndex =(int)e.NewValue;
            ListBox CurrentList = d as ListBox;
            if (CurrentList!=null)
            {

                CurrentList.SelectedIndex=CurrentIndex;
                CurrentList.UpdateLayout();
                CurrentList.ScrollIntoView(CurrentList.SelectedItem);
            }
            
        }       
    }

Je Bind la DependencyProperty ScrollViewFromIndex à BINDING_PROP_CURRENT_INDEX qui est elle même mis à jour à chaque fois qu’un nouvel élément est ajouté en tant que source de la ListBox.

<ShareViews:CustomListBox ItemsSource="{Binding BINDING_PROP_LISTMESSAGES}" Background="{x:Null}"
            ScrollViewFromIndex="{Binding BINDING_PROP_CURRENT_INDEX}"

 

private int m_CurrentIndex;
        public int BINDING_PROP_CURRENT_INDEX
        {
            get { return m_CurrentIndex; }
            set
            {
                this.SetProperty(ref m_CurrentIndex, value);
            }
        }
        ObservableCollection<UserControl> m_ListMessages;
        public ObservableCollection<UserControl> BINDING_PROP_LISTMESSAGES
        {
            get { return m_ListMessages; }
            set
            {
                this.SetProperty(ref m_ListMessages, value);
                BINDING_PROP_CURRENT_INDEX = m_ListMessages.Count - 1;
            }

        }

Sans doute les puristes vont râler, mais bon pour les autres une petite solution simple et rapide à mettre en œuvre et qui fonctionne également pour Windows Phone.

Eric