wpf ItemContainerGenerator.ContainerFromItem() 在 VirtualizingStackPanel.IsVirtualizing="False" 时返回 null
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16184172/
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
ItemContainerGenerator.ContainerFromItem() returns null while VirtualizingStackPanel.IsVirtualizing="False"
提问by Berker Soyluoglu
I'm facing a similar problem with this questionhowever VirtualizingStackPanel.IsVirtualizing="False"didn't solve my problem. Is there anyone facing the same issue?
我在这个问题上遇到了类似的问题,但VirtualizingStackPanel.IsVirtualizing="False"没有解决我的问题。有没有人面临同样的问题?
The thing is I have a custom combobox,
问题是我有一个自定义组合框,
<Style TargetType="{x:Type MultiSelectionComboBox}" >
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"
VerticalAlignment="Center"
HorizontalAlignment="Center"
VirtualizingStackPanel.IsVirtualizing="False"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal" x:Name="ItemStack" VirtualizingStackPanel.IsVirtualizing="False">
<CheckBox x:Name="CheckBoxItem"
Command="{Binding SelectItem, RelativeSource={RelativeSource AncestorType={x:Type MultiSelectionComboBox}}}"
CommandParameter="{Binding Key}"
>
</CheckBox>
<TextBlock Text="{Binding DisplayText}"></TextBlock>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid x:Name="Placement" SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border BorderThickness="1" BorderBrush="Black">
<TextBox IsReadOnly="True" Grid.Column="0"
Text="{Binding Text, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type MultiSelectionComboBox}}}">
</TextBox>
</Border>
<Popup x:Name="PART_Popup"
Grid.Column="0"
Focusable="False"
Grid.ColumnSpan="2"
IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
Placement="Bottom"
VerticalOffset="-1"
PlacementTarget="{Binding ElementName=LayoutRoot}">
<Popup.Resources>
<Style TargetType="{x:Type ScrollBar}" BasedOn="{StaticResource {x:Type ScrollBar}}">
<Style.Triggers>
<Trigger Property="Orientation" Value="Vertical">
<Setter Property="BorderThickness" Value="0"/>
</Trigger>
</Style.Triggers>
</Style>
</Popup.Resources>
<ScrollViewer x:Name="DropDownScrollViewer"
Background="{StaticResource Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
MinWidth="{Binding ActualWidth, ElementName=LayoutRoot}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<ItemsPresenter KeyboardNavigation.DirectionalNavigation="Contained"/>
</ScrollViewer>
</Popup>
<ToggleButton IsEnabled="{Binding IsEnabled, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type MultiSelectionComboBox}}}" Grid.Column="1" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ComboBoxToggleButton}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
and yet I can't get a reference to the checkbox inside via,
但是我无法通过以下方式获得对复选框的引用,
this.ItemContainerGenerator.ContainerFromItem(this.Items[0]) as ComboBoxItem;
Is there any suggestions?
有什么建议吗?
What i actually want to achieve is,
我真正想要实现的是,
i want to change checkboxes ischecked property which is depending on an other object which can change on runtime. I can't do it with using bindings due to the current state of the overall project which i can not change at this point. So basically once the new MultiSelectionComboBox is created i want to do something like this,
我想更改复选框 ischecked 属性,该属性取决于可以在运行时更改的其他对象。由于整个项目的当前状态,我无法使用绑定来做到这一点,此时我无法更改。所以基本上一旦创建了新的 MultiSelectionComboBox,我就想做这样的事情,
foreach (object item in this.Items)
{
ComboBoxItem comboBoxItem = this.ItemContainerGenerator.ContainerFromItem(item) as ComboBoxItem;
if (comboBoxItem == null)
continue;
FrameworkElement element = comboBoxItem.ContentTemplate.LoadContent() as FrameworkElement;
CheckBox checkBox = element.FindName("CheckBoxItem") as CheckBox;
checkBox.IsChecked = this.SelectedItem.Contains(item);
}
回答by R.Titov
try execute UpdateLayout()before this.ItemContainerGenerator.ContainerFromItem(item)
尝试执行UpdateLayout()之前this.ItemContainerGenerator.ContainerFromItem(item)
回答by user1545761
Use ItemContainerGenerator.StatusChanged event from you ComboBox like this:
像这样使用 ComboBox 中的 ItemContainerGenerator.StatusChanged 事件:
myComboBox.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
void ItemContainerGenerator_StatusChanged(object sender, System.EventArgs e)
{
if (myComboBox.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
foreach (var item in myComboBox.Items)
{
var container = (ComboBoxItem)LanguageComboBox.ItemContainerGenerator.ContainerFromItem(item);
}
}
}
回答by Michel P.
As my logic was in the SelectionChanged event, i wondered why the ItemContainerGenerator.ContainerFromItemmethod always returned null even if the Listbox.SelectedItemwas not null and even more strange, Virtualisation was turned off! Looking at the ItemContainerGenerator.Statusi saw that it was Primitives.GeneratorStatus.NotStartedthen i added a simple test on ItemContainerGenerator.Status == Primitives.GeneratorStatus.ContainersGeneratedand finally solved it that way and no need to subsribe to the Status_Changed event.
由于我的逻辑是在 SelectionChanged 事件中,我想知道为什么ItemContainerGenerator.ContainerFromItem即使Listbox.SelectedItem不为 null该方法总是返回 null更奇怪的是,虚拟化被关闭了!看着ItemContainerGenerator.Status我看到它Primitives.GeneratorStatus.NotStarted然后我添加了一个简单的测试ItemContainerGenerator.Status == Primitives.GeneratorStatus.ContainersGenerated并最终以这种方式解决了它并且不需要订阅 Status_Changed 事件。

