How to make Custom Control as PasswordBox where to the left of passwordbox will be a textblock (lock icon or other symbol). Ie unite passwordbox and textblock in 1 control. From which I can get the Password values. There was an idea to make PasswordBox a ControlTemplate из textblock a and passwordbox`a But I also need that in MainWindow.xaml I could change the style

cs: CustomPassBox Style = {StaticResource DefaultStyle}>

But when I determine the style of the control, then the controlTemplate disappears.

  • This is done through the UserControl in which the DependencyProperty is created and is already interacting with it. As an example, I can offer one of my old answers in which the UserControl of the "custom" button was implemented. - EvgeniyZ
  • Cool of course, but if <local: CustomButton /> is set to style. Isn't the error going out? - Pavel Erikov
  • It depends on how you make the CustomButton. For example, we have such a simple UserControl and such a style , then we can easily apply styles in the standard way ( <local:CustomButton Style="{StaticResource TestStyle}"/> ). If I'm not mistaken, then any element in WPF accepts Style, including its own. - EvgeniyZ
  • In general, your task can essentially be solved with a simple style for PasswordBox. Redefine the element template in it, add everything you need and use as the base style for all children through BasedOn="///" . - EvgeniyZ
  • Can you elaborate on the answer? Please - Pavel Erikov

1 answer 1

Well, look, the main goal is to make two elements inside one and add the ability to use styles. You can go in several ways.

Using styles:

It makes sense here, we make a certain basic style in which we redefine what we need and add a new one.

For example, we have this style for PasswordBox :

 <Style x:Key="MainStyle" TargetType="PasswordBox"> <Setter Property="Height" Value="30"/> <Setter Property="Width" Value="150"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Viewbox> <Canvas Width="24" Height="24"> <Path Data="M12,17C10.89,17 10,16.1 10,15C10,13.89 10.89,13 12,13A2,2 0 0,1 14,15A2,2 0 0,1 12,17M18,20V10H6V20H18M18,8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V10C4,8.89 4.89,8 6,8H7V6A5,5 0 0,1 12,1A5,5 0 0,1 17,6V8H18M12,3A3,3 0 0,0 9,6V8H15V6A3,3 0 0,0 12,3Z" Fill="Black" /> </Canvas> </Viewbox> <Border Grid.Column="1" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True"> <ScrollViewer x:Name="PART_ContentHost" VerticalAlignment="Center" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> 

When applying it, we get the following result:

 <PasswordBox Style="{StaticResource MainStyle}" Password="1234" /> 

Result 1

Now we say we want to set some style for example for errors, then we create another style and set it BaseOn , which will inherit everything from the base style:

 <Style x:Key="ErrorStyle" TargetType="PasswordBox" BasedOn="{StaticResource MainStyle}"> <Setter Property="Background" Value="#99DE0000"/> <Setter Property="Foreground" Value="White"/> </Style> 

Apply and see the result:

 <PasswordBox Style="{StaticResource ErrorStyle}" Password="1234" /> 

Result 2

Using UserControl:

It's all about the same thing, but there is still such a thing as DependencyProperty . With its help, we can pass non-standard properties to our Control (as an example, PasswordBox has the Password property, we can do the same, but let's allow the icon to be redefined), UserControl also supports styles. Let's create something simple:

Add a UserControl with this style:

 <UserControl x:Class="WpfApp1.CustomPasswordBox" 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:WpfApp1" mc:Ignorable="d" x:Name="uc" Height="30" Width="150"> <UserControl.Resources> <StreamGeometry x:Key="DefaultData"> M12,17C10.89,17 10,16.1 10,15C10,13.89 10.89,13 12,13A2,2 0 0,1 14,15A2,2 0 0,1 12,17M18,20V10H6V20H18M18,8A2,2 0 0,1 20,10V20A2,2 0 0,1 18,22H6C4.89,22 4,21.1 4,20V10C4,8.89 4.89,8 6,8H7V6A5,5 0 0,1 12,1A5,5 0 0,1 17,6V8H18M12,3A3,3 0 0,0 9,6V8H15V6A3,3 0 0,0 12,3Z </StreamGeometry> </UserControl.Resources> <UserControl.Template> <ControlTemplate TargetType="UserControl"> <ContentPresenter/> </ControlTemplate> </UserControl.Template> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Viewbox> <Canvas Width="24" Height="24"> <Path Data="{Binding ElementName=uc, Path=Icon, FallbackValue={StaticResource DefaultData}, TargetNullValue={StaticResource DefaultData}}" Fill="Black" /> </Canvas> </Viewbox> <PasswordBox x:Name="PBox" Grid.Column="1" Foreground="{Binding ElementName=uc, Path=Foreground}" Background="{Binding ElementName=uc, Path=Background}" VerticalContentAlignment="Center" /> </Grid> </UserControl> 

And define a pair of DP:

 public partial class CustomPasswordBox : UserControl { public CustomPasswordBox() { InitializeComponent(); PBox.PasswordChanged += (sender, args) => { Password = ((PasswordBox) sender).SecurePassword; }; } public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register( "Password", typeof(SecureString), typeof(CustomPasswordBox), new PropertyMetadata(default(SecureString))); public SecureString Password { get => (SecureString)GetValue(PasswordProperty); set => SetValue(PasswordProperty, value); } public static readonly DependencyProperty IconProperty = DependencyProperty.Register( "Icon", typeof(StreamGeometry), typeof(CustomPasswordBox), new PropertyMetadata(default(StreamGeometry))); public StreamGeometry Icon { get => (StreamGeometry) GetValue(IconProperty); set => SetValue(IconProperty, value); } } 

Here, for example, I set two DependencyProperty:

  1. Password - there are some difficulties, and to be more precise, in WPF, the password should not be stored in memory in an unprotected form, for this reason it will not be possible to simply bind the password, you have to pass it through the PasswordChanged event. There are many examples on the Internet how to get around this, it will be interesting, I think you will find ...
  2. Icon - Simple geometry of our vector icon.

Now let's call it and see the result:

 <local:CustomPasswordBox /> 

UC Result

Create a style for our new UserControl, redefine the colors and icon:

 <StreamGeometry x:Key="KeyIcon"> M21,11C21,16.55 17.16,21.74 12,23C6.84,21.74 3,16.55 3,11V5L12,1L21,5V11M12,21C15.75,20 19,15.54 19,11.22V6.3L12,3.18L5,6.3V11.22C5,15.54 8.25,20 12,21M12,6A3,3 0 0,1 15,9C15,10.31 14.17,11.42 13,11.83V14H15V16H13V18H11V11.83C9.83,11.42 9,10.31 9,9A3,3 0 0,1 12,6M12,8A1,1 0 0,0 11,9A1,1 0 0,0 12,10A1,1 0 0,0 13,9A1,1 0 0,0 12,8Z </StreamGeometry> <Style x:Key="ErrorStyle" TargetType="local:CustomPasswordBox"> <Setter Property="Background" Value="#99DE0000"/> <Setter Property="Foreground" Value="White"/> <Setter Property="Icon" Value="{StaticResource KeyIcon}"/> </Style> 

Result:

 <local:CustomPasswordBox Style="{StaticResource ErrorStyle}" /> 

UC Result2

Actually, this is how pretty simple we can work with elements.
Good luck learning WPF!

  • Thanks for the help! And the last question, how do you make such icons? I’m sure that they’re not drawing such things themselves. - Pavel Erikov
  • @PavelErikov I usually use ready-made solutions, for example FontAwesome.WPF , which allow you to specify icons like this: <fa:FontAwesome Icon="Flag" /> . Sometimes (as it is now) I use such sites as Material Design Icons - on it, each icon has the View XAML option, which just gives out the vector of the icon. - EvgeniyZ