我更喜欢在
Behavior
可以添加到XAML中;这需要
System.Windows.Interactivity.WPF NuGet Package
.
如果你真的不想
另一方面,从中提取事件处理逻辑以用于您喜欢的任何方法应该是相当简单的。
public class KeepSelectionBehavior : Behavior<TextBox>
{
private bool _wasAllTextSelected = false;
private int inputKeysDown = 0;
protected override void OnAttached()
{
base.OnAttached();
CheckSelection();
AssociatedObject.TextChanged += TextBox_TextChanged;
AssociatedObject.SelectionChanged += TextBox_SelectionChanged;
AssociatedObject.PreviewKeyDown += TextBox_PreviewKeyDown;
AssociatedObject.KeyUp += TextBox_KeyUp;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.TextChanged -= TextBox_TextChanged;
AssociatedObject.SelectionChanged -= TextBox_SelectionChanged;
AssociatedObject.PreviewKeyDown -= TextBox_PreviewKeyDown;
AssociatedObject.KeyUp -= TextBox_KeyUp;
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (_wasAllTextSelected && inputKeysDown == 0)
{
AssociatedObject.SelectAll();
}
CheckSelection();
}
private void TextBox_SelectionChanged(object sender, RoutedEventArgs e)
{
CheckSelection();
}
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (IsInputKey(e.Key))
{
inputKeysDown++;
}
}
private void TextBox_KeyUp(object sender, KeyEventArgs e)
{
if (IsInputKey(e.Key))
{
inputKeysDown--;
}
}
private bool IsInputKey(Key key)
{
return
key == Key.Space ||
key == Key.Delete ||
key == Key.Back ||
(key >= Key.D0 && key <= Key.Z) ||
(key >= Key.Multiply && key <= Key.Divide) ||
(key >= Key.Oem1 && key <= Key.OemBackslash);
}
private void CheckSelection()
{
_wasAllTextSelected = AssociatedObject.SelectionLength == AssociatedObject.Text.Length;
}
}
你可以这样使用它:
<Window
x:Class="ScriptyBot.Client.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="TestWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<StackPanel>
<TextBox Name="TextBox1" Margin="20">
<i:Interaction.Behaviors>
<behaviors:KeepSelectionBehavior />
</i:Interaction.Behaviors>
</TextBox>
</StackPanel>
</Window>
我正在用一个简单的
DispatchTimer
每秒钟更新一次文本:
public partial class TestWindow : Window
{
private DispatcherTimer timer;
public TestWindow()
{
InitializeComponent();
timer = new DispatcherTimer(DispatcherPriority.Normal);
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += (sender, e) => { TextBox1.Text = DateTime.Now.ToString(); };
timer.Start();
}
}
默认情况下
行为
,您可以使用
Style
app.xaml
public class AttachableForStyleBehavior<TComponent, TBehavior> : Behavior<TComponent>
where TComponent : System.Windows.DependencyObject
where TBehavior : AttachableForStyleBehavior<TComponent, TBehavior>, new()
{
public static readonly DependencyProperty IsEnabledForStyleProperty =
DependencyProperty.RegisterAttached(name: "IsEnabledForStyle",
propertyType: typeof(bool),
ownerType: typeof(AttachableForStyleBehavior<TComponent, TBehavior>),
defaultMetadata: new FrameworkPropertyMetadata(false, OnIsEnabledForStyleChanged));
public bool IsEnabledForStyle
{
get => (bool)GetValue(IsEnabledForStyleProperty);
set => SetValue(IsEnabledForStyleProperty, value);
}
private static void OnIsEnabledForStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is UIElement uiElement)
{
var behaviors = Interaction.GetBehaviors(uiElement);
var existingBehavior = behaviors.FirstOrDefault(b => b.GetType() == typeof(TBehavior)) as TBehavior;
if ((bool)e.NewValue == false && existingBehavior != null)
{
behaviors.Remove(existingBehavior);
}
else if ((bool)e.NewValue == true && existingBehavior == null)
{
behaviors.Add(new TBehavior());
}
}
}
}
行为
类更改为如下所示:
public class KeepSelectionBehavior : AttachableForStyleBehavior<TextBox, KeepSelectionBehavior>
并且是这样应用的(它甚至可以绑定到
bool
动态开启和关闭!):
<Style TargetType="TextBox">
<Setter Property="KeepSelectionBehavior.IsEnabledForStyle" Value="True" />
</Style>
就我个人而言,我更喜欢使用
风格
无论如何,即使将其添加到单个一次性控件中,也要使用基于方法的方法。它大大减少了输入,而且我不必记住如何定义
xmlns
Interactions
Behaviors
名称空间。