IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

[WPF MVVM] Listbox simple avec défilement automatique sur le dernier ajout


Sujet :

VB.NET

  1. #1
    Membre averti Avatar de megamario
    Homme Profil pro
    VB6/VB.net/C/C++/C#
    Inscrit en
    Septembre 2008
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : VB6/VB.net/C/C++/C#
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2008
    Messages : 929
    Points : 312
    Points
    312
    Par défaut [WPF MVVM] Listbox simple avec défilement automatique sur le dernier ajout
    Bonjour à tous,

    Je sèche sur un truc qui aurait quand même pu être plus simple.

    Contexte:

    Une simple Listbox visualise les transmissions entrante et sortant sur le port COM.

    Le souci, c'est que je souhaite respecter le pattern MVVM et a chaque ajout de texte j'ai un défilement automatique sur le dernier texte ajouté (ou arrêt du défilement si l'utilisateur souhaite vérifier manuellement les captures ,par exemple en cliquant sur une checkbox).

    J'ai trouvé un code C# que j'ai adapté VB, mais s'il fonctionne bien au début ensuite lorsque la listbox ce rempli cela part en sucette avec des bon vers le bas puis vers le haut, c'est pas fluide (j’appelle sa des rebond). Pas clean donc. Et puis même sur le code C# je n'arrive pas a empêcher le défilement automatique à l'aide d'une Checkbox qui n'a du coup aucun effet.

    Bizarrement sur cet exemple j'ai pas ce problème de rebond de l'autoscroll, pourtant le code est le même.



    Exemple complet en C#:

    Vue Model:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Windows.Threading;
     
    namespace Test_Listbox_Autoscroll 
    {
        class VueModele : INotifyPropertyChanged
        {
     
            DispatcherTimer Timer;
            ObservableCollection<String> _LST_ListBox1_Collection;
            String _LST_ListBox1_SelectedItem;
            int i;
            public VueModele()
            {
                LST_ListBox1_Collection = new ObservableCollection<string>();
                Timer = new DispatcherTimer();
                Timer.Interval = new TimeSpan(0, 0, 1);
                Timer.Tick += new EventHandler(Timer_Tick);
                Timer.Start();
            }
            private void Timer_Tick(object sender, EventArgs e)
            {
                i += 1;
                LST_ListBox1_Collection.Add("Ligne " + i);
            }
            public ObservableCollection<String> LST_ListBox1_Collection
            {
                get { return _LST_ListBox1_Collection; }
                set {
                    _LST_ListBox1_Collection = value;
                    OnPropertyChanged("_LST_ListBox1_Collection");
                }
            }
            public String LST_ListBox1_SelectedItem
            {
                get { return _LST_ListBox1_SelectedItem; }
                set {
                    _LST_ListBox1_SelectedItem = value;
                    OnPropertyChanged("LST_ListBox1_SelectedItem");
                }
            }
     
            public event PropertyChangedEventHandler PropertyChanged;
            public void OnPropertyChanged(string Name)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(Name));
                }
            }
        }
    }
    Classe LoggingListBox qui n'est pas de moi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
     
    namespace Test_Listbox_Autoscroll
    {
        public class LoggingListBox : ListBox
        {
            ///<summary>
            ///Define the AutoScroll property. If enabled, causes the ListBox to scroll to 
            ///the last item whenever a new item is added.
            ///</summary>
            public static readonly DependencyProperty AutoScrollProperty =
                DependencyProperty.Register(
                    "AutoScroll",
                    typeof(Boolean),
                    typeof(LoggingListBox),
                    new FrameworkPropertyMetadata(
                        true, //Default value.
                        FrameworkPropertyMetadataOptions.AffectsArrange |
                        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                        AutoScroll_PropertyChanged));
     
            /// <summary>
            /// Gets or sets whether or not the list should scroll to the last item 
            /// when a new item is added.
            /// </summary>
            [Category("Common")] //Indicate where the property is located in VS designer.
            public bool AutoScroll
            {
                get { return (bool)GetValue(AutoScrollProperty); }
                set { SetValue(AutoScrollProperty, value); }
            }
     
            /// <summary>
            /// Event handler for when the AutoScroll property is changed.
            /// This delegates the call to SubscribeToAutoScroll_ItemsCollectionChanged().
            /// </summary>
            /// <param name="d">The DependencyObject whose property was changed.</param>
            /// <param name="e">Change event args.</param>
            private static void AutoScroll_PropertyChanged(
                DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                SubscribeToAutoScroll_ItemsCollectionChanged(
                    (LoggingListBox)d,
                    (bool)e.NewValue);
            }
     
            /// <summary>
            /// Subscribes to the list items' collection changed event if AutoScroll is enabled.
            /// Otherwise, it unsubscribes from that event.
            /// For this to work, the underlying list must implement INotifyCollectionChanged.
            ///
            /// (This function was only creative for brevity)
            /// </summary>
            /// <param name="listBox">The list box containing the items collection.</param>
            /// <param name="subscribe">Subscribe to the collection changed event?</param>
            private static void SubscribeToAutoScroll_ItemsCollectionChanged(
                LoggingListBox listBox, bool subscribe)
            {
                INotifyCollectionChanged notifyCollection =
                    listBox.Items.SourceCollection as INotifyCollectionChanged;
                if (notifyCollection != null)
                {
                    if (subscribe)
                    {
                        //AutoScroll is turned on, subscribe to collection changed events.
                        notifyCollection.CollectionChanged +=
                            listBox.AutoScroll_ItemsCollectionChanged;
                    }
                    else
                    {
                        //AutoScroll is turned off, unsubscribe from collection changed events.
                        notifyCollection.CollectionChanged -=
                            listBox.AutoScroll_ItemsCollectionChanged;
                    }
                }
            }
     
            /// <summary>
            /// Event handler called only when the ItemCollection changes
            /// and if AutoScroll is enabled.
            /// </summary>
            /// <param name="sender">The ItemCollection.</param>
            /// <param name="e">Change event args.</param>
            private void AutoScroll_ItemsCollectionChanged(
                object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.Action == NotifyCollectionChangedAction.Add)
                {
                    int count = Items.Count;
                    ScrollIntoView(Items[count - 1]);
                }
            }
     
            /// <summary>
            /// Constructor a new LoggingListBox.
            /// </summary>
            public LoggingListBox()
            {
                //Subscribe to the AutoScroll property's items collection 
                //changed handler by default if AutoScroll is enabled by default.
                SubscribeToAutoScroll_ItemsCollectionChanged(
                    this, (bool)AutoScrollProperty.DefaultMetadata.DefaultValue);
            }
        }
    }

    MainWindow XAML:
    Code XAML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <Window x:Class="Test_Listbox_Autoscroll.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:local="clr-namespace:Test_Listbox_Autoscroll"
            xmlns:tools="clr-namespace:Test_Listbox_Autoscroll"
            mc:Ignorable="d"
            Title="MainWindow" Width="800"
             SizeToContent =" WidthAndHeight">
        <Grid>
            <StackPanel >
                <tools:LoggingListBox x:Name="Listbox1"
                                  Margin=" 10"
                                  Background="Bisque"
                                      Height="180"
                                  ItemsSource="{Binding LST_ListBox1_Collection}"
                                  SelectedItem="{Binding LST_ListBox1_SelectedItem}"/>
                <CheckBox x:Name="ChkAutoScroll"
                          Margin="10"
                          Content="Auto Scroll"
                          Checked="ChkAutoScroll_Checked"
                          Click="ChkAutoScroll_Click"/>
            </StackPanel>
     
        </Grid>
    </Window>

    MainWindow Code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    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;
     
    namespace Test_Listbox_Autoscroll
    {
        /// <summary>
        /// Logique d'interaction pour MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                VueModele VM = new VueModele();
                this.DataContext = VM;
     
            }
     
            private void ChkAutoScroll_Checked(object sender, RoutedEventArgs e)
            {
     
            }
     
            private void ChkAutoScroll_Click(object sender, RoutedEventArgs e)
            {
                if (ChkAutoScroll.IsChecked == true)
                {
                    Listbox1.AutoScroll = true;
                }
                else
                {
                    Listbox1.AutoScroll = false;
                }
            }
        }
    }


    Voila le même code en VB:
    Vue Model:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    Imports System.Collections.ObjectModel
    Imports System.ComponentModel
    Imports System.Windows.Threading
     
     
    Public Class VueModele
        Implements INotifyPropertyChanged
     
        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
        Public Sub OnPropertyChanged(propname As String)
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propname))
        End Sub
     
        Private _LST_ListBox1_Collection As ObservableCollection(Of String)
        Private _LST_ListBox1_SelectedItem As Integer
        Private Timer As DispatcherTimer
        Private i As Integer
     
        Public Sub New()
            LST_ListBox1_Collection = New ObservableCollection(Of String)
            Timer = New DispatcherTimer
            Timer.Interval = New TimeSpan(0, 0, 1)
            AddHandler Timer.Tick, AddressOf Timer_Tick
            Timer.Start()
        End Sub
     
        Public Property LST_ListBox1_SelectedItem As Integer
            Get
                Return _LST_ListBox1_SelectedItem
            End Get
            Set(value As Integer)
                _LST_ListBox1_SelectedItem = value
                OnPropertyChanged("LST_ListBox1_SelectedItem")
            End Set
        End Property
        Public Property LST_ListBox1_Collection As ObservableCollection(Of String)
            Get
                Return _LST_ListBox1_Collection
            End Get
            Set(value As ObservableCollection(Of String))
                _LST_ListBox1_Collection = value
                OnPropertyChanged("LST_ListBox1_Collection")
            End Set
        End Property
        Private Sub Timer_Tick()
            i += 1
            LST_ListBox1_Collection.Add("Ligne " & CStr(i))
        End Sub
     
     
     
    End Class

    Classe LoggingListBox que j'ai converti:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    Imports System.Collections.Specialized
    Imports System.ComponentModel
     
     
    Public Class LoggingListBox
            Inherits ListBox
     
     
            Public Shared ReadOnly AutoScrollProperty As DependencyProperty = DependencyProperty.Register("AutoScroll", GetType(Boolean), GetType(LoggingListBox), New FrameworkPropertyMetadata(True, FrameworkPropertyMetadataOptions.AffectsArrange Or FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, AddressOf AutoScroll_PropertyChanged))
     
     
            <Category("Common")>
            Public Property AutoScroll() As Boolean
                Get
                    Return DirectCast(GetValue(AutoScrollProperty), Boolean)
                End Get
                Set(ByVal value As Boolean)
                    SetValue(AutoScrollProperty, value)
                End Set
            End Property
     
     
            Private Shared Sub AutoScroll_PropertyChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
                SubscribeToAutoScroll_ItemsCollectionChanged(CType(d, LoggingListBox), DirectCast(e.NewValue, Boolean))
            End Sub
     
     
            Private Shared Sub SubscribeToAutoScroll_ItemsCollectionChanged(ByVal listBox As LoggingListBox, ByVal subscribe As Boolean)
                Dim notifyCollection As INotifyCollectionChanged = TryCast(listBox.Items.SourceCollection, INotifyCollectionChanged)
                If notifyCollection IsNot Nothing Then
                    If subscribe Then
                        'AutoScroll is turned on, subscribe to collection changed events.
                        AddHandler notifyCollection.CollectionChanged, AddressOf listBox.AutoScroll_ItemsCollectionChanged
                    Else
                        'AutoScroll is turned off, unsubscribe from collection changed events.
                        RemoveHandler notifyCollection.CollectionChanged, AddressOf listBox.AutoScroll_ItemsCollectionChanged
                    End If
                End If
            End Sub
     
     
            Private Sub AutoScroll_ItemsCollectionChanged(ByVal sender As Object, ByVal e As NotifyCollectionChangedEventArgs)
                If e.Action = NotifyCollectionChangedAction.Add Then
                    Dim count As Integer = Items.Count
                    ScrollIntoView(Items(count - 1))
                End If
            End Sub
     
     
            Public Sub New()
                'Subscribe to the AutoScroll property's items collection 
                'changed handler by default if AutoScroll is enabled by default.
                SubscribeToAutoScroll_ItemsCollectionChanged(Me, DirectCast(AutoScrollProperty.DefaultMetadata.DefaultValue, Boolean))
            End Sub
        End Class
    MainWindow Xaml:
    Code XAML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    <Window x:Class="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:local="clr-namespace:Test_Listbox_Autoscroll"
            xmlns:tools="clr-namespace:Test_Listbox_Autoscroll"
            mc:Ignorable="d"
            Title="MainWindow" Width="800"
             SizeToContent =" WidthAndHeight">
        <Grid>
            <StackPanel >
     
                <tools:LoggingListBox x:Name="Listbox1"
                                  Margin=" 10"
                                  Background="Bisque"
                                      Height="180"
                                  ItemsSource="{Binding LST_ListBox1_Collection}"
                                  SelectedItem="{Binding LST_ListBox1_SelectedItem}"/>
                <CheckBox x:Name="ChkAutoScroll"
                          Margin="10"
                          Content="Auto Scroll"
                          Checked="ChkAutoScroll_Checked"
                          Click="ChkAutoScroll_Click"/>
            </StackPanel>
     
        </Grid>
    </Window>


    MainWindow Code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    Class MainWindow
        Public Sub New()
     
            ' Cet appel est requis par le concepteur.
            InitializeComponent()
     
            ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
            Dim VM As New VueModele
            Me.DataContext = VM
        End Sub
     
        Private Sub ChkAutoScroll_Checked(sender As Object, e As RoutedEventArgs)
     
        End Sub
     
        Private Sub ChkAutoScroll_Click(sender As Object, e As RoutedEventArgs)
            If (ChkAutoScroll.IsChecked = True) Then
     
                Listbox1.AutoScroll = True
            Else
     
                Listbox1.AutoScroll = False
            End If
        End Sub
    End Class


    ce qui m’intéresse c'est le VB.net. Mais je vous ai mis le C# car c'est le code d'origine, mais lui aussi l'autoscroll est toujours actif.

  2. #2
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour

    L'aeezr du defilement automatique se fait sur le checjjvox à condition:
    1/ la DP CheckBox.IsChecked soit simplement bindé sur
    2/ la DP Listbox.AutoScroll & que celui soint "synchronisé" avec le "current item" selectionné...
    je n'observe aucun rebond par ailleurs...
    code xaml revu du form:

    Code XAML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    <Grid>
            <StackPanel >
     
                <local:LoggingListBox 
                    x:Name="Listbox1"
                    Margin=" 10"
                    IsSynchronizedWithCurrentItem="True"
                    AutoScroll="{Binding ElementName=ChkAutoScroll,Path=IsChecked,Mode=TwoWay}"
                    Height="180"
                    ItemsSource="{Binding LST_ListBox1_Collection}"
                    SelectedItem="{Binding LST_ListBox1_SelectedItem}"/>
                <CheckBox x:Name="ChkAutoScroll"
                          Margin="10"
                          Content="Auto Scroll"
                          IsChecked="False"
                          />
            </StackPanel>
     
        </Grid>
    les handlers du CheckBox sont inutiles et à virer...
    von code...

Discussions similaires

  1. [MySQL] Requête simple avec un Where sur un champ utf8_bin
    Par Romanops dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 16/08/2011, 16h35
  2. Réponses: 5
    Dernier message: 29/03/2010, 20h24
  3. Barre défilement automatique sur une page vb6
    Par fiche00 dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 19/12/2007, 15h44
  4. "scrollbar" avec défilement automatique dans listbox
    Par nanettemontp dans le forum Windows
    Réponses: 4
    Dernier message: 15/10/2007, 10h44
  5. Réponses: 18
    Dernier message: 23/06/2007, 01h17

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo