0
votes

I have a treeview in which there are selectable items, with subitems which may trigger some code action. When the subitem is clicked, the action should be executed, but the parent item has to remain/become the selected item.

The problem I'm facing is that item are not being deselected properly, causing multiple items to be selected in the treeview.

Here's the xaml for the treeview:

    <TreeView Name="Treeview1" Style="{StaticResource vcc_Treeview}" >
        <TreeView.ItemTemplate >
            <HierarchicalDataTemplate ItemsSource="{Binding Children}" >
                <StackPanel Orientation="Horizontal">
                    <Image Source="{Binding ImgSrc}" Style="{StaticResource vcc_TreeviewItemImage}" />
                    <TextBlock Text="{Binding Description}" Style="{StaticResource vcc_TreeviewItemTextblock}" Foreground="{Binding TextColorBrush}" />
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
        <TreeView.ItemContainerStyle>
            <Style TargetType="TreeViewItem">
                <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay, Converter={StaticResource clsBindingDebugger}}" />
            </Style>
        </TreeView.ItemContainerStyle>
    </TreeView>

The clsBindingDebugger does nothing but debug print the converted value and pass through the convert- and convertback value.

Next the somewhat shortened version of the TreeviewItem Class

Public Class MyTreeviewItem
Implements INotifyPropertyChanged

Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

Public Event MyTreeviewItem_ExpandedChanged(MTI As MyTreeviewItem, IsExpanded As Boolean)
Public Event MyTreeviewItem_SelectedChanged(MTI As MyTreeviewItem, IsSelected As Boolean)



Public Sub New(Optional Level_ As Integer = 1, Optional ByVal Key_ As String = "")
    MyBase.New()
    Me.Children = New ObservableCollection(Of MyTreeviewItem)
    _Key = Key_
    _Level = Level_
End Sub

Private _Level As Integer
Public Property Level As Integer
    Get
        Level = _Level
    End Get
    Set(value As Integer)
        _Level = value
    End Set
End Property

Private _Descr As String = ""
Public Property Description As String
    Get
        Description = _Descr
    End Get
    Set(value As String)
        _Descr = value
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Description"))
    End Set
End Property

Private _Key As String = ""
Public Property Key As String
    Get
        Key = _Key
    End Get
    Set(value As String)
        _Key = value
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Key"))
    End Set
End Property

Private _ImgSrc As ImageSource
Public Property ImgSrc As ImageSource
    Get
        ImgSrc = _ImgSrc
    End Get
    Set(value As ImageSource)
        _ImgSrc = value
    End Set
End Property

Private _Children As ObservableCollection(Of MyTreeviewItem)
Public Property Children As ObservableCollection(Of MyTreeviewItem)
    Get
        Return _Children
    End Get
    Set(value As ObservableCollection(Of MyTreeviewItem))
        _Children = value
    End Set
End Property

Private _IsSelected As Boolean
Overloads Property IsSelected As Boolean
    Get
        Return _IsSelected
    End Get
    Set(ByVal value As Boolean)
        _IsSelected = value
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("IsSelected"))
        RaiseEvent MyTreeviewItem_SelectedChanged(Me, _IsSelected)
    End Set
End Property

Private _IsActionItem As Boolean
Overloads Property IsActionItem As Boolean
    Get
        Return _IsActionItem
    End Get
    Set(ByVal value As Boolean)
        _IsActionItem = value
    End Set
End Property
End Class

Finally I trigger the event MyTreeviewItem_SelectedChanged:

Private ReselectingParent As Boolean = False

Private Sub MyTreeviewItem_SelectedChanged(MTI As MyTreeviewItem, IsSelected As Boolean)
Debug.Print(MTI.Description & "  Selected = " & IsSelected)
If ReselectingParent Then Exit Sub

If IsSelected Then

    'Do some (action) stuff here

    If MTI.IsActionItem AndAlso MTI.Parent IsNot Nothing Then
        ReselectingParent = True 'to prevent this sub from being executed with the next 2 lines
        MTI.IsSelected = False
        MTI.Parent.IsSelected = True
        ReselectingParent = False
    End If
End If
End Sub

Suppose the treeview looks like:

item 1
--Action 1
--Action 2
Item 2
--Action 3
--Action 4

In my starting situation item 2 is selected. Now I click Action 1, so the action should be executed and afterwards item 1 should be the selected item. The debug.print results in these lines:

ConvertBack: False
Item 2  Selected = False
Convert: False
ConvertBack: True
Action 2  Selected = True
Action 2  Selected = False
Convert: True
Item 1  Selected = True
Convert: False

At this point Item 1 is selected, as it should be. Now I click Action 3.

ConvertBack: False
Action 2  Selected = False
Convert: False
ConvertBack: True
Action 3  Selected = True
Action 3  Selected = False
Convert: True
Item 2  Selected = True
Convert: False

The result is that Item 1 and Item 2 are both selected, where only Item 2 should be selected. The second debugger block says "Action 2 Selected = False", this should be "Item 1 Selected = False"

I hope I'm clear. Can anybody point me to the solution of my problem? Thanks!

1

1 Answers

0
votes

For who's interested...

I stille don't quite understand why the code isn't working properly. But apparently the clicked action-item wasn't deselected properly. Instead of calling these lines:

    ReselectingParent = True 'to prevent this sub from being executed with the next 2 lines
    MTI.IsSelected = False
    MTI.Parent.IsSelected = True
    ReselectingParent = False

directly in MyTreeviewItem_SelectedChanged I now call a timer instead. In the timer_elapsed event I call the four lines. Apparently the primary select of the action-item was not finished when calling the code to select it's parent. It's an ugly workaround, but it works for me...