.net ItemContainerGenerator.ContainerFromItem 如何处理分组列表?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/165424/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does ItemContainerGenerator.ContainerFromItem work with a grouped list?
提问by Matt Hamilton
I have a ListBox which until recently was displaying a flat list of items. I was able to use myList.ItemContainerGenerator.ConainerFromItem(thing) to retrieve the ListBoxItem hosting "thing" in the list.
我有一个 ListBox,直到最近它才显示一个平面的项目列表。我能够使用 myList.ItemContainerGenerator.ConainerFromItem(thing) 来检索列表中托管“事物”的 ListBoxItem。
This week I've modified the ListBox slightly in that the CollectionViewSource that it binds to for its items has grouping enabled. Now the items within the ListBox are grouped underneath nice headers.
本周我稍微修改了 ListBox,因为它为其项目绑定到的 CollectionViewSource 启用了分组。现在 ListBox 中的项目分组在漂亮的标题下。
However, since doing this, ItemContainerGenerator.ContainerFromItem has stopped working - it returns null even for items I know are in the ListBox. Heck - ContainerFromIndex(0) is returning null even when the ListBox is populated with many items!
但是,由于这样做,ItemContainerGenerator.ContainerFromItem 已停止工作 - 即使对于我知道在 ListBox 中的项目,它也返回 null。见鬼 - 即使 ListBox 填充了许多项目,ContainerFromIndex(0) 也返回 null!
How do I retrieve a ListBoxItem from a ListBox that's displaying grouped items?
如何从显示分组项目的 ListBox 中检索 ListBoxItem?
Edit: Here's the XAML and code-behind for a trimmed-down example. This raises a NullReferenceException because ContainerFromIndex(1) is returning null even though there are four items in the list.
编辑:这是一个精简示例的 XAML 和代码隐藏。这会引发 NullReferenceException,因为即使列表中有四个项目,ContainerFromIndex(1) 也会返回 null。
XAML:
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:
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();
}
}
回答by David Schmitt
You haveto listen and react to the ItemsGenerator.StatusChangedEvent and wait until the ItemContainers are generated before you can access them with ContainerFromElement.
您必须监听ItemsGenerator.StatusChanged事件并对事件做出反应,并等待 ItemContainers 生成,然后才能使用 ContainerFromElement 访问它们。
Searching further, I've found a thread in the MSDN forumfrom someone who has the same problem. This seems to be a bug in WPF, when one has a GroupStyle set. The solution is to punt the access of the ItemGenerator after the rendering process. Below is the code for your question. I tried this, and it works:
进一步搜索,我在 MSDN 论坛中找到了一个来自有同样问题的人的帖子。当设置了 GroupStyle 时,这似乎是 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();
}
回答by c_wiz_kid
If the above code doesn't work for you, give this a try
如果上面的代码不适合你,试试这个
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]);
}
}
Usage in XAML
XAML 中的用法
<ListBox IsSynchronizedWithCurrentItem="True" extenders:ListBoxExtenders.AutoScrollToCurrentItem="True" ..../>
回答by Jobi Joy
Try parsing the VisualTree up from the 'thing' until you reach a ListBoxItem type
尝试从“事物”向上解析 VisualTree,直到到达 ListBoxItem 类型

