来自 ItemsControl returns 的 ContentPresenter 空
ContentPresenter from ItemsControl returns null
我想从 ItemsControl
中获取所有 UI 项。
由此post
How do I access the children of an ItemsControl?
我复制了一个答案,目前有效。
但是,如果我 DIRECTLY 在设置 ItemsSource
后执行 for
循环中的代码(如底部示例),contentpresenter
是 null
,我无法使用它。
如果我 运行 for
-loop 相当长一段时间后(也许当我按下按钮时),一切正常。
如何在设置 ItemsSource
后直接访问 ItemsControl
、 的所有子项?
itemscontrol.ItemsSource = items; // items is a list
itemscontrol.ApplyTemplate(); // might refresh the itemscontrol
for (int i = 0; i < itemscontrol.Items.Count; i++)
{
// ↓ this is null
ContentPresenter contentpresenter = (ContentPresenter)itemscontrol.ItemContainerGenerator.ContainerFromItem(itemscontrol.Items[i]);
// ↑ this is null
contentpresenter.ApplyTemplate();
StackPanel stackPanel = (StackPanel)contentpresenter.ContentTemplate.FindName("selectedStackpanel", contentpresenter);
// do some stuff with the stackpanel
}
更好的解决方案是将相关属性添加到项目模型中,例如一个 IsUserSelected
属性。然后创建一个 Style
,您将其分配给 ItemsControl.ItemContainerStyle
。在此 Style
中,您定义了一个在 IsUserSelected
.
上触发的触发器
就是这样。不要处理生成器并检查是否生成了每个项目。让框架为您完成这项工作。
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding IsUserSelected}"
Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>`enter code here`
</ListBox>
由于您的代码隐藏文件中已有 属性 HighlightId
,因此您可以使用 IMultiValueConverter
和 MultiBinding
来定义基于以下颜色的颜色值:
MainWindow.xaml.cs
partial class MainWindow
{
public static readonly DependencyProperty HighlightIdProperty = DependencyProperty.Register(
"HighlightId",
typeof(int),
typeof(MainWindow),
new PropertyMetadata(default(int)));
public int HighlightId
{
get => (int) GetValue(MainWindow.HighlightIdProperty);
set => SetValue(MainWindow.HighlightIdProperty, value);
}
}
HighlightIdToBrushConverter.cs
public class HighlightIdToBrushConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (!(values[0] is MyModelType currentItem
&& values[1] is int highlightId))
{
return Binding.DoNothing;
}
var highlightBrush = highlightId == currentItem.Id
? new SolidColorBrush(Colors.Red)
: new SolidColorBrush(Colors.Transparent);
highlightBrush.Freeze();
return highlightBrush;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
throw new NotSupportedException();
}
MainWindow.xaml
<ListBox ItemsSource="{Binding Items}">
<ListBox.Resources>
<HighlightIdToBrushConverter x:Key="HighlightIdToBrushConverter" />
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource HighlightIdToBrushConverter}">
<Binding />
<Binding RelativeSource="{RelativeSource AncestorType=Window}"
Path="HighlightId" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
也许不是最好的编码风格,但它工作可靠。
public ClassConstructor()
{
InitializeComponent();
itemscontrol.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
}
...
void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
if (itemscontrol.ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
for (int i = 0; i < itemscontrol.Items.Count; i++)
{
ContentPresenter contentpresenter = (ContentPresenter)itemscontrol.ItemContainerGenerator.ContainerFromItem(itemscontrol.Items[i]);
contentpresenter.ApplyTemplate();
StackPanel stackPanel = (StackPanel)contentpresenter.ContentTemplate.FindName("selectedStackpanel", contentpresenter);
int ID = FindIDofSelectedItemFromStackpanel(stackPanel);
if (highlightID == ID)
{
Border border = (Border)contentpresenter.ContentTemplate.FindName("border_models", contentpresenter);
border.Background = (Brush)FindResource("brushAccent3");
}
else
{
Border border = (Border)contentpresenter.ContentTemplate.FindName("border_models", contentpresenter);
border.Background = Brushes.White;
}
}
}
}
我想从 ItemsControl
中获取所有 UI 项。
由此post How do I access the children of an ItemsControl? 我复制了一个答案,目前有效。
但是,如果我 DIRECTLY 在设置 ItemsSource
后执行 for
循环中的代码(如底部示例),contentpresenter
是 null
,我无法使用它。
如果我 运行 for
-loop 相当长一段时间后(也许当我按下按钮时),一切正常。
如何在设置 ItemsSource
后直接访问 ItemsControl
、 的所有子项?
itemscontrol.ItemsSource = items; // items is a list
itemscontrol.ApplyTemplate(); // might refresh the itemscontrol
for (int i = 0; i < itemscontrol.Items.Count; i++)
{
// ↓ this is null
ContentPresenter contentpresenter = (ContentPresenter)itemscontrol.ItemContainerGenerator.ContainerFromItem(itemscontrol.Items[i]);
// ↑ this is null
contentpresenter.ApplyTemplate();
StackPanel stackPanel = (StackPanel)contentpresenter.ContentTemplate.FindName("selectedStackpanel", contentpresenter);
// do some stuff with the stackpanel
}
更好的解决方案是将相关属性添加到项目模型中,例如一个 IsUserSelected
属性。然后创建一个 Style
,您将其分配给 ItemsControl.ItemContainerStyle
。在此 Style
中,您定义了一个在 IsUserSelected
.
就是这样。不要处理生成器并检查是否生成了每个项目。让框架为您完成这项工作。
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding IsUserSelected}"
Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>`enter code here`
</ListBox>
由于您的代码隐藏文件中已有 属性 HighlightId
,因此您可以使用 IMultiValueConverter
和 MultiBinding
来定义基于以下颜色的颜色值:
MainWindow.xaml.cs
partial class MainWindow
{
public static readonly DependencyProperty HighlightIdProperty = DependencyProperty.Register(
"HighlightId",
typeof(int),
typeof(MainWindow),
new PropertyMetadata(default(int)));
public int HighlightId
{
get => (int) GetValue(MainWindow.HighlightIdProperty);
set => SetValue(MainWindow.HighlightIdProperty, value);
}
}
HighlightIdToBrushConverter.cs
public class HighlightIdToBrushConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (!(values[0] is MyModelType currentItem
&& values[1] is int highlightId))
{
return Binding.DoNothing;
}
var highlightBrush = highlightId == currentItem.Id
? new SolidColorBrush(Colors.Red)
: new SolidColorBrush(Colors.Transparent);
highlightBrush.Freeze();
return highlightBrush;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) =>
throw new NotSupportedException();
}
MainWindow.xaml
<ListBox ItemsSource="{Binding Items}">
<ListBox.Resources>
<HighlightIdToBrushConverter x:Key="HighlightIdToBrushConverter" />
</ListBox.Resources>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource HighlightIdToBrushConverter}">
<Binding />
<Binding RelativeSource="{RelativeSource AncestorType=Window}"
Path="HighlightId" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
也许不是最好的编码风格,但它工作可靠。
public ClassConstructor()
{
InitializeComponent();
itemscontrol.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
}
...
void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
if (itemscontrol.ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
for (int i = 0; i < itemscontrol.Items.Count; i++)
{
ContentPresenter contentpresenter = (ContentPresenter)itemscontrol.ItemContainerGenerator.ContainerFromItem(itemscontrol.Items[i]);
contentpresenter.ApplyTemplate();
StackPanel stackPanel = (StackPanel)contentpresenter.ContentTemplate.FindName("selectedStackpanel", contentpresenter);
int ID = FindIDofSelectedItemFromStackpanel(stackPanel);
if (highlightID == ID)
{
Border border = (Border)contentpresenter.ContentTemplate.FindName("border_models", contentpresenter);
border.Background = (Brush)FindResource("brushAccent3");
}
else
{
Border border = (Border)contentpresenter.ContentTemplate.FindName("border_models", contentpresenter);
border.Background = Brushes.White;
}
}
}
}