2011-01-25 26 views
17

Şu anda ItemsSource koleksiyonu, IEnumerable türündeki viewmodel öğesinde bir özelliğe bağlı bir ListBox'a sahibim. Bu preoprty'nin referansı değiştiğinde, ListBox beklendiği gibi güncellenir, ancak büyük bir öğe koleksiyonum varsa ve ListBox'ın altına kaydırırsam ve sonra referansı 1 öğe içeren başka bir koleksiyona değiştirirsem, bir sorunum olur. ListBox görünümü boş ve kaydırma çubuğu görüntülenmiyor. 1 öğe görünene kadar liste kutusunu fare tekerleği ile yukarı kaydırmam gerekiyor.WPF - ItemsSource değiştiğinde ListBox kaydırma konumu sıfırlanıyor

Öyleyse, sanırım peşinde olduğum şey, ItemsSource özelliği her değiştiğinde ListBox'ın kaydırma konumunu en üst düzeye sıfırlamanın bir yoludur, böylece her ne kadar koleksiyon ne kadar büyük veya küçük olursa olsun her zaman görüntülenir.

+0

Sorunuzu doğru anladınız mı yoksa başka bir şey mi arıyorsunuz? –

+0

@Meleak Teşekkürler! Bu yaklaşım yararlı olacaktır. Ben aslında benim liste kutusu benim http://blogs.msdn.com/b/dancre/archive/2006/02/16/implementing-a-virtualizingpanel-part adresinden aldığım bir VirtualizingTilePanel sorununu izledim -4-goods.aspx. Sorun, dize aşağı kaydırarak örnek yüklemede çoğaltılabilir ve sonra da ilişkili koleksiyonu tek bir öğe içeren bir taneyle değiştirebilir. Fare tekerleği ile yukarı gidinceye kadar görünüm boş kalır. – devdigital

+0

VirtualizingTilePanel için http://social.msdn.microsoft.com/Forums/en/wpf/thread/05c5868b-7c91-4726-81fb-9af634c74d4a adresinde bir yanıt buldu, ancak sanallaştırıcı paketlemeye ikili dağıtımdan geçtim - http://www.binarymission.co.uk/binaryvirtwrappanelsl3.htm – devdigital

cevap

20

Ben senin sorunu yeniden veremeyiz (benim için ListBox yeni koleksiyonunda son öğeye kaydırılan ItemsSource değiştirirken). Her neyse, ListBox'u en iyi şekilde kaydırmak için ItemsSource her değiştiğinde arkasında bir kod kullanabilirsiniz. İlk ItemsSourceProperty değişikliklere dinlemek ve onun ürün

oluşturulduktan sonra sonra üstüne ListBox kaydırmak Güncelleme

yerine bu arkasındaki kodu önlemek için yaptığı ekli bir davranış yaptı.

Basit bir çözümdür: Bu

<ListBox ... 
     behaviors:ScrollToTopBehavior.ScrollToTop="True"/> 

ScrollToTopBehavior

public static class ScrollToTopBehavior 
{ 
    public static readonly DependencyProperty ScrollToTopProperty = 
     DependencyProperty.RegisterAttached 
     (
      "ScrollToTop", 
      typeof(bool), 
      typeof(ScrollToTopBehavior), 
      new UIPropertyMetadata(false, OnScrollToTopPropertyChanged) 
     ); 
    public static bool GetScrollToTop(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(ScrollToTopProperty); 
    } 
    public static void SetScrollToTop(DependencyObject obj, bool value) 
    { 
     obj.SetValue(ScrollToTopProperty, value); 
    } 
    private static void OnScrollToTopPropertyChanged(DependencyObject dpo, 
                DependencyPropertyChangedEventArgs e) 
    { 
     ItemsControl itemsControl = dpo as ItemsControl; 
     if (itemsControl != null) 
     { 
      DependencyPropertyDescriptor dependencyPropertyDescriptor = 
        DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof(ItemsControl)); 
      if (dependencyPropertyDescriptor != null) 
      { 
       if ((bool)e.NewValue == true) 
       { 
        dependencyPropertyDescriptor.AddValueChanged(itemsControl, ItemsSourceChanged); 
       } 
       else 
       { 
        dependencyPropertyDescriptor.RemoveValueChanged(itemsControl, ItemsSourceChanged); 
       } 
      } 
     } 
    } 
    static void ItemsSourceChanged(object sender, EventArgs e) 
    { 
     ItemsControl itemsControl = sender as ItemsControl; 
     EventHandler eventHandler = null; 
     eventHandler = new EventHandler(delegate 
     { 
      if (itemsControl.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) 
      { 
       ScrollViewer scrollViewer = GetVisualChild<ScrollViewer>(itemsControl) as ScrollViewer; 
       scrollViewer.ScrollToTop(); 
       itemsControl.ItemContainerGenerator.StatusChanged -= eventHandler; 
      } 
     }); 
     itemsControl.ItemContainerGenerator.StatusChanged += eventHandler; 
    } 
} 

Ve GetVisualChild bir uygulamaya

private T GetVisualChild<T>(DependencyObject parent) where T : Visual 
{ 
    T child = default(T); 
    int numVisuals = VisualTreeHelper.GetChildrenCount(parent); 
    for (int i = 0; i < numVisuals; i++) 
    { 
     Visual v = (Visual)VisualTreeHelper.GetChild(parent, i); 
     child = v as T; 
     if (child == null) 
     { 
      child = GetVisualChild<T>(v); 
     } 
     if (child != null) 
     { 
      break; 
     } 
    } 
    return child; 
} 
+0

bu gerçekten çok kullanışlıdır :) –

1

bu deneyin:

if (listBox.Items.Count > 0) { 
    listBox.ScrollIntoView(listBox.Items[0]); 
} 
7

Geç cevap gibi kullanılabilir TargetUpdated olay için bir olay işleyicisi ekleyin ve bağlayıcı ItemsSource üzerinde NotifyOnTargetUpdated=True ayarlamak için:

<ListBox x:Name="listBox" 
     ItemsSource="{Binding MySource, NotifyOnTargetUpdated=True}" 
     TargetUpdated="ListBox_TargetUpdated"/> 

ve olay işleyicisinde, üst öğeye ilerleyin:

private void ListBox_TargetUpdated(object sender, DataTransferEventArgs e) 
{ 
    if (listBox.Items.Count > 0) 
    { 
     listBox.ScrollIntoView(listBox.Items[0]); 
    } 
} 
0

işe Fredrik Hedblad cevabı Geliştirilmiş ObservableCollection ile: Eğer kontrol formatladığınızda

public static class ItemsControlAttachedProperties 
{ 
    #region ScrollToTopOnItemsSourceChange Property 

    public static readonly DependencyProperty ScrollToTopOnItemsSourceChangeProperty = 
     DependencyProperty.RegisterAttached(
      "ScrollToTopOnItemsSourceChange", 
      typeof(bool), 
      typeof(ItemsControlAttachedProperties), 
      new UIPropertyMetadata(false, OnScrollToTopOnItemsSourceChangePropertyChanged)); 

    public static bool GetScrollToTopOnItemsSourceChange(DependencyObject obj) 
    { 
     return (bool) obj.GetValue(ScrollToTopOnItemsSourceChangeProperty); 
    } 

    public static void SetScrollToTopOnItemsSourceChange(DependencyObject obj, bool value) 
    { 
     obj.SetValue(ScrollToTopOnItemsSourceChangeProperty, value); 
    } 

    static void OnScrollToTopOnItemsSourceChangePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
    { 
     var itemsControl = obj as ItemsControl; 
     if (itemsControl == null) 
     { 
      throw new Exception("ScrollToTopOnItemsSourceChange Property must be attached to an ItemsControl based control."); 
     } 

     DependencyPropertyDescriptor descriptor = 
      DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof(ItemsControl)); 
     if (descriptor != null) 
     { 
      if ((bool) e.NewValue) 
      { 
       descriptor.AddValueChanged(itemsControl, ItemsSourceChanged); 
      } 
      else 
      { 
       descriptor.RemoveValueChanged(itemsControl, ItemsSourceChanged); 
      } 
     } 
    } 

    static void ItemsSourceChanged(object sender, EventArgs e) 
    { 
     var itemsControl = sender as ItemsControl; 
     DoScrollToTop(itemsControl); 

     var collection = itemsControl.ItemsSource as INotifyCollectionChanged; 
     if (collection != null) 
     { 
      collection.CollectionChanged += (o, args) => DoScrollToTop(itemsControl); 
     } 
    } 

    static void DoScrollToTop(ItemsControl itemsControl) 
    { 
     EventHandler eventHandler = null; 
     eventHandler = 
      delegate 
      { 
       if (itemsControl.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) 
       { 
        var scrollViewer = GetVisualChild<ScrollViewer>(itemsControl); 
        scrollViewer.ScrollToTop(); 
        itemsControl.ItemContainerGenerator.StatusChanged -= eventHandler; 
       } 
      }; 
     itemsControl.ItemContainerGenerator.StatusChanged += eventHandler; 
    } 

    static T GetVisualChild<T>(DependencyObject parent) where T : Visual 
    { 
     T child = default(T); 
     int numVisuals = VisualTreeHelper.GetChildrenCount(parent); 
     for (var i = 0; i < numVisuals; i++) 
     { 
      var v = (Visual) VisualTreeHelper.GetChild(parent, i); 
      child = v as T ?? GetVisualChild<T>(v); 
      if (child != null) 
      { 
       break; 
      } 
     } 
     return child; 
    } 

    #endregion 
} 
0

, sen t vardır seçim seçenekleri olarak bir hücre aralığı seçmek liste kutusunda listelenen tavuk. Ayrıca, listedeki seçimin konumuna bağlı olarak bir sayının görüntüleneceği seçili seçimlere bağlantı olarak bir hücre de seçebilirsiniz. Listede ilk 1, ikinci vb için 2Kod oldukça basit: -

Range ("A1") Eğer bağladığınız hücreye

Seçim = 1

Değiştir ("A1") seçip pozisyonunda 1 ila değiştirmek Seçtiğiniz liste.

Bir bağlantı olan hücre referansı her iki şekilde de çalışır; seçiminizi değiştirirseniz, hücre içindeki sayı değişir ve hücrede sayıyı değiştirirseniz, vurgulanan seçim değişir.