简体   繁体   English

如何使用 Caliburn.Micro MVVM 正确设置 WPF 文本框的样式?

[英]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.您应该使用VisualBrushTriggers来实现这一点。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM