WPF, display attribute value in TreeView instead of node name - wpf

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.

Related

The attached property is not send to the style

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)"/>

Conditional binding in column of datagrid

I have a DataGrid which itemsSource is an ObservableCollection<MyType>. This type has this properties:
long ID;
long IDCategory;
long? IDState01;
long? IDEstate02;
long? IDEste03;
I have 3 categories, if it is category 1, IDState01 is not null and the others states are null. If category is 2, the IDState02 is not null and the others are null and son on.
I have a state column in my DataGrid, which value depends on the category. So I would like to binding to the correct property depending on the category, so if the category is 1, it would bind property state01, if the category is 3 it would bind property state02 and so on.
I think that my DataGrid would be something like that:
<DataGrid HorizontalAlignment="Stretch" Margin="5,5,5,5" VerticalAlignment="Stretch">
<DataGrid.Columns>
<DataGridTextColumn Header="State">
<!--Something here, perhaps a datatrigger.-->
</DateGridTextColumn>
</DataGrid.Columns>
</DataGrid>
Thanks.
EDIT: I would like to do it in XAML if it is possible, instead of using a converter.
introduce a property which will get/set the correct state based on category:
public long? State
{
get
{
if (IDCategory == 1) return IDState01;
if (IDCategory == 2) return IDState02;
return null;
}
set
{
if (IDCategory == 1) IDState01 = value;
else if (IDCategory == 2) IDState02 = value;
}
}
in DataGird bind column to a new property:
<DataGridTextColumn Header="State" Binding="{Binding State}"/>
I would like to do it in XAML if it is possible ...
You could use a DataGridTemplateColumn:
<DataGridTemplateColumn Header="State">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding IDCategory}" Value="1">
<Setter Property="Text" Value="{Binding IDState01}" />
</DataTrigger>
<DataTrigger Binding="{Binding IDCategory}" Value="2">
<Setter Property="Text" Value="{Binding IDEstate02}" />
</DataTrigger>
<DataTrigger Binding="{Binding IDCategory}" Value="3">
<Setter Property="Text" Value="{Binding IDEste03}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IDCategory}" Value="1">
<Setter Property="Text" Value="{Binding IDState01}" />
</DataTrigger>
<DataTrigger Binding="{Binding IDCategory}" Value="2">
<Setter Property="Text" Value="{Binding IDEstate02}" />
</DataTrigger>
<DataTrigger Binding="{Binding IDCategory}" Value="3">
<Setter Property="Text" Value="{Binding IDEste03}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
I think you will need own DataTemplate for each category and DataTemplateSelector to assign DataTemplates based on category type.

Using multiple data triggers does not work

I want to detect when the selected item changes in a ListBox and a TreeView via DataTriggers
so this is my code
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=DirTreeView, Path=SelectedItemChanged}" Value="{x:Null}">
<Setter Property="Text" Value="{Binding ElementName=DirTreeView, Path=SelectedItem, Converter={StaticResource contentConverter}}"/>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=listbox, Path=SelectionChanged}" Value="{x:Null}">
<Setter Property="Text" Value="{Binding ElementName=listbox, Path=SelectedItem, Converter={StaticResource contentConverter}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
if i comment out the last DataTrigger it works fine, but when I use both nothing works.
Why is that and how do I get this to work using both triggers?

How do I bind to the parent's DataContext in a HierarchicalDataTemplate

I have a situation in which I am using a HierarchicalDataTemplate in which most display fields are bound to the items represented in this template (like you'd expect), but I also need one Binding to the data context of the UserControl itself. I fail to manage this last bit.
So I currently have:
<UserControl x:Class="MyProject.ProjectTreeView">
<UserControl.Resources>
<HierarchicalDataTemplate DataType="{x:Type StreetViewModel}"
ItemsSource="{Binding Houses}">
<!-- This Binding works fine (binds to local:StreetViewModel.Street.StreetName) -->
<TextBlock Text="{Binding Street.StreetName}">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<!-- THIS BINDING DOESN'T WORK (I want it to bind to local:ProjectTreeView.SelectedStreet) -->
<DataTrigger Binding="{Binding Path=SelectedStreet, RelativeSource={RelativeSource Self}, UpdateSourceTrigger=PropertyChanged}" Value="Main Street">
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
<!-- This one works again (binds to local:StreetViewModel.Street.ConstructionWorkGoingOn) -->
<DataTrigger Binding="{Binding Street.ConstructionWorkGoingOn, UpdateSourceTrigger=PropertyChanged}" Value="true">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</HierarchicalDataTemplate>
So the problematic thing is that I want to access data in ProjectTreeView but can't reach it within this code. I've tried all sort of things with RelativeSource but that doesn't work. How can this be done?
Try :
<DataTrigger Binding="{Binding Path=DataContext.SelectedStreet, RelativeSource={RelativeSource AncestorType=UserControl}}, UpdateSourceTrigger=PropertyChanged}" Value="Main Street">
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>

WPF: How do I set the Foreground property of a TextBlock using DataTrigger

This is my XAML:
<TextBlock Name="SeverityText"
Grid.Column="1"
Grid.Row="0"
Foreground="Red">
<TextBlock.Triggers>
<DataTrigger Binding="{Binding Path=Severity}">
<DataTrigger.Value>
<sm:Severity>Warning</sm:Severity>
</DataTrigger.Value>
<Setter TargetName="SeverityText"
Property="Foreground"
Value="Yellow" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Severity}">
<DataTrigger.Value>
<sm:Severity>Information</sm:Severity>
</DataTrigger.Value>
<Setter TargetName="SeverityText"
Property="Foreground"
Value="White" />
</DataTrigger>
</TextBlock.Triggers>
<TextBlock>Severity:</TextBlock>
<TextBlock Text="{Binding Path=Severity}" />
</TextBlock>
This is my error message:
Cannot find the static member 'ForegroundProperty' on the type 'ContentPresenter'.
sm:Severity is an enumeration I imported.
Your triggers and setters need to be defined in a style, rather than on the TextBlock directly:
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding Severity}">
<DataTrigger.Value>
<sm:Severity>Warning</sm:Severity>
</DataTrigger.Value>
<Setter TargetName="SeverityText"
Property="Foreground"
Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Writing the full path of the property also works:
So
Property="Foreground" -> Property="TextBlock.Foreground"
However as suggested in the previous answer, you get:
System.InvalidOperationException: Triggers collection members must be of type EventTrigger.
...if you don't put it in a style.

Resources