在WPF中导出ListBox

时间:2012-03-02 13:40:13

标签: wpf

我在列表框上方有一个按钮,其中的项目处于水平对齐状态。如果我的按钮有焦点,我按下键盘上的向下键,然后列表框获得焦点。如果我然后按键,则列表框仍然具有焦点。可以改变这种行为,所以当我按下键时我的按钮再次聚焦了吗?

编辑:我应该添加我正在使用MVVM,所以如果可能的话,希望保持解决方案不受代码隐藏。

以下是我的列表框的完整代码。

<ListBox Grid.Row="2" ItemsSource="{Binding Movies}" TextSearch.TextPath="Title" SelectedItem="{Binding SelectedItem, Mode=TwoWay}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel IsItemsHost="True" Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.Template>
            <ControlTemplate>
                <Grid>
                    <ScrollViewer VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Disabled">
                        <ItemsPresenter />
                    </ScrollViewer>
                </Grid>
            </ControlTemplate>
        </ListBox.Template>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid x:Name="poster">
                    <Image x:Name="posterImage" RenderOptions.BitmapScalingMode="LowQuality" Source="{Binding Poster}" Stretch="Uniform" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"
                           Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}, Path=ActualHeight}">
                    </Image>
                    <TextBlock Text="{Binding PosterOverlayText}" Style="{DynamicResource PosterOverlayText}" Width="{Binding ActualWidth, ElementName=posterImage}"/>
                    <Grid.LayoutTransform>
                        <TransformGroup>
                            <ScaleTransform x:Name="st" ScaleX="0.85" ScaleY="{Binding ScaleX, RelativeSource={RelativeSource Self}}"/>
                        </TransformGroup>
                    </Grid.LayoutTransform>
                    <Grid.InputBindings>
                        <MouseBinding Command="{x:Static Commands:MediaFiles.PlaySelectedMovie}" Gesture="LeftDoubleClick" />
                    </Grid.InputBindings>
                </Grid>

                <DataTemplate.Resources>
                    <CubicEase x:Key="ease" EasingMode="EaseOut"/>
                </DataTemplate.Resources>
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}},Path=IsSelected}" Value="True">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation 
                            Duration="0:0:0.3" 
                            EasingFunction="{StaticResource ease}" 
                            Storyboard.TargetName="st" 
                            Storyboard.TargetProperty="ScaleX" 
                            To="1"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                        <DataTrigger.ExitActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation 
                            Duration="0:0:0.3" 
                            EasingFunction="{StaticResource ease}" 
                            Storyboard.TargetName="st" 
                            Storyboard.TargetProperty="ScaleX" 
                            To="0.85"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.ExitActions>

                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ListBox.ItemTemplate>
        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
                <Style.Resources>
                    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
                    <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent"/>
                </Style.Resources>

            </Style>
        </ListBox.ItemContainerStyle>
        <ListBox.InputBindings>
            <KeyBinding Command="{x:Static Commands:MediaFiles.PlaySelectedMovie}" Gesture="ENTER"/>
        </ListBox.InputBindings>            
    </ListBox>

1 个答案:

答案 0 :(得分:0)

不知道是否有一个直接的MVVM接受解决此问题的方法。原因是ListBox实际上使用键向上和按键事件来浏览列表项(大多数时候这是期望的效果),而按钮将让事件进入FocusManager类。

然而,至于那里的一切,有解决方法,所以这里是我将如何做到这一点: 首先,您需要拦截Key-Down事件并寻找方向输入(上下左右)。我认为您仍然希望使用列表中的键进行导航,因此,在事件处理程序中,我将确保测试我是否在第一个(或最后一个)元素上,然后使用TraversalRequest的MoveFocus()方法 - FocusNavigationDirection.Up / Down / Next / Previous移动焦点。

最后,为了确保您的代码隐藏是干净的,请创建一个新的ListBox派生控件并在那里举行您的活动。实际上,在派生控件中,不要使用事件,覆盖OnKeyDown方法。这样,您就可以在自定义控件中编写焦点逻辑,而不是View。

代码:

  protected override void OnKeyDown(KeyEventArgs e)
    {
        if ((e.Key == Key.Up ||e.Key == Key.Left) && SelectedIndex == 0)
        {
            //.Previous will navigate correctly to the last element 
            this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Previous));

            return;
        }

        if (e.Key == Key.Down && this.SelectedIndex == this.Items.Count - 1)
        {
            //.Next will navigate to the first item in the list rather than skip to the next control. We will use Down or Right.
            //this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));

            this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Down));
            return;
        }

        if (e.Key == Key.Right && this.SelectedIndex == this.Items.Count - 1)
        {
            this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Right));
            return;
        }


        base.OnKeyUp(e);
    }