2008-10-03 16 views
26

Yakın zamana kadar düz bir öğe listesi görüntüleyen bir ListBox'ım var. ListlistItem "şey" barındıran almak için myList.ItemContainerGenerator.ConainerFromItem (thing) kullanabildi.ItemContainerGenerator.ContainerFromItem gruplandırılmış bir liste ile nasıl çalışır?

Bu hafta, ListBox'ı, öğelerini için gruplandırmasını etkinleştirdiği CollectionViewSource öğesinin etkin olduğundan biraz değiştirdim. Şimdi, ListBox içindeki öğeler güzel başlıkların altında gruplandırılmıştır.

Ancak, bunu yaptığınızda, ItemContainerGenerator.ContainerFromItem çalışmayı durdurdu - ListBox'ta olduğunu bildiğim öğeler için bile null değerini döndürür. Heck - ListBox birçok öğe ile doldurulmuş olsa bile ContainerFromIndex (0) null döndürüyor!

Gruplanmış öğeleri görüntüleyen bir ListBox Listesinden bir ListBoxItem'i nasıl alabilirim?

Düzenleme: Kesilmiş bir örnek için XAML ve kod arkası işte burada. Listede dört öğe olsa bile, ContainerFromIndex (1) null döndürdüğü için bu bir NullReferenceException yükseltir.

XAML:

<Window x:Class="WpfApplication1.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" 
    Title="Window1"> 

    <Window.Resources> 
     <XmlDataProvider x:Key="myTasks" XPath="Tasks/Task"> 
      <x:XData> 
       <Tasks xmlns=""> 
        <Task Name="Groceries" Type="Home"/> 
        <Task Name="Cleaning" Type="Home"/> 
        <Task Name="Coding" Type="Work"/> 
        <Task Name="Meetings" Type="Work"/> 
       </Tasks> 
      </x:XData> 
     </XmlDataProvider> 

     <CollectionViewSource x:Key="mySortedTasks" Source="{StaticResource myTasks}"> 
      <CollectionViewSource.SortDescriptions> 
       <scm:SortDescription PropertyName="@Type" /> 
       <scm:SortDescription PropertyName="@Name" /> 
      </CollectionViewSource.SortDescriptions> 

      <CollectionViewSource.GroupDescriptions> 
       <PropertyGroupDescription PropertyName="@Type" /> 
      </CollectionViewSource.GroupDescriptions> 
     </CollectionViewSource> 
    </Window.Resources> 

    <ListBox 
     x:Name="listBox1" 
     ItemsSource="{Binding Source={StaticResource mySortedTasks}}" 
     DisplayMemberPath="@Name" 
     > 
     <ListBox.GroupStyle> 
      <GroupStyle> 
       <GroupStyle.HeaderTemplate> 
        <DataTemplate> 
         <TextBlock Text="{Binding Name}"/> 
        </DataTemplate> 
       </GroupStyle.HeaderTemplate> 
      </GroupStyle> 
     </ListBox.GroupStyle> 
    </ListBox> 
</Window> 

CS:

public Window1() 
{ 
    InitializeComponent(); 
    listBox1.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged; 
} 

void ItemContainerGenerator_StatusChanged(object sender, EventArgs e) 
{ 
    if (listBox1.ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated) 
    { 
     listBox1.ItemContainerGenerator.StatusChanged -= ItemContainerGenerator_StatusChanged; 

     var i = listBox1.ItemContainerGenerator.ContainerFromIndex(1) as ListBoxItem; 

     // select and keyboard-focus the second item 
     i.IsSelected = true; 
     i.Focus(); 
    } 
} 
+0

Ne yapıyorsun

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 konteyner ile? Önceki kodun gerçekte ne işe yaradığını görmek mümkün mü? Konteyneri almanın birkaç yolu var ... sadece onunla ne yapmak istediğinize bağlı? – rudigrobler

cevap

35

bir ListBoxItem tip ulaşana kadar 'şey' dan yukarı VisualTree ayrıştırma deneyin ItemsGenerator.StatusChanged Olayına gidin ve ContainerConfiglement ile onlara erişebilmeniz için önce ItemContainers oluşturulmasını bekleyin. ayrıca aranıyor


, ben aynı sorunu olan birinden a thread in the MSDN forum buldum. Bu bir GroupStyle seti olduğunda, WPF'de bir hata gibi görünüyor. Çözüm, render işleminden sonra ItemGenerator'ın erişimini sağlamaktır. Aşağıda sorunuzun kodu var. Bunu denedim, ve çalışır: Yukarıdaki kodu sizin için işe yaramazsa

void ItemContainerGenerator_StatusChanged(object sender, EventArgs e) 
    { 
     if (listBox1.ItemContainerGenerator.Status 
      == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated) 
     { 
      listBox1.ItemContainerGenerator.StatusChanged 
       -= ItemContainerGenerator_StatusChanged; 
      Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Input, 
       new Action(DelayedAction)); 
     } 
    } 

    void DelayedAction() 
    { 
     var i = listBox1.ItemContainerGenerator.ContainerFromIndex(1) as ListBoxItem; 

     // select and keyboard-focus the second item 
     i.IsSelected = true; 
     i.Focus(); 
    } 
+0

Evet, bunu yapıyorum. Soruyu önümüzdeki hafta başlarında bazı kodlarla güncelleyeceğim. –

+0

Sadece bunu kendim denedim.Bu hafta sonu dertte olduğum bir şey için bana yardımcı oldu. –

+0

Harika - teşekkürler David. Bunu henüz test etme şansım olmadı ama bunu şimdilik "cevap" olarak kabul ediyorum. –

0

Eğer sen dinlemek ve tepki

+0

Jobi - bu durumda "şey" görsel bir unsur değildir - bu bir iş nesnesinin bir örneğidir. ListBox'un ItemsSource öğesinin bağlı olduğu bir IList parçası. Bu senaryoda tanımladığınız şeyi yapabilir miyim? –

+0

Evet seni aldım. açıklama için teşekkürler. Arkanızdaki kodun hangi bölümünden bunu yapmaya çalışıyorsunuz? herhangi bir DataTemplate tıklayın veya diğer bazı olay işleyicilerinde? –

+0

Sayfa (Gezinme stili bir uygulama) yüklendiğinde, klavye odağını belirli bir öğeye ayarlamak istiyorum. Yani Yüklü olay işleyicisinde. –

0

, XAML bir deneyin bu

<ListBox IsSynchronizedWithCurrentItem="True" extenders:ListBoxExtenders.AutoScrollToCurrentItem="True" ..../> 
İlgili konular