我想从ItemsControl中获取所有UI项。
在这篇文章中,How do I access the children of an ItemsControl?,我复制了一个答案,到目前为止,它是有效的。
但是,如果我直接在设置ItemsSource后在for-loop中执行代码(如下面的示例所示),那么contentpresenter就是null,我无法使用它。
如果我在很长一段时间后运行for-loop (也许当我按一下按钮时),一切都会很好。
如何在设置ItemsControl,后直接访问ItemsSource的所有子级
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
}发布于 2021-02-23 17:17:19
更好的解决方案是向项目模型添加相关属性,例如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>发布于 2021-02-25 19:55:28
也许不是最好的编码风格,但它的工作可靠。
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;
}
}
}
}https://stackoverflow.com/questions/66330043
复制相似问题