ItemContainerGenerator.containerfromitem은 그룹화 된 목록과 어떻게 작동합니까?
문제
최근까지 평평한 항목 목록을 표시하는 ListBox가 있습니다. MyList.ItemContainergenerator.conainerFromItem (Thing)을 사용하여 목록에서 ListBoxItem 호스팅 "Thing"을 검색 할 수있었습니다.
이번 주에는 항목에 묶인 CollectionViewSource에 그룹화가 활성화 된 CollectionViewSource에서 Listbox를 약간 수정했습니다. 이제 Listbox 내의 항목은 Nice 헤더 아래에 그룹화됩니다.
그러나이 작업을 수행 한 이후 itemcontainergenerator.containerfromitem은 작동이 중지되었습니다. ListBox에있는 항목에 대해서도 NULL을 반환합니다. Heck -Containerfromindex (0)는 ListBox에 많은 항목이 채워져 있어도 NULL을 반환합니다!
그룹화 된 항목을 표시하는 ListBox에서 ListBoxItem을 검색하려면 어떻게해야합니까?
편집 : 다음은 다듬은 예제의 XAML과 코드-비만입니다. 컨테이너 프롬 린덱스 (1)가 목록에 4 개의 항목이 있더라도 Null을 반환하고 있기 때문에 NullReferenceException이 발생합니다.
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();
}
}
해결책
너 가지다 듣고 반응합니다 ItemsGenerator.StatusChanged
컨테이너 프롬 리멘트로 액세스하기 전에 항목 컨테이너가 생성 될 때까지 이벤트 및 기다립니다.
더 검색하면서 찾았습니다 MSDN 포럼의 스레드 같은 문제가있는 사람으로부터. 이것은 그룹 스타일 세트가있을 때 WPF의 버그 인 것 같습니다. 해결책은 렌더링 프로세스 후에 ItemGenerator의 액세스를 펀트하는 것입니다. 아래는 귀하의 질문에 대한 코드입니다. 나는 이것을 시도했고 그것은 작동한다 :
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();
}
다른 팁
위의 코드가 효과가 없다면 시도해보십시오.
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]);
}
}
XAML의 사용
<ListBox IsSynchronizedWithCurrentItem="True" extenders:ListBoxExtenders.AutoScrollToCurrentItem="True" ..../>
ListboxItem 유형에 도달 할 때까지 'Thing'에서 VisualTree를 구문 분석 해보세요.