2010-02-18 26 views
23

Dikey kaydırma özelliği olan büyük bir ListBox'ım var, MVVM'm Yeni ve Düzenleme ICommand'larına sahip. Koleksiyonun sonuna yeni bir öğe ekliyorum ancak MVVM-AddCommandımı çağırdığımda kaydırma çubuğunun da End konumuna otomatik olarak konumlanmasını istiyorum. Ayrıca bir öğeyi düzenlenebilir (belirli bir satır öğesi ile EditCommand'ı çağırarak) uygulamasının diğer bir bölümünden veriyorum, böylece ListBoxItem'i DataTrigger kullanarak düzenleme moduna geçiyorum, ancak bu satırı (ListBoxItem) ne zaman getireceğim? kaydırma konumunu ayarlayarak görüntüleyin.Bir MVVM WPF uygulamasında bir ListBox'un kaydırma konumunu denetleme

Görünüm tarafında yapıyorum, listBox.ScrollInToView (lstBoxItem) çağırabilir. Ancak, bu yaygın Kaydırma sorununu MVVM perspektifinden çözmenin en iyi yolu nedir?

+0

ListBox SelectionChanged olayını ve ScrollIntoView yöntemini kullanmak MVVM'yi bozmaz. Bu tamamen görünüm işlevidir ve görünüm tarafından ele alınmalıdır. Görünüm modeli, ListBox'un varlığını bile bilmemeli veya bir nesnenin görünümde nerede bulunduğu konusunda herhangi bir kontrole sahip olmamalıdır. Görünüm modelinin yapması gereken tek şey, ListBox'un görünüm modeline bağlı özelliği olması gereken SelectedItem'i değiştirmektir. – Tim

cevap

27

Genellikle ListBox'a IsSynchronizedWithCurrentItem="True"'u ayarlıyorum. Sonra bir SelectionChanged işleyici ekleyin ve her zaman Seçilmiş öğeleri getirmek, kodla böyle:

private void BringSelectionIntoView(object sender, SelectionChangedEventArgs e) 
    { 
     Selector selector = sender as Selector; 
     if (selector is ListBox) 
     { 
      (selector as ListBox).ScrollIntoView(selector.SelectedItem); 
     } 
    } 

benim VM itibaren varsayılan toplama görünüm elde edebilirsiniz ve madde olma sağlamak için MoveCurrent*() yöntemlerden birini kullanın düzenlenmiş mevcut öğedir.

CollectionViewSource.GetDefaultView(_myCollection).MoveCurrentTo(thisItem); 

NOT: MVVM bu kullanma sanallaştırmayı

+0

Evet benim ListView sanallaştırıldı, yanıt Dr. için teşekkürler –

7

karşılamak için ListBox.ScrollIntoView() kullanmak Düzenlendi kolayca şöyle ekli davranış yoluyla gerçekleştirilebilir:

using System.Windows.Controls; 
using System.Windows.Interactivity; 

namespace Jarloo.Sojurn.Behaviors 
{ 
    public sealed class ScrollIntoViewBehavior : Behavior<ListBox> 
    { 
     protected override void OnAttached() 
     { 
      base.OnAttached(); 
      AssociatedObject.SelectionChanged += ScrollIntoView; 
     } 

     protected override void OnDetaching() 
     { 
      AssociatedObject.SelectionChanged -= ScrollIntoView; 
      base.OnDetaching(); 
     } 

     private void ScrollIntoView(object o, SelectionChangedEventArgs e) 
     { 
      ListBox b = (ListBox) o; 
      if (b == null) 
       return; 
      if (b.SelectedItem == null) 
       return; 

      ListBoxItem item = (ListBoxItem) ((ListBox) o).ItemContainerGenerator.ContainerFromItem(((ListBox) o).SelectedItem); 
      if (item != null) item.BringIntoView(); 
     } 
    } 
} 

Ardından Görünüm reklama bu referans adresinde üst:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 

Ve bunu yapın:

<ListBox ItemsSource="{Binding MyData}" SelectedItem="{Binding MySelectedItem}"> 
     <i:Interaction.Behaviors> 
      <behaviors:ScrollIntoViewBehavior /> 
     </i:Interaction.Behaviors> 
</ListBox> 

SelectedItem değiştiğinde, davranış sizin için BringIntoView() çağrısını yapacaktır. Yukarıdaki kodu sizin için işe yaramazsa

1

, XAML

<ListBox IsSynchronizedWithCurrentItem="True" extenders:ListBoxExtenders.AutoScrollToCurrentItem="True" ..../> 
3

bir deneyin bu

public class ListBoxExtenders : DependencyObject 
{ 
    public static readonly DependencyProperty AutoScrollToCurrentItemProperty = DependencyProperty.RegisterAttached("AutoScrollToCurrentItem", typeof(bool), typeof(ListBoxExtenders), new UIPropertyMetadata(default(bool), OnAutoScrollToCurrentItemChanged)); 

    public static bool GetAutoScrollToCurrentItem(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(AutoScrollToSelectedItemProperty); 
    } 

    public static void SetAutoScrollToCurrentItem(DependencyObject obj, bool value) 
    { 
     obj.SetValue(AutoScrollToSelectedItemProperty, value); 
    } 

    public static void OnAutoScrollToCurrentItemChanged(DependencyObject s, DependencyPropertyChangedEventArgs e) 
    { 
     var listBox = s as ListBox; 
     if (listBox != null) 
     { 
      var listBoxItems = listBox.Items; 
      if (listBoxItems != null) 
      { 
       var newValue = (bool)e.NewValue; 

       var autoScrollToCurrentItemWorker = new EventHandler((s1, e2) => OnAutoScrollToCurrentItem(listBox, listBox.Items.CurrentPosition)); 

       if (newValue) 
        listBoxItems.CurrentChanged += autoScrollToCurrentItemWorker; 
       else 
        listBoxItems.CurrentChanged -= autoScrollToCurrentItemWorker; 
      } 
     } 
    } 

    public static void OnAutoScrollToCurrentItem(ListBox listBox, int index) 
    { 
     if (listBox != null && listBox.Items != null && listBox.Items.Count > index && index >= 0) 
      listBox.ScrollIntoView(listBox.Items[index]); 
    } 

} 

Kullanımını vermek budur kabul cevabın ekli özelliği formu:

using System.Windows; 
using System.Windows.Controls; 

namespace CommonBehaviors 
{ 
    public static class ScrollCurrentItemIntoViewBehavior 
    { 
     public static readonly DependencyProperty AutoScrollToCurrentItemProperty = 
      DependencyProperty.RegisterAttached("AutoScrollToCurrentItem", 
       typeof(bool), typeof(ScrollCurrentItemIntoViewBehavior), 
       new UIPropertyMetadata(default(bool), OnAutoScrollToCurrentItemChanged)); 

     public static bool GetAutoScrollToCurrentItem(DependencyObject obj) 
     { 
      return (bool)obj.GetValue(AutoScrollToCurrentItemProperty); 
     } 

     public static void OnAutoScrollToCurrentItemChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
     { 
      var listBox = obj as ListBox; 
      if (listBox == null) return; 

      var newValue = (bool)e.NewValue; 
      if (newValue) 
       listBox.SelectionChanged += listBoxSelectionChanged; 
      else 
       listBox.SelectionChanged -= listBoxSelectionChanged; 
     } 

     static void listBoxSelectionChanged(object sender, SelectionChangedEventArgs e) 
     { 
      var listBox = sender as ListBox; 
      if (listBox == null || listBox.SelectedItem == null || listBox.Items == null) return; 

      listBox.Items.MoveCurrentTo(listBox.SelectedItem); 
      listBox.ScrollIntoView(listBox.SelectedItem); 
     } 

     public static void SetAutoScrollToCurrentItem(DependencyObject obj, bool value) 
     { 
      obj.SetValue(AutoScrollToCurrentItemProperty, value); 
     } 
    } 
} 

Kullanım:

<ListBox ItemsSource="{Binding}" 
      IsSynchronizedWithCurrentItem="True" 
      behaviors:ScrollCurrentItemIntoViewBehavior.AutoScrollToCurrentItem="True">