多个ListView控件Items只关注一个ListViewItem

Multiple ListView controls Items only focus on one ListViewItem

我在同一个 window 上有两个 ListView 控件。我正在尝试设置它的样式,以便一次只有一个 ListViewItem 具有焦点。我做了一个名为 FocusBehavior 的附加行为。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace FocusTest
{
    public class FocusBehavior
    {
        #region IsFocused Property
        public static readonly DependencyProperty IsFocusedProperty =
            DependencyProperty.RegisterAttached("IsFocused",
                                                typeof(bool),
                                                typeof(FocusBehavior));

        public static bool GetIsFocused(DependencyObject d)
            => (bool)d.GetValue(IsFocusedProperty);

        public static void SetIsFocused(DependencyObject d, bool value)
            => d.SetValue(IsFocusedProperty, value);
        #endregion

        #region SetFocus Property
        public static readonly DependencyProperty SetFocusProperty =
            DependencyProperty.RegisterAttached("SetFocus",
                                                typeof(bool),
                                                typeof(FocusBehavior),
                        new PropertyMetadata(HandleSetFocusedPropertyChanged));

        private static void HandleSetFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var shouldSetFocus = (bool)e.NewValue;
            if (shouldSetFocus == false)
            {
                return;
            }

            if (d is ListViewItem item)
            {
                var listView = FindAncestor<ListView>(item);
                listView.LostKeyboardFocus += (sender, e) =>
                {
                    SetIsFocused(d, false);
                };

                item.GotFocus += (sender, e) =>
                {
                    SetIsFocused(d, true);
                    Keyboard.Focus(item);
                    e.Handled = true;
                };
                item.LostFocus += (sender, e) =>
                {
                    SetIsFocused(d, false);
                };
            }
        }

        public static bool GetSetFocus(DependencyObject d)
            => (bool)d.GetValue(SetFocusProperty);

        public static void SetSetFocus(DependencyObject d, bool value)
            => d.SetValue(SetFocusProperty, value);
        #endregion

        private static T FindAncestor<T>(DependencyObject dependencyObject) where T : DependencyObject
        {
            var parent = VisualTreeHelper.GetParent(dependencyObject);
            if (parent == null) return null;
            var parentT = parent as T;
            return parentT ?? FindAncestor<T>(parent);
        }
    }
}

如果 ListViewItem 具有焦点并且其父级也是当前焦点的 ListView,这允许我将文本设置为粗体。

      <Window.Resources>
        <Style TargetType="{x:Type ListViewItem}">
            <Setter Property="Focusable" Value="True"/>
            <Setter Property="local:FocusBehavior.SetFocus" Value="True"/>
            <Style.Triggers>
                <Trigger Property="local:FocusBehavior.IsFocused" Value="True">
                    <Setter Property="FontWeight" Value="Bold"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <ListView Grid.Column="0" ItemsSource="{Binding SourceItems}"/>

        <ListView Grid.Column="1" ItemsSource="{Binding TargetItems}"/>
    </Grid>

这几乎完美无缺,但有时点击某个项目无法使其聚焦。 还有其他方法或我缺少的东西吗?请记住这是 POC 代码。

如果您只想更改 ListViewItem 的外观,绑定到 ListViewItem 的 IsFocused 属性 和父 ListView 的 IsKeyboardFocusWithin 属性 的 MultiDataTrigger 将是一个简单的解决方案。

<Style TargetType="{x:Type ListViewItem}">
    <Setter Property="FontWeight" Value="Normal"/>
    <Style.Triggers>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsFocused}" Value="True"/>
                <Condition Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListView}}, Path=IsKeyboardFocusWithin}" Value="True"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="FontWeight" Value="Bold"/>
        </MultiDataTrigger>
    </Style.Triggers>
</Style>