我目前正在使用Caliburn.Micro MVVM为登录用户控件(用户名、密码、登录按钮(做一些样式设计。
这是我目前的进展:我创建了用户控件及其标准WPF控件(1个TextBox、1个PasswordBox和1个Button(,并确保在没有任何自定义的情况下与API对话并获得响应。目前,每个控件、UserName TextBox和PasswordBox的左侧都有一个TextBlock,用于指示函数。
我想要实现的是:我想去掉这些TextBlock,而是在TextBox和PasswordBox中有一个默认值来指示每个控件的功能。一旦用户开始在TextBox和PasswordBox中输入,这些默认值就会变得不可见/消失,并被用户输入所取代。
什么不起作用:一旦我将自定义样式应用于TextBox控件,NotifyOfPropertyChange(((=>UserName(不再捕获正在更改的属性值,因此NotifyOfPropertyChange(((=>CanLogin(返回false,登录按钮保持不活动悲伤的脸
我想这一定是主题/风格本身的原因,但在与它搏斗了几个小时后,我不知道如何修复它……所以如果能得到Caliburn.Micro MVVM大师的任何帮助,指向正确的方向,我将不胜感激!
该应用程序是在.NET Framework 4.8中构建的。我正在使用Caliburn.Micro 4.0.210。
登录视图模型:
public class LoginViewModel : Screen
{
private string _userName;
private string _password;
private IAPIHelper _apiHelper;
public LoginViewModel(IAPIHelper apiHelper)
{
_apiHelper = apiHelper;
}
public string UserName
{
get { return _userName; }
set
{
_userName = value;
NotifyOfPropertyChange(() => UserName);
NotifyOfPropertyChange(() => CanLogin);
}
}
public string Password
{
get { return _password; }
set
{
_password = value;
NotifyOfPropertyChange(() => Password);
NotifyOfPropertyChange(() => CanLogin);
}
}
public bool CanLogin
{
get
{
bool output;
output = !string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password);
return output;
}
}
public async Task Login()
{
try
{
var result = await _apiHelper.Authenticate(UserName, Password);
}
catch (Exception ex)
{
// TODO - Just there for break points - change to proper error handling - user notification
Console.WriteLine(ex.Message);
}
}
}
登录视图:
<UserControl x:Class="ARMDesktopUI.Views.LoginView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ARMDesktopUI.Views"
mc:Ignorable="d"
FontSize="24" FontFamily="Montserrat" FontWeight="Light"
d:DesignHeight="414" d:DesignWidth="790">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Header row -->
<TextBlock Grid.Row="1" Grid.Column="1"
Grid.ColumnSpan="2"
HorizontalAlignment="Center"
Text="Login Form"
FontSize="76"
Margin="0 0 0 10"
Foreground="#FF99AAC6"/>
<!-- TODO - Stylized separator - Replace with actual styled separator -->
<Separator Grid.Row="2" Grid.Column="0"
Grid.ColumnSpan="4"
VerticalAlignment="Bottom"
Background="#212121"/>
<Separator Grid.Row="3" Grid.Column="0"
Grid.ColumnSpan="4"
VerticalAlignment="Bottom"
Margin="0 -0.8 0 1"
Background="Black"/>
<Separator Grid.Row="4" Grid.Column="0"
Grid.ColumnSpan="4"
VerticalAlignment="Bottom"
Margin="0 0 0 30"
Background="#FF454545"/>
<!-- Username row -->
<TextBlock Grid.Row="5" Grid.Column="1"
Text="Username:"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="0 0 0 15"
Foreground="#FF99AAC6"/>
<TextBox x:Name="UserName"
Grid.Row="5" Grid.Column="2"
FontSize="20"
Margin="10 0 0 15"
Style="{StaticResource ModernTextBox}"/>
<!-- Password row -->
<TextBlock Grid.Row="6" Grid.Column="1"
Text="Password:"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Margin="0 0 0 30"
Foreground="#FF99AAC6"/>
<PasswordBox x:Name="Password"
Grid.Row="6" Grid.Column="2"
MinWidth="300" Height="30"
FontSize="20"
Margin="10 0 0 30"
Foreground="#FF8897D7"/>
<!-- Login button row -->
<Button x:Name="Login"
Grid.Row="7" Grid.Column="1"
Grid.ColumnSpan="2"
HorizontalAlignment="Center"
Width="439" Height="46"
Content="Login"
Foreground="#FF99AAC6"
Style="{StaticResource LoginButtonTheme}"/>
</Grid>
文本框主题:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style BasedOn="{StaticResource {x:Type TextBox}}"
TargetType="{x:Type TextBox}"
x:Key="ModernTextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border CornerRadius="10"
Background="#353340"
MinWidth="300" Height="40">
<Grid>
<Rectangle StrokeThickness="1"/>
<TextBox Margin="1"
Text="{TemplateBinding Text}"
BorderThickness="0"
Background="Transparent"
VerticalContentAlignment="Center"
Padding="5"
Foreground="#CFCFCF"
x:Name="UserName"/>
<TextBlock IsHitTestVisible="False"
Text="Username"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="10 0 0 0"
FontSize="20"
Foreground="DarkGray"
Grid.Column="1">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=UserName}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
<Setter Property="Visibility" Value="Hidden"/>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
有人能发现我在哪里把Caliburn.Micro和我正在做的事情混淆了吗?
您应该使用VisualBrush
和Triggers
来实现这一点。例如,对于UserName,可以使用以下
<TextBox x:Name="UserName" Grid.Row="5" Grid.Column="2"
FontSize="20"
Margin="10 0 0 15">
<TextBox.Style>
<Style TargetType="TextBox" >
<Style.Resources>
<VisualBrush x:Key="CueBannerBrush" AlignmentX="Left" AlignmentY="Center" Stretch="None">
<VisualBrush.Visual>
<Label Content="{Binding CueTextUserName}" Foreground="Gray" />
</VisualBrush.Visual>
</VisualBrush>
</Style.Resources>
<Style.Triggers>
<Trigger Property="Text" Value="{x:Static system:String.Empty}">
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
</Trigger>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="Background" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>