I am creating a log in page for my wpf application and want to add watermarks onto the username and password fields. I can achieve this by duplicating code but this is not a satisfactory solution for me. Is there a way I can pass string value through to the watermark binding seen in my Grid.resources section?
the goal is to refactor these two controls so they both can use the single resource login hint below, I have done research on this but came up short on information. Thanks
<Grid.Resources>
<VisualBrush x:Key="LoginHint" Stretch="Uniform" AlignmentX="Left" AlignmentY="Center" >
<VisualBrush.Visual>
<Grid HorizontalAlignment="Left">
<TextBlock FontFamily="Corbel"
HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="Gray" FontStyle="Italic" Opacity="0.3"
Text="Enter Username"/>
</Grid>
</VisualBrush.Visual>
</VisualBrush>
</Grid.Resources>
<TextBox FontSize="24" BorderBrush="#008AB8" BorderThickness="1" Grid.Row="1" x:Name="usernameTextBox" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="25">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=usernameTextBox,Path=Text}" Value="" >
<Setter Property="Background" Value="{StaticResource LoginHint}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<PasswordBox FontSize="24" BorderBrush="#008AB8" BorderThickness="1" Grid.Row="2" x:Name="passwordMarkTextBox" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="25">
<PasswordBox.Style>
<Style TargetType="{x:Type PasswordBox}">
<Setter Property="Background" Value="Transparent"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=passwordMarkTextBox,Path=Text}" Value="" >
<Setter Property="Background" Value="{StaticResource LoginHint}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</PasswordBox.Style>
</PasswordBox>
I would create a custom attached property (e.g., WatermarkText) and then create new control templates which bind to that value and superimpose the watermarks on top of the regular text area. Use triggers to govern its visibility, showing it only when no text or password has been entered. You may need a separate, readonly (computed) property to control its visibility in order to work with both TextBox and PasswordBox.
Related
Im currently working on a UI with WPF embedded in a ElementHost Control(Winform) for a powerpoint add-in. The appearance for the button works fine, however sometimes when entering the button it simply doesn't respond, meaning that hover/press events are not fired and when I click on it selects the parent behind it (probaly since nothing is selected) as if the button was a ghost. When i remove the border inside the template that displays the rounded rectangle the problem dissapears, a default button also doesnt suffer from the same problem. However if the custom button has focus on it, it works flawlessly. So far my best guess is performance related issues.
Grid inside usercontrol that holds the buttons:
<Viewbox Grid.Column="2" Grid.RowSpan="3" HorizontalAlignment="Right" Margin="0,5,10,5">
<Grid Height="100" Width="100">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Background="red" Style="{StaticResource AnchorPoint}" Click="Button_Click_1"/>
<!--<Button Grid.Row="0" Grid.Column="1" Style="{StaticResource AnchorPoint}"/>
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource AnchorPoint}"/>
<Button Grid.Row="1" Grid.Column="2" Style="{StaticResource AnchorPoint}"/>
<Button Grid.Row="1" Grid.Column="1" Style="{StaticResource AnchorPoint}"/>
<Button Grid.Row="1" Grid.Column="0" Style="{StaticResource AnchorPoint}"/>
<Button Grid.Row="2" Grid.Column="0" Style="{StaticResource AnchorPoint}"/>
<Button Grid.Row="2" Grid.Column="1" Style="{StaticResource AnchorPoint}"/>-->
<Button Grid.Row="2" Grid.Column="2" Style="{StaticResource AnchorPoint}"/>
<Button Content="Button" Grid.Column="2" Grid.Row="1"/>
</Grid>
</Viewbox>
Style for button:
<Style TargetType="Button" x:Key="AnchorPoint">
<Setter Property="Background" Value="Transparent"></Setter>
<Setter Property="Foreground" Value="Transparent"></Setter>
<Setter Property="BorderBrush" Value="{x:Null}"></Setter>
<Setter Property="BorderThickness" Value="0"></Setter>
<Setter Property="HorizontalAlignment" Value="Stretch"></Setter>
<Setter Property="VerticalAlignment" Value="Stretch"></Setter>
<Setter Property="Margin" Value="0,0,0,0"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="border" CornerRadius="2" Margin="0" BorderThickness="2" Style="{StaticResource TestHidden}">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Content"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="Red" TargetName="border"></Setter>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Background" Value="blue" TargetName="border"></Setter>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="green" TargetName="border"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Style for Border:
<Style x:Key="TestHidden" TargetType="Border">
<Setter Property="BorderBrush" Value="{StaticResource SkyGrey}"/>
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="Focusable" Value="False"></Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource SkyGrey}" />
<Setter Property="Background" Value="{StaticResource SkyGreyHover}" />
</Trigger>
</Style.Triggers>
</Style>
My hunch is that the problem is related to setting the Background Property of the Border (Key="TestHidden") default to {x:Null}. Although it seems odd, setting the Background to null for a UIElement can cause the element to be invisible to mouse events. This is probably why the element behind the border is the one capturing mouse events instead - making the border seem like a "Ghost". Set the borders default background to Transparent.
<Style x:Key="TestHidden" TargetType="Border">
<Setter Property="BorderBrush" Value="{StaticResource SkyGrey}"/>
<Setter Property="Background" Value="Transparent" />
You might ask why parent button (Key="AnchorPoint") is not capturing mouse events instead: Although the Buttons Background is correctly set to Transparent, this property is being ignored by WPF because it is not referenced in the ControlTemplate via TemplateBinding. If you want the buttons background property to actually show up in the control, use a TemplateBinding on the control responsible for displaying the Background color (the border):
<Border x:Name="border"
CornerRadius="2"
Margin="0"
BorderThickness="2"
Style="{StaticResource TestHidden}"
Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Content"/>
</Border>
Note: There are various other occurrences in your XAML where the issues described above might exist. Hope this helps.
I'm new to wpf and xaml,
trying to understand the basic concepts by writing a simple app using MVVM.
One thing I can't wrap my head around is
How to bind a control eg. textBox which is defined in a style to a viewModel from the control which uses this style?
Style Example (I like to bind the textBox named "SearchBox"):
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type TextBox}"
x:Key="FlatSearchBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border CornerRadius="10"
Background="#353340"
Width="200" Height="40">
<Grid>
<Rectangle StrokeThickness="1"/>
<TextBox Margin="1"
Text="{TemplateBinding Text}"
BorderThickness="0"
Background="Transparent"
VerticalContentAlignment="Center"
Padding="5"
Foreground="#CFCFCF"
x:Name="SearchBox"/>
<TextBlock Grid.Column="1"
IsHitTestVisible="False"
Text="Search"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="10,0,0,0"
FontSize="11"
Foreground="DarkGray">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=SearchBox}" 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>
Part of XAML in which the style is applied to a textBox:
<TextBox Grid.Row="2" Grid.Column="2"
VerticalAlignment="Center"
FontSize="20"
Style="{StaticResource FlatSearchBox}"
Text="{Binding CurrentFinanceModel.Value, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource currencyConverter}}"/>
The text binding should apply to the textBox named "SearchBox" in the style.
Hope the question is clear and I did not make a mistake, because it's my first question here :)
Thanks!
So I have this ListView which has a DataTemplate of my UserContol because I wanted a custom design for my ListView and it looks like this
<ListView x:Name="LeftMenuListView"
ItemsSource="{Binding MenuItems}"
SelectedItem="{Binding SelectedMenuItem}"
BorderThickness="0"
Width="255">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<local:MenuItemControl/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Super simple, now when an Item is selected the entire thing changes color
which I want it looks great imo
<Style TargetType="ListViewItem">
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border
Name="Border"
BorderThickness="0">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="Background"
Value="#444444"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But there is a border inside my usercontrol thats 10px wide with the name SmallBorder.
I want to change the color of that to green when the item is selected but I have no idea how to access that property
My UserControl
<Grid Background="Transparent">
<TextBlock Text="{Binding Name}"
VerticalAlignment="Center"
Margin="20,0,0,0"
Foreground="#9e9e9e"
FontFamily="Tahoma"/>
<Border Width="10"
HorizontalAlignment="Left"
x:Name="SmallBorder"/>
</Grid>
So how do I change the color of SmallBorder when an item is selected and then when it's not selected it turns transparent?
The ViewModel, which is the DataContext of you usercontrol, should expose a property like IsSelected, then you can add an style with a DataTrigger that reacts to a change in this property.
EDIT:
Declare an style for the border itself an access it as an StaticResource:
It could be placed in a ResourceDictionary, within YourUserControl.Resources or inline with the Border control declaration:
<Style TargetType={x:Type Border} x:Key=SelectedBorderStyle>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="BorderBrush" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
And then your UserControl would be:
<Grid Background="Transparent">
<TextBlock Text="{Binding Name}"
VerticalAlignment="Center"
Margin="20,0,0,0"
Foreground="#9e9e9e"
FontFamily="Tahoma"/>
<Border Width="10"
Style={StaticResource SelectedBorderStyle}
HorizontalAlignment="Left"/>
</Grid>
Note that now you don't need to set the name for the Border.
A Border is invisible unless there is something in it, but you could replace the Border with a Grid and use a Style with a DataTrigger that binds to the IsSelected property:
<Grid Background="Transparent">
<TextBlock Text="{Binding Name}"
VerticalAlignment="Center"
Margin="20,0,0,0"
Foreground="#9e9e9e"
FontFamily="Tahoma"/>
<Grid Width="10"
HorizontalAlignment="Left"
x:Name="SmallBorder">
<Grid.Style>
<Style TargetType="Grid">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}" Value="True">
<Setter Property="Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
</Grid>
</Grid>
When a TextBox element has an error The custom adorner doesn't resize the StackPanel the Textbox control lies in:
Using DockPanel.Bottom causes the adorner to overlap on the Textbox below.
The code I shamelessly lifted off http://hirenkhirsaria.blogspot.ie/2013/05/wpf-input-validation-using-mvvm.html:
<ControlTemplate.Resources>
<Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10 0 10 0" />
</Style>
</ControlTemplate.Resources>
<DockPanel LastChildFill="true">
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</Border>
<AdornedElementPlaceholder Name="customAdorner">
<Border BorderBrush="#DC000C" BorderThickness="1.3" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
Sure, I could use Z Index but I don't like it.
Is there a way to cause the StackPanel to resize on error?
I was thinking of adding a ContentTemplate after each Textbox control:
<StackPanel>
<TextBox/>
<ContentTemplate/>
</StackPanel>
<StackPanel>
<TextBox/>
<ContentTemplate/>
</StackPanel>
The ContentTemplate generates an error info DataTemplate which I believe should cause the StackPanel to resize.
But I can't figure out how the binding to (Validation.Errors)[0].ErrorContent} should be done.
My terrible attempt:
<UserControl.Resources>
<DataTemplate x:Key="errorinfo">
<TextBlock>Hello World</TextBlock>
</DataTemplate>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Grid.Row="4">
<Label Padding="0,0,20,0">Name:</Label>
<StackPanel>
<TextBox Padding="0,0,10,0" Width="150" x:Name="name" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"></TextBox>
</StackPanel>
<ContentControl >
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=name, Path=(Validation.HasError)}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding ElementName=name, Path=(Validation.Errors)[0].ErrorContent}"> </TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</StackPanel>
I can't reuse the datatemplate though!
My question is similar to: WPF- Validation -The validation error message goes behind the other controls because of AdornerDecorator
I just want a different solution.
Any ideas? Thanks
Adorner layers sit separate from the main rendering layers in WPF. A good way to think of an Adorner is simply as a graphical overlay layer which encompasses the shape of the Control it's element tags surround (similar to the behaviour of a Border for example).
You don't need a separate AdornerDecorator for every Control. This means the ideal solution would be to add the AdornerDecorator at the highest level possible such as your Window so that you are always guaranteed an Adorner scope.
I can't believe it! Figured it out myself :D
<UserControl.Resources>
<Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10 0 10 0" />
</Style>
<DataTemplate x:Key="errortemplate">
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding Path=(Validation.Errors)[0].ErrorContent}"></TextBlock>
</Border>
</DataTemplate>
<Style x:Key="ContentControlErrorTemplate" TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=Children[1].(Validation.HasError)}" Value="True">
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate>
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=Children[1].(Validation.Errors)[0].ErrorContent}"></TextBlock>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Grid.Row="4">
<Label Padding="0,0,20,0">Name:</Label>
<TextBox Padding="0,0,10,0" Width="150" x:Name="name" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"></TextBox>
<ContentControl Style="{StaticResource ContentControlErrorTemplate}">
</ContentControl>
</StackPanel>
If you have ideas to improve it please let me know. I'm not sure how efficient it is but it works.
I am developing a windows phone app and my requirements include to use a specific color theme and not use the default theme (Light/Dark/etc.) of the phone.
I'm stuck at formatting/templating the headers of textboxes. The following code in the app.xaml is not working:
<DataTemplate x:Key="HeaderTemplate">
<TextBlock Text="{Binding}" Foreground="Black"/>
</DataTemplate>
<Style TargetType="TextBox">
<Setter Property="Foreground" Value="#FFBBB8B8"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="HeaderTemplate" Value="{StaticResource HeaderTemplate}"/>
</Style>
Is there either a way just to configure the theme used or a way to implement the template for the headers?
If you need to implement a Template on a Page
<Page.Resources>
<Style TargetType="TextBox">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding}" Foreground="Red" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<StackPanel>
<TextBox x:Name="TextBox" Width="300" Height="80"
Margin="20" Header="Headline"/>
<TextBox x:Name="TextBox2" Width="300" Height="80"
Margin="20" Header="Headline2"/>
</StackPanel>
or if you want the Style to apply to certain TextBox give it a Key
<Style TargetType="TextBox" x:Key="MyTextBoxStyle">
and apply to relevant TextBox
<TextBox x:Name="TextBox2" Width="300" Height="80"
Margin="20" Header="Headline2"
Style="{StaticResource MyTextBoxStyle}"/>}"/>
Hope that helps
It is really strange I tested the following:
<Application.Resources>
<Style TargetType="TextBox" >
<Setter Property="Foreground" Value="#FFBBB8B8"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Foreground="Red" Text="testing"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="DT1">
<TextBlock Foreground="Green" Text="testing"/>
</DataTemplate>
<Style TargetType="TextBox" x:Key="TextBoxStyle2">
<Setter Property="Foreground" Value="#FFBBB8B8"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="HeaderTemplate" Value="{StaticResource DT1}"/>
</Style>
</Application.Resources>
and in the mainpage
<Grid>
<TextBox Text="testing"/>
<TextBox Margin="0,100,0,0" Style="{StaticResource TextBoxStyle2}" Text="testing"/>
</Grid>
And it works, so I think the content from the binding is empty and appears not be working.