C# 将焦点设置为ItemsControl WPF中的项目

C# 将焦点设置为ItemsControl WPF中的项目,c#,wpf,itemscontrol,C#,Wpf,Itemscontrol,我在scrolviewer中水平显示了一个图像列表,我使用下面的代码行来完成它 <ScrollViewer Name="lviewThumbnails" Height="230" > <ItemsControl ItemsSource="{Binding ThumbsCollection}" MouseWheel="ItemsControl_MouseWheel" > <ItemsControl.ItemTemplate > &

我在scrolviewer中水平显示了一个图像列表,我使用下面的代码行来完成它

<ScrollViewer Name="lviewThumbnails" Height="230"   >
<ItemsControl ItemsSource="{Binding ThumbsCollection}"  MouseWheel="ItemsControl_MouseWheel" > 
    <ItemsControl.ItemTemplate >
        <DataTemplate>
            <DockPanel Height="230">
                <Button Name="pageThumbnail" DockPanel.Dock="Top" Tag="{Binding}" VerticalAlignment="Top"  Margin="5,2">
                    <Grid>
                        <Image MaxWidth="140" Height="200" Source="{Binding ThubnailPath,IsAsync=True}" Stretch="None"></Image>                             
                    </Grid>
                </Button>
                <Label  HorizontalAlignment="Center"  FontSize="14" FontWeight="Bold" Content="text" Foreground="White" Padding="5"></Label>
            </DockPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel  Orientation="Horizontal"  />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>
使图像可见,但每次都默认选择第一项。 我使用触发器来检测所选图像,就像这样

  <DataTrigger Binding="{Binding IsSelected}" Value="True">                                            
                                        <Setter TargetName="pageThumbnail" Property="BorderBrush" Value="Yellow"/>
                                        <Setter TargetName="pageThumbnail" Property="BorderThickness" Value="3"/>
 </DataTrigger>
但问题是,如果选择的是图像75,我可以看到图像75周围的黄色边框,但当我单击按钮时,焦点仍在图像1上。我必须使用scroll Viewer的上一个、下一个按钮才能到达图像75。 我使用的滚动查看器具有特定的样式,如第1列a按钮第2列内容和第3列再次按钮,希望它不会影响默认行为,并且我防止鼠标在滚动查看器上到处滚动

 <ControlTemplate TargetType="{x:Type ScrollViewer}" x:Key="ButtonOnlyScrollViewer">
        <ControlTemplate.Resources>
        </ControlTemplate.Resources>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="20" />
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="20"/>
            </Grid.ColumnDefinitions>
            <Button Style="{StaticResource ResourceKey=ViewPreviousButton}" Grid.Column="0"   Command="ScrollBar.PageUpCommand" MouseWheel="ItemsControl_MouseWheel" 
                      Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"   HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></Button>

            <ScrollContentPresenter
            CanContentScroll="{TemplateBinding CanContentScroll}"
            Grid.Column="1" 
            Content="{TemplateBinding Content}"  
            Width="{TemplateBinding Width}"
            Height="{TemplateBinding Height}" 
            Margin="{TemplateBinding Margin}"/>
            <Button Style="{StaticResource ResourceKey=ViewNextButton}" Grid.Column="2"   Command="ScrollBar.PageDownCommand"  HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MouseWheel="ItemsControl_MouseWheel"
                     ></Button>

        </Grid>
    </ControlTemplate>

您可以使用触发器来执行此操作,并为所选项目使用单独的模板,或者以任何适合您的方式

类似这样,假设您将图像ID作为属性

<DataTrigger Binding="{Binding ThumbsCollection.ImageId}" Value="75">
   <Setter Property="ContentTemplate" Value="{StaticResource SelectedTemplate}" />
</DataTrigger>

在这种情况下,可以使用附加属性

<DataTrigger Binding="{Binding IsSelected}" Value="True">                                            
    <Setter TargetName="pageThumbnail" Property="BorderBrush" Value="Yellow"/>
    <Setter TargetName="pageThumbnail" Property="BorderThickness" Value="3"/>
    <Setter TargetName="pageThumbnail" Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"/>
</DataTrigger>
如果您想设置焦点或显示一些效果,可以绑定IsFocus并使用触发器


我想您应该在屏幕的中间显示第75项,这样就可以使用ScrollToHorizontalOffset。首先获取按钮的实际值,并在计算中获取其边距/填充,然后您将获得偏移量。

所有这些答案都忽略了有关Items控件的讨厌的一点关键信息。它们使用虚拟化,因此只有视图中实际存在的项目和一些周围的项目实际存在。OP想要做的是使用上面给出的答案是不可能的,因为第75张图片实际上还不存在,所以你不能设置它的焦点

您需要:

1订阅ItemsControl ItemContainerGenerator.StatusChanged事件 2设置滚动位置,以便将第75项滚动到视图中 3在StatusChanged事件处理程序中,等待第75个项目的status=ContainerGenerated,然后取消订阅并设置焦点

是的,这太复杂了,是的,代码将立即执行,但是您必须等到容器生成之后,第75项才能设置焦点。这就是虚拟化的工作原理


您正在尝试将焦点设置为第75个项目,但只创建了项目1-10。

请参见问题的编辑。我已经在使用触发器设置所选项目的样式。但问题是,如果选择了第75个图像,我必须使用滚动条滚动器来访问该图像,默认情况下,项目1将被加载OK。因此,您希望滚动条自动滚动到图像75。我没有首先得到它。然后下面的链接可能会帮助您我尝试了3个选项,但列表中的第一项始终是默认的选定项如何通过背景功能或单击/按下按钮设置IsSelected属性?是否可以看到代码的工作示例?这可能有助于轻松完成。请从这里下载示例代码
<DataTrigger Binding="{Binding IsSelected}" Value="True">                                            
    <Setter TargetName="pageThumbnail" Property="BorderBrush" Value="Yellow"/>
    <Setter TargetName="pageThumbnail" Property="BorderThickness" Value="3"/>
    <Setter TargetName="pageThumbnail" Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsSelected}" Value="True">                                            
    <Setter TargetName="pageThumbnail" Property="BorderBrush" Value="Yellow"/>
    <Setter TargetName="pageThumbnail" Property="BorderThickness" Value="3"/>
    <Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=pageThumbnail}"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsSelected}" Value="True">                                            
    <Setter TargetName="pageThumbnail" Property="BorderBrush" Value="Yellow"/>
    <Setter TargetName="pageThumbnail" Property="BorderThickness" Value="3"/>
    <Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"/>
    <Setter TargetName="pageThumbnail" Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"/>
</DataTrigger>
<ItemsControl ItemsSource="{Binding ThumbsCollection}"  MouseWheel="ItemsControl_MouseWheel" Name="singleThumbs">
    <ItemsControl.Resources>
        <Style TargetType="ContentPresenter" xmlns:l="clr-namespace:WPFPerfomanceTest">
            <Setter Property="l:ScrollProvider.ScrollIntoView"
                    Value="{Binding IsSelected}" />
        </Style>
    </ItemsControl.Resources>
    <ItemsControl.ItemTemplate >
        <DataTemplate>
            <DockPanel Height="230">
                <Button Name="pageThumbnail"  DockPanel.Dock="Top" Tag="{Binding}" VerticalAlignment="Top"  Margin="5,2" Width="140">
                    <Grid>
                        <Image Height="200" Source="{Binding ThubnailPath,IsAsync=True}" Stretch="None"></Image>                                        
                    </Grid>
                </Button>
                <Label   HorizontalAlignment="Center"  FontSize="14" FontWeight="Bold" Content="{Binding PageNo}" Foreground="White" Padding="5"></Label>
            </DockPanel>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding IsSelected}" Value="True" >
                    <Setter TargetName="pageThumbnail" Property="BorderBrush" Value="Yellow"/>
                    <Setter TargetName="pageThumbnail" Property="BorderThickness" Value="3"/>
                    <Setter TargetName="pageThumbnail" Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}"/>
                </DataTrigger>

            </DataTemplate.Triggers>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel  Orientation="Horizontal"  />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>
class ScrollProvider : DependencyObject
{
    public static bool GetScrollIntoView(DependencyObject obj)
    {
        return (bool)obj.GetValue(ScrollIntoViewProperty);
    }

    public static void SetScrollIntoView(DependencyObject obj, bool value)
    {
        obj.SetValue(ScrollIntoViewProperty, value);
    }

    // Using a DependencyProperty as the backing store for ScrollIntoView.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ScrollIntoViewProperty =
        DependencyProperty.RegisterAttached("ScrollIntoView", typeof(bool), typeof(ScrollProvider), new PropertyMetadata(false, OnScrollIntoViewChanged));

    private static void OnScrollIntoViewChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        FrameworkElement element = d as FrameworkElement;
        if ((bool)e.NewValue)
        {
            element.BringIntoView();
            element.Focus();
        }
    }
}
private void Button_Click(object sender, RoutedEventArgs e)
        {
            lviewThumbnails.Visibility = Visibility.Visible;

            int index = 75;
            ThumbsCollection[index].IsFocus = true;

            Button button = (Button)FindFirstVisualChild(lviewThumbnails, "pageThumbnail");

            lviewThumbnails.ScrollToHorizontalOffset((button.ActualWidth + 6.5) * index); // set it with pageThumbnail's location or margin
        }

        public object FindFirstVisualChild(DependencyObject obj, string childName)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                if (child != null && child.GetValue(NameProperty).ToString() == childName)
                {
                    return child;
                }
                else
                {
                    object childOfChild = FindFirstVisualChild(child, childName);
                    if (childOfChild != null)
                    {
                        return childOfChild;
                    }
                }
            }
            return null;
        }