I have a TreeView that is bound to an ObservableCollection (that properly implements IPropertyNotifyChanged). Each TreeViewItem is a HierarchicalDataTemplate. I have a Converter on the TextBlock that is bound to 'amount' - that changes the foreground colour to red if the string represents a negative number. The first time the TreeView is loaded the amounts all display correctly. However if the underlying ObservableCollection is changed then the amount changes correctly but the colour doesn't (ie a negative 'amount' is shown in white not red).
I have tried using both a IValueConverter and IMultiValueConverter. I have ensured everything is bound with UpdateSourceTrigger=PropertyChanged. The converter just isn't getting called.
What do I need to do to get the converter to be called every time the 'amount' changes??
Thanks Andy
Template:
<!-- Data templates-->
<HierarchicalDataTemplate x:Key="RealTemplate" DataType="{x:Type l:Account}" ItemsSource="{Binding Path=children}">
<DockPanel LastChildFill="True">
<TextBlock x:Name="AccountTitle" Text="{Binding Path=title}" Foreground="White" DockPanel.Dock="Left"/>
<TextBox x:Name="EditAccountTitle" Text="{Binding Path=title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource RoundedTextBox}" FontWeight="Bold" LostFocus="tvLostFocus" PreviewKeyDown="tvKeyDown" LostKeyboardFocus="tvLostFocus" Visibility="Collapsed" DockPanel.Dock="Left" l:FocusExtension.IsFocused="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeViewItem}}}" CaretIndex="{x:Static sys:Int32.MaxValue}"/>
<TextBlock Text="{Binding Path=amount, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DockPanel.Dock="Right" TextAlignment="Right">
<TextBlock.Foreground>
<MultiBinding Converter="{StaticResource GetColourConverterAmountM}" UpdateSourceTrigger="PropertyChanged">
<Binding/>
</MultiBinding>
</TextBlock.Foreground>
</TextBlock>
</DockPanel>
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=isEditable}" Value="True">
<Setter TargetName="AccountTitle" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="EditAccountTitle" Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=isEditable}" Value="False">
<Setter TargetName="AccountTitle" Property="Visibility" Value="Visible"/>
<Setter TargetName="EditAccountTitle" Property="Visibility" Value="Collapsed"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource TreeViewTopItemConverter}}" Value="False">
<DataTrigger.Setters>
<Setter Property="ContextMenu" Value="{StaticResource RealAccountMenu}"/>
</DataTrigger.Setters>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource TreeViewTopItemConverter}}" Value="True">
<DataTrigger.Setters>
<Setter Property="ContextMenu" Value="{StaticResource CategoryMenu}"/>
</DataTrigger.Setters>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
Converter:
Public Class GetColourConverterAmountM
Implements IMultiValueConverter
Function Convert(ByVal values() As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As Globalization.CultureInfo) As Object Implements IMultiValueConverter.Convert
If values Is Nothing Then
Return New SolidColorBrush(Colors.White)
ElseIf (Val(values(0).amount) >= 0) Then
Return New SolidColorBrush(Colors.White)
Else
Return New SolidColorBrush(Colors.Red)
End If
End Function
Function ConvertBack(ByVal value As Object, ByVal targetTypes() As Type, ByVal parameter As Object, ByVal culture As Globalization.CultureInfo) As Object() Implements IMultiValueConverter.ConvertBack
Return Nothing
End Function
End Class
ObservableCollection:
Public Class Account
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Sub NotifyPropertyChanged()
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(Nothing))
End Sub
Private _name, _title, _amount, _target As String
Private _ID, _type, _category, _column As Integer
Private _isEditable, _isNodeExpanded, _isNodeSelected As Boolean
Private _children As ObservableCollection(Of Account)
Public Sub New(__ID As Integer, __name As String, __title As String, __amount As String, __target As String, __type As Integer, __category As Integer, __column As Integer)
children = New ObservableCollection(Of Account)
_ID = __ID
_name = __name
_title = __title
_amount = __amount
_target = __target
_category = __category
_type = __type
_column = __column
_isEditable = False
_isNodeExpanded = True
_isNodeSelected = False
End Sub
Property ID As Integer
Get
Return _ID
End Get
Set(value As Integer)
_ID = value
NotifyPropertyChanged()
End Set
End Property
Property name As String
Get
Return _name
End Get
Set(value As String)
_name = value
NotifyPropertyChanged()
End Set
End Property
Property title As String
Get
Return _title
End Get
Set(value As String)
_title = value
NotifyPropertyChanged()
End Set
End Property
Property amount As String
Get
Return _amount
End Get
Set(value As String)
_amount = value
NotifyPropertyChanged()
End Set
End Property
Property target As String
Get
Return _target
End Get
Set(value As String)
_target = value
NotifyPropertyChanged()
End Set
End Property
Property category As Integer
Get
Return _category
End Get
Set(value As Integer)
_category = value
NotifyPropertyChanged()
End Set
End Property
Property type As Integer
Get
Return _type
End Get
Set(value As Integer)
_type = value
NotifyPropertyChanged()
End Set
End Property
Property column As Integer
Get
Return _column
End Get
Set(value As Integer)
_column = value
NotifyPropertyChanged()
End Set
End Property
Property isEditable As Boolean
Get
Return _isEditable
End Get
Set(value As Boolean)
_isEditable = value
NotifyPropertyChanged()
End Set
End Property
Property isNodeExpanded As Boolean
Get
Return _isNodeExpanded
End Get
Set(value As Boolean)
_isNodeExpanded = value
NotifyPropertyChanged()
End Set
End Property
Property isNodeSelected As Boolean
Get
Return _isNodeSelected
End Get
Set(value As Boolean)
_isNodeSelected = value
NotifyPropertyChanged()
End Set
End Property
Property children As ObservableCollection(Of Account)
Get
Return _children
End Get
Set(value As ObservableCollection(Of Account))
_children = value
NotifyPropertyChanged()
End Set
End Property
End Class