0
votes

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
1

1 Answers

2
votes

You need to bind TextBlock's Foreground property to amount, and use converter to convert amount to color. With that Foreground will be updated whenever amount value changed. For example (not using multibinding) :

<TextBlock Text="{Binding Path=amount, Mode=TwoWay}"
           Foreground="{Binding Path=amount,
                           Converter="{StaticResource GetColourConverterAmount}" 
           DockPanel.Dock="Right" TextAlignment="Right">