ItemContainerGenerator.ContainerFromItem() 返回 null?
我有一些奇怪的行为,我似乎无法解决。当我迭代 ListBox.ItemsSource 属性中的项目时,我似乎无法获取容器?我期望看到返回一个 ListBoxItem,但我只得到 null。
有什么想法吗?
这是我正在使用的代码:
this.lstResults.ItemsSource.ForEach(t =>
{
ListBoxItem lbi = this.lstResults.ItemContainerGenerator.ContainerFromItem(t) as ListBoxItem;
if (lbi != null)
{
this.AddToolTip(lbi);
}
});
ItemsSource 当前设置为字典并且包含许多 KVP。
I'm having a bit of weird behavior that I can't seem to work out. When I iterate through the items in my ListBox.ItemsSource property, I can't seem to get the container? I'm expecting to see a ListBoxItem returned, but I only get null.
Any ideas?
Here's the bit of code I'm using:
this.lstResults.ItemsSource.ForEach(t =>
{
ListBoxItem lbi = this.lstResults.ItemContainerGenerator.ContainerFromItem(t) as ListBoxItem;
if (lbi != null)
{
this.AddToolTip(lbi);
}
});
The ItemsSource is currently set to a Dictionary and does contain a number of KVPs.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
我在这个 StackOverflow 问题中发现了更适合我的情况的东西:
在数据网格中获取行
通过将在 UpdateLayout 和 ScrollIntoView 调用中,在调用 ContainerFromItem 或 ContainerFromIndex 之前,您会导致 DataGrid 的该部分被实现,这使得它可以返回 ContainerFromItem/ContainerFromIndex 的值:
如果您不希望如果要更改 DataGrid 中的当前位置,这对您来说可能不是一个好的解决方案,但如果可以的话,它无需关闭虚拟化即可工作。
I found something that worked better for my case in this StackOverflow question:
Get row in datagrid
By putting in UpdateLayout and a ScrollIntoView calls before calling ContainerFromItem or ContainerFromIndex, you cause that part of the DataGrid to be realized which makes it possible for it return a value for ContainerFromItem/ContainerFromIndex:
If you don't want the current location in the DataGrid to change, this probably isn't a good solution for you but if that's OK, it works without having to turn off virtualizing.
终于解决了问题...通过将
VirtualizingStackPanel.IsVirtualizing="False"
添加到我的 XAML 中,现在一切都按预期工作。不利的一面是,我错过了虚拟化的所有性能优势,因此我将加载路由更改为异步,并在加载时在列表框中添加了一个“旋转器”...
Finally sorted out the problem... By adding
VirtualizingStackPanel.IsVirtualizing="False"
into my XAML, everything now works as expected.On the downside, I miss out on all the performance benefitst of the virtualization, so I changed my load routing to async and added a "spinner" into my listbox while it loads...
使用调试器单步执行代码,看看是否实际上没有返回任何内容,或者
as
转换是否错误,从而将其转换为null
(您可以只使用正常转换以获得正确的异常)。经常发生的一个问题是,当
ItemsControl
对大多数项目进行虚拟化时,任何时候都不会存在容器。另外,我不建议直接处理项目容器,而是绑定属性并订阅事件(通过
ItemsControl.ItemContainerStyle
)。Step through the code with the debugger and see if there is actually nothing retured or if the
as
-cast is just wrong and thus turns it tonull
(you could just use a normal cast to get a proper exception).One problem that frequently occurs is that when an
ItemsControl
is virtualizing for most of the items no container will exist at any point in time.Also i would not recommend dealing with the item containers directly but rather binding properties and subscribing to events (via the
ItemsControl.ItemContainerStyle
).使用此订阅:
Use this subscription:
虽然从 XAML 禁用虚拟化是可行的,但我认为最好从使用 ContainerFromItem 的 .cs 文件中禁用它,
这样可以减少 XAML 和代码之间的耦合;因此,您可以避免有人通过接触 XAML 来破坏代码的风险。
Although disabling virtualization from XAML works, I think it's better to disable it from the .cs file which uses
ContainerFromItem
That way, you reduce the coupling between the XAML and the code; so you avoid the risk of someone breaking the code by touching the XAML.
我参加聚会有点晚了,但这里有另一个解决方案,在我的情况下是防失败的,
在尝试了许多建议将
IsExpanded
和IsSelected
添加到底层对象和绑定的解决方案之后以TreeViewItem
风格给他们,虽然这大部分有效在某些情况下它仍然失败......注意:我的目标是编写一个迷你/自定义类似资源管理器的视图,当我单击其中的文件夹时它在
TreeView
上选择右侧窗格,就像在资源管理器中一样。这里使用了多个技巧:
null
到目前为止,它运行得很好,
I'm a bit late for the party but here's another solution that's fail-proof in my case,
After trying many solutions suggesting to add
IsExpanded
andIsSelected
to underlying object and binding to them inTreeViewItem
style, while this mostly works in some case it still fails ...Note: my objective was to write a mini/custom Explorer-like view where when I click a folder in the right pane it gets selected on the
TreeView
, just like in Explorer.Multiple tricks used in here:
null
So far it works very well,
这很可能是与虚拟化相关的问题,因此仅为当前可见的项目生成
ListBoxItem
容器(请参阅https://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingstackpanel(v=vs.110).aspx#Anchor_9)如果您使用的是
ListBox
我建议改用ListView
- 它继承自ListBox
并且支持ScrollIntoView()
方法您可以利用它来控制虚拟化;(上面的示例还利用了
DoEvents()
静态方法,此处有更详细的解释;WPF 如何在处理更多代码之前等待绑定更新发生?)之间还有一些其他细微差别列表框
和ListView
控件(之间有什么区别ListBox 和 ListView) - 这本质上不会影响您的用例。Most probably this is a virtualization-related issue so
ListBoxItem
containers get generated only for currently visible items (see https://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingstackpanel(v=vs.110).aspx#Anchor_9)If you are using
ListBox
I'd suggest switching toListView
instead - it inherits fromListBox
and it supportsScrollIntoView()
method which you can utilize to control virtualization;(the example above also utilizes the
DoEvents()
static method explained in more detail here; WPF how to wait for binding update to occur before processing more code?)There are a few other minor differences between the
ListBox
andListView
controls (What is The difference between ListBox and ListView) - which should not essentially affect your use case.VirtualizingStackPanel.IsVirtualizing="False" 使控制变得模糊。请参阅下面的实现。这有助于我避免同样的问题。
始终设置您的应用程序 VirtualizingStackPanel.IsVirtualizing="True"。
有关详细信息,请参阅链接
VirtualizingStackPanel.IsVirtualizing="False" Makes the control fuzzy . See the below implementation. Which helps me to avoid the same issue.
Set your application VirtualizingStackPanel.IsVirtualizing="True" always.
See the link for detailed info
对于仍然遇到此问题的任何人,我可以通过忽略第一个选择更改事件并使用线程基本上重复调用来解决此问题。这就是我最终所做的:
编辑 10/29/2014:您实际上甚至不需要线程调度程序代码。您可以将所需的任何内容设置为 null 以触发第一个选择更改事件,然后从事件中返回,以便将来的事件按预期工作。
For anyone still having issues with this, I was able to work around this issue by ignoring the first selection changed event and using a thread to basically repeat the call. Here's what I ended up doing:
EDIT 10/29/2014: You actually don't even need the thread dispatcher code. You can set whatever you need to null to trigger the first selection changed event and then return out of the event so that future events work as expected.