WPF ControlTemplate Height - wpf

I have the following style for validating input in my controls:
<Style x:Key="MyErrorTemplate" TargetType="Control">
<Style.Setters>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate x:Name="ControlErrorTemplate">
<StackPanel Orientation="Vertical" Height="Auto">
<StackPanel Orientation="Horizontal">
<TextBlock Foreground="Red" FontSize="20">!</TextBlock>
<AdornedElementPlaceholder x:Name="Holder"/>
</StackPanel>
<Label Foreground="Red" Content="{Binding ElementName=Holder,
Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
If an error happens, the error message in the label appears under the control (e.g. textbox) and overlaps the control below. I made StackPanel's Height="Auto", but it didn't help. Each control is in a Grid cell, and the Grid's row Height is also Auto.
Could you please tell me what I am missing? I want the error message to push what is below down.
Thanks.

Validation.ErrorTemplate shows error feedback on an adorner layer. This means all controls in this template will not be considered when the layout system is measuring and arranging the controls on the adorned element layer.

I found this and thanks LPL, i did not know that about the adorner layer.
My solution was a margin "hack". I just used the trigger:
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="Margin" Value="0,0,0,28"/>
</Trigger>
</Style.Triggers>
To increase the bottom margin of the adorned textbox. I set the margin large enough to make room for a single string textblock/label and then the content below was moved down

Related

WPF ComboBox selected item text

I made a custom combobox where I have a TextBlock (named mySelectedContent) to display the selected item and a TextBox for editing in "IsEditable" mode. I have a MultiDataTrigger that is being shot correctly, however, I am unable to "catch" the text of the selected item and put it into the TextBlock. How should be mounted the correct expression in place of "???". Thanks a lot!
Here is the code of the trigger (I'm showing mainly the part of the trigger because it's just in it the problem):
<ComboBox.Resources>
<Style x:Key="myComboBox" TargetType="{x:Type ComboBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid>
<ToggleButton>
...
</ToggleButton>
<TextBlock
Name="mySelectedContent"
.../>
<TextBox x:Name="myEditableTextBox"
.../>
<Popup>
...
</Popup>
</Grid>
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
...
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter TargetName="myEditableTextBox" Property="Visibility" Value="Hidden"/>
<Setter TargetName="mySelectedContent" Property="Visibility" Value="Visible"/>
<Setter TargetName="mySelectedContent" Property="Text" Value="???"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.Resources>
It was solved with cYounes first suggestion. I used:
Value={Binding ElementName=MyEditableTextBox Path=Text}
and it works as expected!
Thanks!
That's way too much work when you simply could have used the Tag property to get the value easily with 2 lines:
in XAML:
<ComboBoxItem Content="This Value" Tag="This Value"/>
Then:
GetValue=ComboBoxName.SelectedItem.Tag.ToString()
will give you "This Value" and not
"System.Windows.Controls.ComboBoxItem: This Value"
Much simpler, faster and less time consuming.

TextBlock with vertical scrollbar only

I have a TextBlock which may contain a long text so I want to add a vertical scroll bar to it. My initial attempt was to wrap a ScrollViewer around it. That works but the problem is that when I zoom in, the width is zoomed also. I tried disabling the horizontal scroll bar like this:
<ScrollViewer IsTabStop="True" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
But it didn't solve the problem. I also tried binding the width:
Width="{Binding ElementName=Scroller, Path=ViewportWidth}"
It didn't help either.
So, my question is, how can I add vertical scrollbar to it but have a fixed width and wrapped text for the TextBlock inside? Here's my full code:
<ScrollViewer Grid.Row="1" IsTabStop="True" VerticalScrollBarVisibility="Auto">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Top" TextWrapping="Wrap" TextAlignment="Center"/>
</ScrollViewer>
There are two parts to this answer... the first is to simply use a TextBox:
<TextBox ScrollViewer.VerticalScrollBarVisibility="Visible" Text="Something really
really really really really really really really really long"
Style="{StaticResource TextBlockStyle}" />
The second part is to simply Style the TextBox so that it looks like a TextBlock:
<Style x:Key="TextBlockStyle" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{x:Null}" />
<Setter Property="BorderBrush" Value="{x:Null}" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="TextWrapping" Value="Wrap" />
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{x:Null}" />
</Trigger>
</Style.Triggers>
</Style>
Feel free to remove any of these properties if they do not suit your situation.
<TextBox HorizontalAlignment="Center"
VerticalAlignment="Top"
TextWrapping="Wrap"
TextAlignment="Center"
VerticalScrollBarVisibility="Auto" Width="300" Style="{StaticResource TextBlockStyle}"/>
You don't need a ScrollViewer wrapped in the TextBox, the TextBox control has its own ScrollViewer. And you need to define the width of the TextBox so that the scrollbar will know its fixed width and will wrap the text.
Then, you have to style the TextBox to look like a TextBlock
A good reason why this ScrollViewer won't work according to to Ifeanyi Echeruo from Microsoft, from MSDN
ScrollViewer first asks its content how large it would like to be in
the absence of constraints, if the content requires more space than
the Viewer has then its time to kick in some ScrollBars
In the absence of constraints TextBlock will always opt to return a
size where all text fits on a single line.
A ScrollViewer with ScrollBars will never get a TextBlock to wrap.
However you may be able to come up with a Measure\Arrange combination
for a panel of your own that is almost like ScrollViewer but I cant
think of any logic that can satify both constraints without explicit
knowlege of the behaviour of said children

ControlTemplate and validation - How to position items?

I created ControlTemplate which is shown if there are validation error on my textbox. My controltemplate looks like that
<ControlTemplate x:Key="TextBoxErrorTemplate">
<TextBlock Foreground="Orange" FontSize="12pt">Field can't be empty</TextBlock>
</ControlTemplate>
However if validation errors occure textBlock appears on textBox - and the user can't enter proper value. Is there any way to set the position of TextBlock - the one which shows error info?
ErrorTemplates are for adorning the control and not for changing its internal properties, to do this you should use a style with the respective trigger:
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Foreground" Value="Orange"/>
<Setter Property="FontSize" Value="12"/>
</Trigger>
</Style.Triggers>
</Style>
If you want to display some text you could use a template like this:
<ControlTemplate x:Key="TextBoxErrorTemplate">
<StackPanel Orientation="Horizontal">
<AdornedElementPlaceholder/>
<TextBlock Foreground="Orange" FontSize="12pt">Field can't be empty</TextBlock>
</StackPanel>
</ControlTemplate>
The TextBlock will be displayed on the right of the TextBox.
If you just want to show error messages i'd suggest you set the tooltip of the TextBox and bind it to the validation errors.

How do I change the CellErrorStyle for an Xceed Datagrid?

So in the Xceed documentation there is a code example that does not work for me. It may be because my grid is bound to a DataGridCollectionView. The objects in the collection used by the datagridcollection are what implement IDataErrorInfo.
The errors are showing up just fine. The problem is that they are using the default orange background for errors...I need a red border. Below is the XAML instantiation of my grid. I set the DataCell background property to red just so I could be sure I had access to the grid's properties... I do. I just can't find the way to identify the cell's w/ errors so I can style them. Thanks!
<XceedDG:DataGridControl Grid.Row="1" Grid.ColumnSpan="5" ItemsSource="{Binding Path = ABGDataGridCollectionView, UpdateSourceTrigger=PropertyChanged}"
Background="{x:Static Views:DataGridControlBackgroundBrushes.ElementalBlue}" IsDeleteCommandEnabled="True"
FontSize="16" AutoCreateColumns="False" x:Name="EncounterDataGrid" AllowDrop="True">
<XceedDG:DataGridControl.View>
<Views:TableView ColumnStretchMode="All" ShowRowSelectorPane="True"
ColumnStretchMinWidth="100">
<Views:TableView.FixedHeaders>
<DataTemplate>
<XceedDG:InsertionRow Height="40"/>
</DataTemplate>
</Views:TableView.FixedHeaders>
</Views:TableView>
</XceedDG:DataGridControl.View>
<!--Group Header formatting-->
<XceedDG:DataGridControl.Resources>
<Style TargetType="{x:Type XceedDG:GroupByControl}">
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
<Style TargetType="{x:Type XceedDG:DataCell}">
<Setter Property="Background" Value="Red"/>
</Style>
</XceedDG:DataGridControl.Resources>
...
The knowledge base entry:
http://xceed.com/KB/questions.php?questionid=256
Does seem to be potentially missing a critical piece.
Did you try the CellErrorStyle Property on DataGridView?
<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
<Grid.Resources>
<Style x:Key="errorStyle" TargetType="{x:Type xcdg:DataCell}">
<Setter Property="Foreground" Value="Red"/>
</Style>
</Grid.Resources>
<xcdg:DataGridControl CellErrorStyle="{StaticResource errorStyle}" >
<!--STUFF OMITTED-->
</xcdg:DataGridControl>
</xcdg:DataGridControl>

WPF Expander still shows Validation Error adorner when shrunk

I've got a style for a TextBox to show a validation error message as follows:
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<Border BorderBrush="{Binding Path=ErrorContent,
Converter={StaticResource ValidationErrorToBrushConverter}}" BorderThickness="2">
<AdornedElementPlaceholder />
</Border>
<Image Name="image1" Height="14" Width="14" Stretch="Fill" Margin="1,1,1,1"
Source="{Binding Path=ErrorContent,
Converter={StaticResource ValidationErrorToImageSourceConverter}}"
ToolTip="{Binding Path=ErrorContent}"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The TextBox lives in an Expander. When I open the Expander, the TextBox allows for input, but will fail validation if the input is NullorEmpty, or contains special characters.
My problem is that when I trigger a validation error, the TextBox lights up in red and shows an icon with the message as a tooltip. All good so far. BUT when i close the Expander without passing validation, the red outline and icon with tooltip are still there! Even with the Expander shrunk down! Just floating there... This is not good behavior.
Any ideas on how to get the Validation stuff to hide along with all the other controls in the Expander? Also, the Style for validation is declared in the resources of the UserControl, not in the Expander itself.
I ended up simply clearing the TextBox upon closing the Expander. That way, the validation error goes away and the box is clear and ready for another input when the Expander is opened back up.
I had the same problem. I fixed it by putting an AdornerDecorator as the first child object of the expander. The AdornerDecorator is collapsed when the Expander is collapsed, so the Adorners should all disappear too.
I've resolved this same problem by setting the Validation.ErrorTemplate property to null when the TextBox is hidden
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsHitTestVisible" Value="False">
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
</Trigger>
</Style.Triggers>
</Style>

Resources