[英]How to properly style a WPF TextBox using Caliburn.Micro MVVM?
i am currenty doing a little bit of styling for a login user control (username, password, login button), using Caliburn.Micro MVVM.我目前正在使用 Caliburn.Micro MVVM 为登录用户控件(用户名、密码、登录按钮)做一些样式。
This is my current progress: I created the user control, with its standard WPF controls (1 TextBox, 1 PasswordBox, 1 Button) and made sure that talking to the API and getting a response works without any customization.这是我目前的进展:我创建了用户控件,其标准 WPF 控件(1 个文本框、1 个密码框、1 个按钮)并确保与 API 交谈并获得响应而无需任何自定义。 Currently, each control, the UserName TextBox and the PasswordBox have a TextBlock to there left, to indicate there function.目前,每个控件,UserName TextBox 和 PasswordBox 在左侧都有一个 TextBlock,以指示 function。
What i want to achieve: I want to get rid of these TextBlocks and instead have a default value inside the TextBox and PasswordBox to indicate the function of each control.我想要实现的目标:我想摆脱这些 TextBlocks,而是在 TextBox 和 PasswordBox 中有一个默认值来指示每个控件的 function。 As soon as the user starts typing in the TextBox and PasswordBox, these default values become invisible/go away and are being replaced by the users input.一旦用户开始在 TextBox 和 PasswordBox 中输入,这些默认值就会变得不可见/消失,并被用户输入所取代。
What doesn't work: As soon as i apply the custom style to my TextBox control, NotifyOfPropertyChange(() => UserName) doesn't catch the changing property values any more, therefore NotifyOfPropertyChange(() => CanLogin) returns false and the login button stays inactive sad face什么不起作用:一旦我将自定义样式应用到我的 TextBox 控件,NotifyOfPropertyChange(() => UserName) 就不再捕获不断变化的属性值,因此 NotifyOfPropertyChange(() => CanLogin) 返回 false 并且登录按钮保持不活动悲伤的脸
i guess the reason for this must be the theme/style itself, but after a couple of hours wrestling with it, i can't figure out how to fix it... so any help from a Caliburn.Micro MVVM Guru, pointing in the right direction would be highly appreciated我想这一定是主题/风格本身的原因,但是经过几个小时的努力,我无法弄清楚如何解决它......所以来自 Caliburn.Micro MVVM Guru 的任何帮助,指向正确的方向将不胜感激
The App is build in .NET Framework 4.8.该应用程序是在 .NET 框架 4.8 中构建的。 I am using Caliburn.Micro 4.0.210.我正在使用 Caliburn.Micro 4.0.210。
The LoginViewModel:登录视图模型:
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);
}
}
}
The LoginView:登录视图:
<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>
The TextBoxTheme:文本框主题:
<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>
Can anyone spot where i am confusing Caliburn.Micro with what i am doing?谁能发现我将 Caliburn.Micro 与我正在做的事情混淆的地方?
You should make use of VisualBrush
and Triggers
to achieve this.您应该使用VisualBrush
和Triggers
来实现这一点。 For example for UserName, you could use the following,例如对于用户名,您可以使用以下内容,
<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>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.