2013-05-31 11 views
9

के साथ सूची में सूची बॉक्स स्क्रॉल करें मेरे पास एक बहुत ही सरल समस्या है, लेकिन मैं यह नहीं समझ सकता कि एमवीवीएम का उपयोग करके इसे कैसे क्रैक करना है।एमवीवीएम

मेरे पास ListBox है जो ObservableCollection<string> से जुड़ा हुआ है।

मैं एक ऐसी प्रक्रिया चलाता हूं जो संग्रह में वस्तुओं का एक पूरा समूह जोड़ देगा और इसलिए उन्हें ListBox में दिखाया गया है।

समस्या यह है कि आइटम सूची बॉक्स में जोड़े गए हैं ... स्क्रॉल बार बस बढ़ता है, लेकिन मुझे लगता है कि संग्रह में जोड़े गए प्रत्येक आइटम के लिए इसे ScrollIntoView बनाने का तरीका नहीं लगता है।

यह नमूना कोड पूरी तरह से समस्या को दर्शाता है।

XAML

<Window x:Class="Stack.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:vm="clr-namespace:Stack" 
    Title="MainWindow" 
    Height="350" 
    Width="525"> 
<Window.DataContext> 
    <vm:MainWindowViewModel /> 
</Window.DataContext> 
<StackPanel> 
    <ListBox Margin="10" Height="150" 
      ItemsSource="{Binding Path=MyValue}" /> 
    <Button Margin="10" 
      Height="25" 
      Content="Generate" 
      Command="{Binding Path=CommandName}" /> 
</StackPanel> 
</Window> 

देखें मॉडल

namespace Stack 
{ 
using System; 
using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Linq; 
using System.Windows.Input; 
using GalaSoft.MvvmLight.Command; 

/// <summary> 
/// TODO: Update summary. 
/// </summary> 
public class MainWindowViewModel : INotifyPropertyChanged 
{ 
    private readonly BackgroundWorker _worker; 

    private ICommand _commandName; 

    private ObservableCollection<string> _myValue = new ObservableCollection<string>(); 

    /// <summary> 
    /// Initializes a new instance of the <see cref="MainWindowViewModel" /> class. 
    /// </summary> 
    public MainWindowViewModel() 
    { 
     this._worker = new BackgroundWorker(); 
     this._worker.DoWork += new DoWorkEventHandler(DoWork); 
     this._worker.ProgressChanged += new ProgressChangedEventHandler(ProgressChanged); 
     this._worker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) 
     { 
      CommandManager.InvalidateRequerySuggested(); 
     }; 
    } 

    /// <summary> 
    /// Occurs when a property value changes. 
    /// </summary> 
    public event PropertyChangedEventHandler PropertyChanged; 

    public ICommand CommandName 
    { 
     get 
     { 
      if (this._commandName == null) 
      { 
       this._commandName = new RelayCommand(() => this.CommandMethod()); 
      } 
      return this._commandName; 
     } 
    } 

    /// <summary> 
    /// Gets or sets my value. 
    /// </summary> 
    /// <value>My value.</value> 
    public ObservableCollection<string> MyValue 
    { 
     get 
     { 
      return this._myValue; 
     } 
     set 
     { 
      this._myValue = value; 
      this.NotifyPropertyChange("MyValue"); 
     } 
    } 

    /// <summary> 
    /// Notifies the property change. 
    /// </summary> 
    /// <param name="propName">Name of the prop.</param> 
    internal void NotifyPropertyChange(string propName) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propName)); 
     } 
    } 

    /// <summary> 
    /// Commands the method. 
    /// </summary> 
    private void CommandMethod() 
    { 
     this.MyValue.Clear(); 
     this._worker.RunWorkerAsync(); 
     this._worker.WorkerReportsProgress = true; 
    } 

    /// <summary> 
    /// Does the work. 
    /// </summary> 
    /// <param name="sender">The sender.</param> 
    /// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs" /> instance containing the event data.</param> 
    private void DoWork(object sender, DoWorkEventArgs e) 
    { 
     this.Populate(); 
    } 

    /// <summary> 
    /// Populates this instance. 
    /// </summary> 
    private void Populate() 
    { 
     for (int index = 0; index < 100; index++) 
     { 
      System.Threading.Thread.Sleep(10); 
      this._worker.ReportProgress(index); 
     } 
    } 

    /// <summary> 
    /// Progresses the changed. 
    /// </summary> 
    /// <param name="sender">The sender.</param> 
    /// <param name="e">The <see cref="System.ComponentModel.ProgressChangedEventArgs" /> instance containing the event data.</param> 
    private void ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     this.MyValue.Add(e.ProgressPercentage.ToString()); 
    } 
} 

}

उत्तर

17

आप एक DependencyProperty बना सकते हैं या बस ListBox नियंत्रण का विस्तार करने और इसके स्थान पर अपने नए नियंत्रण का उपयोग करें।

public class ScrollingListBox : ListBox 
{ 
    protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) 
    { 
     int newItemCount = e.NewItems.Count; 

     if(newItemCount > 0) 
      this.ScrollIntoView(e.NewItems[newItemCount - 1]); 

     base.OnItemsChanged(e); 
    } 
} 

अपने XAML में, वर्ग के नाम स्थान जोड़ें:

xmlns:custom="clr-namespace:ScrollingListBoxNamespace" 

और अपने कस्टम एक के साथ अपने मानक ListBox बाहर स्वैप:

<custom:ScrollingListBox Margin="10" Height="150" 
         ItemsSource="{Binding Path=MyValue}" /> 
+2

बहुत धन्यवाद ...! –

+0

@BOBINJOSEPH आपका स्वागत है :) – keyboardP

+0

@keyboard मुझे पता है कि आपने इस सवाल का जवाब देने के 3 साल बाद किया है, लेकिन किसी भी मौके पर आप अपना जवाब विस्तारित करेंगे और समझाएंगे कि निर्भरता संपत्ति विकल्प कैसे काम करेगा? धन्यवाद। – Thierry

9

तुम भी एक व्यवहार जोड़ सकते हैं:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
. 
. 
. 
<ListBox Margin="10" Height="150" ItemsSource="{Binding Path=MyValue}" > 
<i:Interaction.Behaviors> 
    <bhv:ScrollIntoViewBehavior/> 
</i:Interaction.Behaviors> 
</ListBox> 

और व्यवहार को लागू करें:

using System.Windows.Interactivity; 

public class ScrollIntoViewBehavior : Behavior<ListBox> 
{ 
    protected override void OnAttached() 
    { 
     ListBox listBox = AssociatedObject; 
     ((INotifyCollectionChanged)listBox.Items).CollectionChanged += OnListBox_CollectionChanged; 
    } 

    protected override void OnDetaching() 
    { 
     ListBox listBox = AssociatedObject; 
     ((INotifyCollectionChanged)listBox.Items).CollectionChanged -= OnListBox_CollectionChanged; 
    } 

    private void OnListBox_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     ListBox listBox = AssociatedObject; 
     if (e.Action == NotifyCollectionChangedAction.Add) 
     { 
      // scroll the new item into view 
      listBox.ScrollIntoView(e.NewItems[0]); 
     } 
    } 
}