gpt4 book ai didi

c# - 为什么我的WPF PasswordBox样式触发器不起作用?

转载 作者:太空狗 更新时间:2023-10-29 21:48:50 26 4
gpt4 key购买 nike

所以我的应用程序中有这个 PasswordBox

XAML

<PasswordBox Name="PB_PASSWORD" Padding="100,0,34,0" FontSize="20" Width="384" Height="34" PasswordChar="█" Password="" HorizontalAlignment="Left" VerticalAlignment="Top" FontFamily="Century Gothic" HorizontalContentAlignment="Left" VerticalContentAlignment="Center" TabIndex="2" PasswordChanged="PB_PASSWORD_PasswordChanged" >
<PasswordBox.Style>
<Style BasedOn="{x:Null}" TargetType="{x:Type PasswordBox}">
<Setter Property="Background" Value="#FFCCCCCC" />
<Setter Property="Foreground" Value="#FFF22613" />
<Setter Property="BorderBrush" Value="#FFF22613" />
<Setter Property="BorderThickness" Value="0,2,0,2" />
<Setter Property="ClipToBounds" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="PasswordBox">
<Grid>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer x:Name="PART_ContentHost" Margin="0,-4,0,0" />
</Border>
<TextBlock Name="TB" Text="Password" HorizontalAlignment="Left" Margin="140,0,0,0" VerticalAlignment="Center" Foreground="#FF222222" Opacity="0.3"/>
</Grid>
<ControlTemplate.Triggers>

<Trigger Property="IsFocused" Value="true">
<Setter TargetName="TB" Property="Text" Value="Password:" />
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Padding" To="100,0,34,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<ThicknessAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Margin" To="2,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<DoubleAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Padding" To="230,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<ThicknessAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Margin" To="140,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<DoubleAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Opacity" To="0.3" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>

<Trigger Property="ClipToBounds" Value="false">
<Setter TargetName="TB" Property="Text" Value="Password:" />
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Padding" To="100,0,34,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<ThicknessAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Margin" To="2,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<DoubleAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Padding" To="230,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<ThicknessAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Margin" To="140,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<DoubleAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Opacity" To="0.3" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>

<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsFocused" Value="false" />
<Condition Property="ClipToBounds" Value="true" />
</MultiTrigger.Conditions>
<Setter TargetName="TB" Property="Text" Value="Password" />
<MultiTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Padding" To="230,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<ThicknessAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Margin" To="140,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<DoubleAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Opacity" To="0.3" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</MultiTrigger.EnterActions>
<MultiTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Padding" To="100,0,34,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<ThicknessAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Margin" To="2,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<DoubleAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</MultiTrigger.ExitActions>
</MultiTrigger>

<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="TB" Property="Text" Value="DISABLE"/>
<Setter TargetName="TB" Property="Margin" Value="140,0,0,0"/>
<Setter Property="Background" Value="#FFAAAAAA"/>
<Setter Property="Foreground" Value="#FF777777"/>
<Setter Property="BorderBrush" Value="#FF888888" />
<Setter Property="BorderThickness" Value="0,3,0,3" />
</Trigger>

<Trigger Property="Tag" Value="ShowPW">
<Setter Property="Visibility" Value="Hidden"/>
</Trigger>

<Trigger Property="Tag" Value="HidePW">
<Setter Property="Visibility" Value="Visible"/>
</Trigger>

</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
</Style.Triggers>
</Style>
</PasswordBox.Style>
</PasswordBox>

输入的密码为空时,我需要更改其边框颜色。

如果PasswordBox的密码值已更改,则以下代码将更改BorderColor。
注意:清除PasswordBox.Password后,将发生PasswordBox禁用。所以这不重要[我猜]。
C#
    private void PB_PASSWORD_PasswordChanged(object sender, RoutedEventArgs e)
{
if (PB_PASSWORD.SecurePassword.Length == 0)
{ //Password is Empty.
PB_PASSWORD.ClipToBounds = true;
}
else
{ //Password Not Empty
PB_PASSWORD.ClipToBounds = false;
}

Int32 PWStrength = 0;
if (PB_PASSWORD.SecurePassword.Length >= 5)
{
//A Function that Return int Value between 0-5 depending on how Strong is Password.
PWStrength = GetPasswordStrength(Marshal.PtrToStringUni(Marshal.SecureStringToGlobalAllocUnicode(PB_PASSWORD.SecurePassword)));
}
//Corresponding Colors Are Set as per Returned Integer0=red, 1=Orange+Red, 2=Orange, 3=Yellow, 4=Light Green, 5=Green
switch (PWStrength)
{
case 0:
{
//Following 2 Lines Required to Unfreez Color From Control
PB_PASSWORD.Foreground = new SolidColorBrush(CustomColors.PasswordStrengthColors[PWStrength]);
PB_PASSWORD.BorderBrush = new SolidColorBrush(CustomColors.PasswordStrengthColors[PWStrength]);

ColorAnimation AnimateForegroundColor_0 = new ColorAnimation(CustomColors.PasswordStrengthColors[PWStrength], new Duration(TimeSpan.FromMilliseconds(200)));
PB_PASSWORD.Foreground.BeginAnimation(SolidColorBrush.ColorProperty, AnimateForegroundColor_0);
ColorAnimation AnimateBorderBrushColor_0 = new ColorAnimation(CustomColors.PasswordStrengthColors[PWStrength], new Duration(TimeSpan.FromMilliseconds(200)));
PB_PASSWORD.BorderBrush.BeginAnimation(SolidColorBrush.ColorProperty, AnimateBorderBrushColor_0);
break;
}

default:
{
ColorAnimation AnimateForegroundColor = new ColorAnimation(CustomColors.PasswordStrengthColors[PWStrength], new Duration(TimeSpan.FromMilliseconds(200)));
PB_PASSWORD.Foreground.BeginAnimation(SolidColorBrush.ColorProperty, AnimateForegroundColor);
ColorAnimation AnimateBorderBrushColor = new ColorAnimation(CustomColors.PasswordStrengthColors[PWStrength], new Duration(TimeSpan.FromMilliseconds(200)));
PB_PASSWORD.BorderBrush.BeginAnimation(SolidColorBrush.ColorProperty, AnimateBorderBrushColor);
break;
}
}
}

密码值不可访问,因此我使用 ClipToBounds bool 值进行设置,如下所示:
C#
if (String.IsNullOrEmpty(PB_PASSWORD.Password))
{ PB_PASSWORD.ClipToBounds = true; }
else
{ PB_PASSWORD.ClipToBounds = false; }

首次启动应用程序时,此功能运行良好。

当我从后面的代码中修改启用/禁用值时,问题就开始了,如下所示:

C#
    private void Button_Click(object sender, RoutedEventArgs e)
{

if (PB_PASSWORD.IsEnabled)
{
PB_PASSWORD.ClipToBounds = true;
PB_PASSWORD.Password = "";
BTN_BROWSE.Focus();
PB_PASSWORD.MoveFocus(new System.Windows.Input.TraversalRequest(System.Windows.Input.FocusNavigationDirection.Next));
PB_PASSWORD.IsEnabled = false;
}
else
{
PB_PASSWORD.IsEnabled = true;
}
}

输入密码然后禁用后,应该看起来像这样:

但它看起来像这样:

我需要在XAML代码中解决它。

最佳答案

链接到项目:HERE-必须下载!

我决定为您提供完整的MVVM示例,以便您可以学习“正确方法”。

Note: I am using MVVM Light (for it's RelayCommand). You can install it through NuGet. It's worth having, as it provides a lot of useful classes for MVVM development. Another alternative to it is Prism.



1.什么是MVVM?

MVVM(模型- View - View 模型)是一种编程模式,与WPF完美结合。它的主要目的是将 View (您所看到的)与 ViewModels (您的程序的逻辑)分离。

它可能会导致需要更多的编码,但是 yield 却是巨大的-您将获得干净,结构化的代码,该代码是模块化的并且非常容易测试(即单元测试)。

1.1-模型

模型基本上是程序的结构。它应该为您的类提供主干,这些主干保存数据并在ViewModels中进一步使用。

在此项目中-尽管没有模型-不需要模型(随着您的应用程序的发展,肯定会需要它!)

1.2-查看

View 基本上就是您所看到的。大多数情况下,它是一个窗口,它具有显示的元素-但并不仅限于此!一个UserControl本身可以是一个View,并具有自己的ViewModel绑定(bind)-与它所在的Window不同。

1.3 ViewModel

ViewModel基本上是程序的核心。它拥有逻辑并具有View可以绑定(bind)到并在其控件中使用/显示的属性。
将其视为您的应用程序的 brain

2.代码

查看:
<Window x:Class="PasswordBoxMVVM.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"
xmlns:local="clr-namespace:PasswordBoxMVVM"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:b="clr-namespace:System.Media;assembly=System"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:PasswordLengthToColorConverter x:Key="passwordLengthToColorConverter" />
</Window.Resources>
<Grid>
<StackPanel VerticalAlignment="Center">
<PasswordBox local:PasswordBoxMVVMAttachedProperties.EncryptedPassword="{Binding Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding Path=IsPasswordFieldDisabled, Mode=TwoWay ,UpdateSourceTrigger=PropertyChanged}"
FontSize="20" Width="384" Height="34" PasswordChar="█" HorizontalAlignment="Center" FontFamily="Century Gothic"
HorizontalContentAlignment="Left" VerticalContentAlignment="Center" TabIndex="2" Foreground="Red"
PasswordChanged="MyPasswordBox_PasswordChanged"
IsEnabledChanged="PasswordBox_IsEnabledChanged">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PasswordChanged">
<i:InvokeCommandAction Command="{Binding Path=PasswordChangedCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<PasswordBox.Style>
<Style TargetType="{x:Type PasswordBox}">
<Setter Property="Background" Value="#FFCCCCCC" />
<Setter Property="BorderThickness" Value="0,2,0,2" />
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="ClipToBounds" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="PasswordBox">
<Grid>
<Border Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding Foreground}">
<ScrollViewer x:Name="PART_ContentHost" Margin="0,-4,0,0"/>
</Border>
<TextBlock Name="TB" Text="Password" HorizontalAlignment="Left" Margin="140,0,0,0" VerticalAlignment="Center" Opacity="0.3" Foreground="Gray">
</TextBlock>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter TargetName="TB" Property="Text" Value="Password:" />
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Padding" To="100,0,34,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<ThicknessAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Margin" To="2,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<DoubleAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Padding" To="230,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<ThicknessAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Margin" To="140,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<DoubleAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Opacity" To="0.3" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>

<DataTrigger Binding="{Binding Path=IsPasswordFieldEmpty,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="false">
<Setter TargetName="TB" Property="Text" Value="Password:" />
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Padding" To="100,0,34,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<ThicknessAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Margin" To="2,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<DoubleAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Padding" To="230,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<ThicknessAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Margin" To="140,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<DoubleAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Opacity" To="0.3" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>

<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsFocused, RelativeSource={RelativeSource Self}}" Value="false" />
<Condition Binding="{Binding Path=IsPasswordFieldEmpty, UpdateSourceTrigger=PropertyChanged}" Value="true" />
</MultiDataTrigger.Conditions>
<Setter TargetName="TB" Property="Text" Value="Password" />
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Padding" To="230,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<ThicknessAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Margin" To="140,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<DoubleAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Opacity" To="0.3" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<BackEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
<MultiDataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Padding" To="100,0,34,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<ThicknessAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Margin" To="2,0,0,0" Duration="0:0:0.3">
<ThicknessAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</ThicknessAnimation.EasingFunction>
</ThicknessAnimation>
<DoubleAnimation Storyboard.TargetName="TB" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.3">
<DoubleAnimation.EasingFunction>
<SineEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.ExitActions>
</MultiDataTrigger>

<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="TB" Property="Text" Value="DISABLE"/>
<Setter TargetName="TB" Property="Margin" Value="140,0,0,0"/>
<Setter Property="Background" Value="#FFAAAAAA"/>
<Setter Property="Foreground" Value="Gray"/>
<Setter Property="BorderBrush" Value="#FF888888" />
<Setter Property="BorderThickness" Value="0,3,0,3" />
</Trigger>
<Trigger Property="Tag" Value="ShowPW">
<Setter Property="Visibility" Value="Hidden"/>
</Trigger>
<Trigger Property="Tag" Value="HidePW">
<Setter Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
</Style.Triggers>
</Style>
</PasswordBox.Style>
<PasswordBox.Triggers>
<EventTrigger RoutedEvent="PasswordBox.PasswordChanged">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(PasswordBox.Foreground).(SolidColorBrush.Color)"
To="{Binding Path=Password.Length, UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource passwordLengthToColorConverter}}" Duration="0:0:0.1">
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="local:PasswordBoxAttachedEvent.HasBeenDisabled">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(PasswordBox.Foreground).(SolidColorBrush.Color)"
To="Gray" Duration="0:0:0.1">
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="local:PasswordBoxAttachedEvent.HasBeenEnabled">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetProperty="(PasswordBox.Foreground).(SolidColorBrush.Color)"
To="{Binding Path=Password.Length, UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource passwordLengthToColorConverter}}" Duration="0:0:0.1">
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</PasswordBox.Triggers>
</PasswordBox>
<Button Width="200" Height="50" Margin="0,50,0,0" Command="{Binding Path=ClickCommand}">Click me</Button>
</StackPanel>
</Grid>

这与您提供的内容没有太大不同,但是已被扭曲到MVVM中-添加了绑定(bind),命令和转换器。他们需要绑定(bind)(连接)我们的 View ViewModel

View 的背后代码:
public partial class MainWindow : Window
{
public MainWindow()
{
var vm = new PasswordViewModel();
this.DataContext = vm;

InitializeComponent();
}

private void MyPasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
PasswordBox pBox = sender as PasswordBox;
PasswordBoxMVVMAttachedProperties.SetEncryptedPassword(pBox, pBox.SecurePassword);
}

private void PasswordBox_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
PasswordBox pBox = sender as PasswordBox;

if (pBox.IsEnabled == false)
{
RoutedEventArgs eventArgs = new RoutedEventArgs(PasswordBoxAttachedEvent.HasBeenDisabledEvent);
pBox.RaiseEvent(eventArgs);
}
if (pBox.IsEnabled == true)
{
RoutedEventArgs eventArgs = new RoutedEventArgs(PasswordBoxAttachedEvent.HasBeenEnabledEvent);
pBox.RaiseEvent(eventArgs);
}
}
}

在View的构造函数中,我们定义ViewModel-并将其设置为View的 DataContext

下面是一些事件处理程序,使我们可以附加事件和属性-但稍后我们将对此进行讨论。

重要提示:在继续自己学习MVVM时,您可能会看到人们说“在良好的MVVM中,View中不应包含任何代码”。那实际上是完整的公牛** :)
只要不违反任何MVVM原理,将代码放在View中绝对好-通常,它常常使某些事情的编写变得容易一些。

ViewModel:
namespace PasswordBoxMVVM
{
public class PasswordViewModel : ViewModelBase
{
private bool isPasswordFieldEmpty;
public bool IsPasswordFieldEmpty
{
get { return isPasswordFieldEmpty; }
set
{
isPasswordFieldEmpty = value;
RaisePropertyChanged();
}
}

private SecureString password;
public SecureString Password
{
get { return password; }
set
{
password = value;
RaisePropertyChanged();
}
}

private bool isPassWordFieldDisabled;
public bool IsPasswordFieldDisabled
{
get { return isPassWordFieldDisabled; }
set
{
isPassWordFieldDisabled = value;
RaisePropertyChanged();
}
}

public ICommand ClickCommand { get { return new RelayCommand(doAction, canDoAction); } }
public ICommand PasswordChangedCommand { get { return new RelayCommand(updatePassword, canUpdatePassword); } }

public PasswordViewModel()
{
// Init conditions, need them to not get null reference at the start.
isPassWordFieldDisabled = true;
IsPasswordFieldEmpty = true;
}

private void doAction()
{
IsPasswordFieldDisabled = !IsPasswordFieldDisabled;
}

private bool canDoAction()
{
// Replace this with any condition that you need.
return true;
}

private void updatePassword()
{
if (Password != null)
{
if (Password.Length > 0)
{
isPasswordFieldEmpty = false;
}
else
{
isPasswordFieldEmpty = true;
}
}
else
{
isPasswordFieldEmpty = true;
}
}

private bool canUpdatePassword()
{
// Replace this with any condition that you need.
return true;
}
}
}

这里发生了很多事情。首先,我们有一些公共(public)属性,例如Password,isPasswordFieldDisabled等。这些是我们的View可以绑定(bind)到的属性,它使我们可以从ViewModel中控制View。

我们也有命令,这是View与我们的ViewModel进行交互的一种方式。 View 将某些东西绑定(bind)到这些命令(例如事件),然后我们基于ViewModel中的代码执行代码。

在此示例中,单击按钮将向我们的ViewModel发射命令,这将更改isPasswordBoxDisabled属性,我们的PasswordBox isEnabled属性绑定(bind)到-实际上,启用/禁用PasswordBox,而View和ViewModel之间没有任何直接交互!酷吧?

转换器
namespace PasswordBoxMVVM
{
class PasswordLengthToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int length = (int)value;
Color output = Colors.Red;

if (length >= 0 && length < 5)
output = Colors.Red;

else if (length >= 5 && length < 6)
output = Colors.Orange;

else if (length >= 6 && length < 7)
output = Colors.Yellow;

else if (length >= 7 && length < 8)
output = Colors.LightGreen;

else if (length >= 8)
output = Colors.Green;

return output;
}

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

转换器很像翻译器。在这里,我们将密码长度转换为颜色-以便以后可以在动画中使用它们。
当我说MVVM是模块化的时,这就是我的意思的完美示例-您想要不同的转换吗?只需拍一个绑定(bind)到新转换器,就可以完成,无需重写您的View!

密码附加属性-外观链接的项目

这仅仅是出于我们需要将PasswordBox的密码绑定(bind)到ViewModel的需要。最初,PasswordBox不支持该功能。输入附加属性!它通过附加一个新属性(因此命名),从而“扩展”了我们的PasswordBox的可能性-一个我们可以绑定(bind)到ViewModel的属性。

附加事件也是如此-您可以在代码中找到其他所有内容,因为字符配额限制了我无法粘贴更多内容。

关于c# - 为什么我的WPF PasswordBox样式触发器不起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43782774/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com