多个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>
我在同一个 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>