为什么 WPF PasswordBox 不可滚动
Why WPF PasswordBox is not scrollable
谁能给我解释一下为什么 PasswordBox 控件不可滚动。
如您所见,当鼠标光标出现在 PasswordBox 上时,滚动不起作用。我添加了默认和自定义 PasswordBox,两者的行为相同。
这是我为更好地演示而创建的示例项目。
<Window
x:Class="PasswordBoxDemo.MainWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="600"
WindowStartupLocation="CenterScreen">
<Window.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Padding" Value="12,8"/>
<Setter Property="Text" Value="Sample text"/>
</Style>
<Style TargetType="{x:Type PasswordBox}">
<Setter Property="Padding" Value="12,8"/>
</Style>
</Window.Resources>
<ScrollViewer>
<StackPanel Margin="10" Height="800">
<TextBlock Margin="16" FontSize="32" TextWrapping="Wrap">
Put your mouse on password box area and try to scroll by mouse wheel.
</TextBlock>
<Label>Text:</Label>
<TextBox />
<Label>Password:</Label>
<PasswordBox Password="123456"/>
<Label>Text:</Label>
<TextBox />
<Label>Text:</Label>
<TextBox />
<Label>Password:</Label>
<PasswordBox Password="123456"/>
<Label>Text:</Label>
<TextBox />
<Label>Text:</Label>
<TextBox />
</StackPanel>
</ScrollViewer>
</Window>
这看起来像是在内部抑制了密码框上的滚动鼠标事件。您可以将 IsHitTestVisible
设置为 false,但这也会阻止其他鼠标事件的发生。
如果您只需要简单的解决方法,请为 PreviewMouseWheel
事件添加处理程序,如下所示:
<PasswordBox PreviewMouseWheel="PasswordBox_PreviewMouseWheel" />
为父 ScrollViewer 命名:
<ScrollViewer Name="scrollViewer1">
然后在代码中实现处理程序回调,如下所示:
private void PasswordBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta != 0)
{
scrollViewer1.ScrollToVerticalOffset(scrollViewer1.VerticalOffset - e.Delta);
}
e.Handled = true;
}
这是一个很大的丑陋,但有效。
我使用另一种方法向 PasswordBox 控件添加滚动行为。我觉得这样更干净。
public class PasswordBoxAssist
{
public static ScrollViewer GetParentScrollViewer(DependencyObject obj)
=> (ScrollViewer)obj.GetValue(ParentScrollViewerProperty);
public static void SetParentScrollViewer(DependencyObject obj, ScrollViewer value)
=> obj.SetValue(ParentScrollViewerProperty, value);
public static readonly DependencyProperty ParentScrollViewerProperty =
DependencyProperty.RegisterAttached("ParentScrollViewer", typeof(ScrollViewer),
typeof(PasswordBoxAssist), new UIPropertyMetadata(default, OnParentScrollViewerChanged));
private static void OnParentScrollViewerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var passwordBox = (PasswordBox)d;
var scrollViewer = (ScrollViewer)e.NewValue;
if (scrollViewer is null)
passwordBox.PreviewMouseWheel -= OnPasswordBoxPreviewMouseWheel;
else
passwordBox.PreviewMouseWheel += OnPasswordBoxPreviewMouseWheel;
}
private static void OnPasswordBoxPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var passwordBox = (PasswordBox)sender;
var scrollViewer = GetParentScrollViewer(passwordBox);
if (e.Delta != 0)
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta);
e.Handled = true;
}
}
<ScrollViewer x:Name="SampleScrollViewer">
<PasswordBox
[...]
local:PasswordBoxAssist.ParentScrollViewer="{Binding ElementName=SampleScrollViewer}"
[...]/>
</ScrollViewer>
谁能给我解释一下为什么 PasswordBox 控件不可滚动。
如您所见,当鼠标光标出现在 PasswordBox 上时,滚动不起作用。我添加了默认和自定义 PasswordBox,两者的行为相同。
这是我为更好地演示而创建的示例项目。
<Window
x:Class="PasswordBoxDemo.MainWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="600"
WindowStartupLocation="CenterScreen">
<Window.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Padding" Value="12,8"/>
<Setter Property="Text" Value="Sample text"/>
</Style>
<Style TargetType="{x:Type PasswordBox}">
<Setter Property="Padding" Value="12,8"/>
</Style>
</Window.Resources>
<ScrollViewer>
<StackPanel Margin="10" Height="800">
<TextBlock Margin="16" FontSize="32" TextWrapping="Wrap">
Put your mouse on password box area and try to scroll by mouse wheel.
</TextBlock>
<Label>Text:</Label>
<TextBox />
<Label>Password:</Label>
<PasswordBox Password="123456"/>
<Label>Text:</Label>
<TextBox />
<Label>Text:</Label>
<TextBox />
<Label>Password:</Label>
<PasswordBox Password="123456"/>
<Label>Text:</Label>
<TextBox />
<Label>Text:</Label>
<TextBox />
</StackPanel>
</ScrollViewer>
</Window>
这看起来像是在内部抑制了密码框上的滚动鼠标事件。您可以将 IsHitTestVisible
设置为 false,但这也会阻止其他鼠标事件的发生。
如果您只需要简单的解决方法,请为 PreviewMouseWheel
事件添加处理程序,如下所示:
<PasswordBox PreviewMouseWheel="PasswordBox_PreviewMouseWheel" />
为父 ScrollViewer 命名:
<ScrollViewer Name="scrollViewer1">
然后在代码中实现处理程序回调,如下所示:
private void PasswordBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta != 0)
{
scrollViewer1.ScrollToVerticalOffset(scrollViewer1.VerticalOffset - e.Delta);
}
e.Handled = true;
}
这是一个很大的丑陋,但有效。
我使用另一种方法向 PasswordBox 控件添加滚动行为。我觉得这样更干净。
public class PasswordBoxAssist
{
public static ScrollViewer GetParentScrollViewer(DependencyObject obj)
=> (ScrollViewer)obj.GetValue(ParentScrollViewerProperty);
public static void SetParentScrollViewer(DependencyObject obj, ScrollViewer value)
=> obj.SetValue(ParentScrollViewerProperty, value);
public static readonly DependencyProperty ParentScrollViewerProperty =
DependencyProperty.RegisterAttached("ParentScrollViewer", typeof(ScrollViewer),
typeof(PasswordBoxAssist), new UIPropertyMetadata(default, OnParentScrollViewerChanged));
private static void OnParentScrollViewerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var passwordBox = (PasswordBox)d;
var scrollViewer = (ScrollViewer)e.NewValue;
if (scrollViewer is null)
passwordBox.PreviewMouseWheel -= OnPasswordBoxPreviewMouseWheel;
else
passwordBox.PreviewMouseWheel += OnPasswordBoxPreviewMouseWheel;
}
private static void OnPasswordBoxPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var passwordBox = (PasswordBox)sender;
var scrollViewer = GetParentScrollViewer(passwordBox);
if (e.Delta != 0)
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta);
e.Handled = true;
}
}
<ScrollViewer x:Name="SampleScrollViewer">
<PasswordBox
[...]
local:PasswordBoxAssist.ParentScrollViewer="{Binding ElementName=SampleScrollViewer}"
[...]/>
</ScrollViewer>