The attached property is not send to the style - wpf

I wanted to create a cell style to show errors and a text with the tooltip.
My style in the xaml dictionary file is this:
<Style TargetType="{x:Type DataGridCell}" x:Key="DataGridCellConErrores">
<Setter Property="ToolTipService.ShowOnDisabled" Value="True"/>
<Setter Property="ToolTipService.InitialShowDelay" Value="5000"/>
<Setter Property="ToolTipService.ShowDuration" Value="60000"/>
<Setter Property="ToolTip">
<Setter.Value>
<MultiBinding Converter="{StaticResource ResourceKey=dlgEnviarAlbaranCantidadParaDescontarTooltipMultivalueConverter}">
<MultiBinding.Bindings>
<Binding Path="(ap:CeldasDatagridConErroresAttachedProperty.TextoTooltip01)"/>
<Binding Path="(ap:CeldasDatagridConErroresAttachedProperty.TextoTooltip02)"/>
</MultiBinding.Bindings>
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=(ap:CeldasDatagridConErroresAttachedProperty.EsDatoCorrecto)}" Value="false"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="Orange"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
This is how I am trying to use in my column of the datagrid:
<DataGridTextColumn Header="Cantidad Para Descontar" Binding="{Binding CantidadParaDescontar, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, ValidatesOnDataErrors=True}" Width="AUTO" IsReadOnly="false"
ap:CeldasDatagridConErroresAttachedProperty.TextoTooltip01="{Binding Path=DescripcionCantidadParaDescontar}"
ap:CeldasDatagridConErroresAttachedProperty.TextoTooltip02="{Binding Path=MotivoCantidadParaDescontarIncorrecta}"
ap:CeldasDatagridConErroresAttachedProperty.EsDatoCorrecto="{Binding Path=EsCantidadParaDescontarCorrecta}"
CellStyle="{StaticResource DataGridCellConErrores}"/>
I can compile and run, but the text of tooltip is always empty and also it doesn't change the color of the background if the data is not correct.
How should I bind the attached properties?
Thanks.

You should bind to the attached property of the column. Try this:
<Binding Path="Column.(ap:CeldasDatagridConErroresAttachedProperty.TextoTooltip01)"/>

Related

How to run a DataTrigger based on if Validation.HasError = False?

On my DataGridTextColumn I would like to run a DataTrigger but only when Validation.HasError is False
This is what I have at the moment:
<DataGridTextColumn Header="Volts"
Binding="{Binding DcVolts, Converter={StaticResource StringToDecimalConverter}}"
Width="Auto">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}"
BasedOn="{StaticResource DataGridTextColumnElementErrorStyle}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=Validation.HasError}"
Value="False" />
<Condition Value="False">
<Condition.Binding>
<MultiBinding Converter="{StaticResource EqualityConverter}">
<Binding Path="DcVolts" />
<Binding Path="DcSpecVolts" />
</MultiBinding>
</Condition.Binding>
</Condition>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Property="Background" Value="Orange" />
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
The thinking behind is that Validation.HasError has to be False for the MultiDataTrigger to set the BackGround to Orange if the result of the EqualityConverter is False
This is because if Validation.HasError is True then I want the usual Pink background that my DataGridTextColumnElementErrorStyle provides when a rule I have set on the Property fails.
I actually got closer with this:
<DataGridTextColumn Header="Volts"
Binding="{Binding DcVolts, Converter={StaticResource StringToDecimalConverter}}"
Width="Auto">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource DataGridTextColumnElementErrorStyle}">
<Style.Triggers>
<DataTrigger Value="False">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource EqualityConverter}" >
<Binding Path="DcVolts" />
<Binding Path="DcSpecVolts" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Background" Value="Orange" />
</DataTrigger>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Background" Value="Pink" />
</Trigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
But the problem was that on Validation.HasError the messages provided (by the rules I have created) in the ToolTip where duplicated.
Any advice is greatly appreciated.
You should add parentheses around the binding path since Validation.HasError is an attached property:
<Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.HasError)}"
Value="True" />

WPF DataGrid Header contents from style only display once per trigger

An odd problem is occurring with my WPF DataGrid Headers' contents. The XAML for the style looks like this:
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Default">
<Setter Property="Background" Value="White"/>
</DataTrigger>
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Error">
<Setter Property="Background" Value="#F2DEDE"/>
<Setter Property="Header">
<Setter.Value>
<Image Source="{StaticResource IconError}" Width="16" Height="16"></Image>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Warning">
<Setter Property="Background" Value="#FCF8E3"/>
<Setter Property="Header">
<Setter.Value>
<Image Source="{StaticResource IconWarning}" Width="16" Height="16"></Image>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
Error and warning icons should be on every row of those types, with standard rows being blank. However, the output looks like so:
The icons only seem to appear once per trigger, though the trigger is evidently firing as the row colouring is correct.
Snoop shows that the image is simply not inserted into each of the other Headers.
This still happens when replacing the resource image with a path, and when replacing the images entirely with TextBlock elements.
What's going on here? Is there a better way I'm missing?
Edit: For anyone finding this after the fact, the StaticResource icons are BitmapImage instances, not paths.
A UIElement such as an Image can only appear once in the visual tree.
You could define the images and non-shared resources:
<DataGrid>
<DataGrid.Resources>
<Image x:Key="errorImg" x:Shared="False" Source="{StaticResource IconError}" Width="16" Height="16"></Image>
<Image x:Key="warnImg" x:Shared="False" Source="{StaticResource IconWarning}" Width="16" Height="16"></Image>
</DataGrid.Resources>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Default">
<Setter Property="Background" Value="White"/>
</DataTrigger>
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Error">
<Setter Property="Background" Value="#F2DEDE"/>
<Setter Property="Header" Value="{StaticResource errorImg}" />
</DataTrigger>
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Warning">
<Setter Property="Background" Value="#FCF8E3"/>
<Setter Property="Header" Value="{StaticResource warnImg}" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
</DataGrid>
In addition to the chosen answer here, I managed to get this working by replacing the direct set of the Header value with a template instead.
<DataTrigger Binding="{Binding Type, Converter={StaticResource EnumToStringConverter}}" Value="Error">
<Setter Property="Background" Value="#F2DEDE"/>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{StaticResource IconError}" Width="16" Height="16"></Image>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>

How to bind to self?

I know RelativeSource Self binds to the DataContext in scope. That is not what I want. I have a TextBlock and I want to set a trigger which will multibind 2 things. A value from my DataContext/ViewModel which is easy and I have done that. The 2nd value I want is the Text property of the TextBlock. I can't seem to get the syntax at all.
I have this trigger in a TextBlock style.
<Style TargetType="TextBlock"}">
<Setter Property="Margin" Value="10"></Setter>
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource CustomMultiValueConverter}">
<Binding Path="SelectedCategory"></Binding>
<Binding Path="Text" RelativeSource="{RelativeSource Self}"></Binding>
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Foreground" Value="Blue"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
You should be able to use a RelativeSource.AncestorType Binding to reach the TextBlock.Text value. Try this:
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="10"></Setter>
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource CustomMultiValueConverter}">
<Binding Path="SelectedCategory"></Binding>
<Binding Path="Text" RelativeSource="{Binding RelativeSource
AncestorType={x:Type TextBlock}}" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Foreground" Value="Blue"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>

setting text on DataGridTextColumn

I am using a DataTrigger to replace empty cells with '-' text. My code:
<DataGridTextColumn Header="Time taken" Binding="{Binding Path=finish}" Width="Auto" x:Name="x">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=finish}" Value="{x:Null}">
<Setter Property="TextBlock.Text" Value="-" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
But I couldn't find the text being set. I tried changing the background of the TextBlock and its working. Why cant I set the Text property?
The Binding in the column might be overriding the Setter.
But you don't need a data trigger to do this. As there is a property in the binding that you can set for these kinds of scenarios.
TargetNullValue allows you to set a value in the case that the bindings path is null.
Binding="{Binding Path=finish, TargetNullValue=Whatever you want}"
Taken From:
What's the simplest way to display NULL values as "NULL" with WPF Data Binding?
Namespace
xmlns:sys="clr-namespace:System;assembly=mscorlib"
<DataGridTextColumn Header="Time taken" Binding="{Binding Path=finish}" Width="Auto" x:Name="x">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Text" Value="{Binding Path=finish}"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=finish}" Value="{x:Static sys:String.Empty}">
<Setter Property="Text" Value="-"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>

WPF, display attribute value in TreeView instead of node name

If I have the following data template for a TreeView, what do I need to change so that each TreeViewItem shows the value of the name attribute on each XML node, instead of the node name?
<HierarchicalDataTemplate x:Key="NodeTemplate">
<TextBlock x:Name="tb"/>
<HierarchicalDataTemplate.ItemsSource>
<Binding XPath="child::node()" />
</HierarchicalDataTemplate.ItemsSource>
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=NodeType}" Value="Text">
<Setter TargetName="tb" Property="Text" Value="{Binding Path=Value}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
<Setter TargetName="tb" Property="Text" Value="{Binding Path=Name}"/>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
Replace your binding with this:
<Setter TargetName="tb" Property="Text" Value="{Binding Path=Attributes[Name].Value}" />
Found the answer in this question.
Neeeeever mind, just had to replace Path=Name and Path=Value with XPath=#name in the two Setters.

Resources