WPF如何通过数据绑定在ItemsControl中找到特定的控件



我有一个绑定到列表的ItemsControl:

<ItemsControl x:Name="icFiles" ItemsSource="{Binding Path=files}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Content="" IsChecked="{Binding IsChecked, Mode=TwoWay}" />
<TextBlock x:Name="ThisTextBlock" Text="{Binding FileName}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
private readonly List<FileModel> files = new();
icFiles.ItemsSource = files;

我想在ItemsControl中突出显示TextBlock中的某些文本。为此,我考虑使用TextPointer:

string? highlightText = "blue";
int highlightTextIndex = ThisTextBlock.Text.IndexOf(highlightText);
if(highlightTextIndex >= 0)
{
TextPointer textStartPointer = ThisTextBlock.ContentStart.DocumentStart.GetInsertionPosition(LogicalDirection.Forward);
TextRange? highlightTextRange = new TextRange(textStartPointer.GetPositionAtOffset(highlightTextIndex), textStartPointer.GetPositionAtOffset(highlightTextIndex + highlightText.Length));
highlightTextRange.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Blue);
}
}

我如何找到这个ThisTextBlock?

您需要访问项目容器的内容模板(即项目的DataTemplate)。

ItemsControl的情况下,您可以使用以下示例从DataTemplate获取命名元素:


for (int itemIndex = 0; itemIndex < this.ItemsControl.Items.Count; itemIndex++)
{
var itemContainer = this.ItemsControl.ItemContainerGenerator.ContainerFromIndex(itemIndex) as ContentPresenter;
var textBlock = itemContainer.ContentTemplate.FindName("ThisTextBlock", itemContainer) as TextBlock;
HighlightText(textBlock);
}

一个在可视化树中搜索元素的简单实现可以在How to: Microsoft Docs:How to: Find DataTemplate-Generated Elements中找到。您可以复制并使用示例的助手方法FindVisualChild按类型而不是按名称搜索元素。该方法是一个示例的一部分,该示例展示了如何在使用ListBoxListView的情况下获取DataTemplate的内容。

如果您没有修改ListBoxItem模板或不希望它改变,您可以使用这个简化和更快的版本(查找命名元素):

for (int itemIndex = 0; itemIndex < this.ListBox.Items.Count; itemIndex++)
{
var listBoxItemContainer = this.ListBox.ItemContainerGenerator.ContainerFromIndex(itemIndex) as ListBoxItem;
var templateRootBorder = VisualTreeHelper.GetChild(listBoxItemContainer, 0) as Border;
var contentHost = templateRootBorder.Child as ContentPresenter;
var textBlock = contentHost.ContentTemplate.FindName("TD", contentHost) as TextBlock;
}

除特殊用例外,强烈建议使用ListBox而不是ItemsControlListBoxListView都是扩展的ItemsControl。它们都提供滚动和显著改进的性能。

首先,您需要删除绑定from.

你可以使用Loaded事件如下:

<ItemsControl x:Name="icFiles" ItemsSource="{Binding Path=files}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Content="" IsChecked="{Binding IsChecked, Mode=TwoWay}" />
<TextBlock Loaded="ThisTextBlock_OnLoaded" x:Name="ThisTextBlock" Text="{Binding FileName}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>    

private void ThisTextBlock_OnLoaded(object sender, RoutedEventArgs e)
{
if (sender is TextBlock tb)
{
string? highlightText = "blue";
int highlightTextIndex = tb.Text.IndexOf(highlightText);
if (highlightTextIndex >= 0)
{
TextPointer textStartPointer = tb.ContentStart.DocumentStart.GetInsertionPosition(LogicalDirection.Forward);
TextRange? highlightTextRange = new TextRange(textStartPointer.GetPositionAtOffset(highlightTextIndex), textStartPointer.GetPositionAtOffset(highlightTextIndex + highlightText.Length));
highlightTextRange.ApplyPropertyValue(TextElement.BackgroundProperty, Brushes.Blue);
}
}
}

最新更新