Use inline XAML with clr-namespace to create a Styled Treeview

Writing WPF code is made easier in VB because of the built in XML features (XAML is really XML). Here is a sample that creates a TreeView of some folders on disk.

 

Suppose we want to add a Trigger style that will fire when the mouse is over an item. We could do it in code:

        Dim style As New Windows.Style

        style.Triggers.Add(…)

but it’s more elegant to do it in XAML.

 

One problem when doing it with inline XML occurs when you want the XML to reference a type. The MyTVItem type inherits from the TreeViewItem class, and I want the style.TargetType to apply to my class, which is not defined in XAML.

 

IOW, we want the WPF XAML code to refer to the VB Type. The mechanism to do that is the clr-namespace, where we can specify the NameSpace and the Assembly in which the type is found.

 

 

Start VS 2010. File->New->Project->VB->Windows->WPF Application. Make sure to name it exactly “VBTVStyle” (or change the xmlns line below)

 

Replace the Mainwindow.Xaml.vb code with the code below.

 

Hit F5.

 

Observe what happens as you expand treeview branches with the keyboard and the mouse.

 

See also: What is your computer doing with all that memory? Write your own memory browser

 

<Code Sample>

Class MainWindow

    Dim _tv As New MyTView

    Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded

        Dim startPath = System.Environment.GetEnvironmentVariable("programfiles") + "\Microsoft Visual Studio 10.0"

        Dim tItem = New MyTVItem(_tv) With {

            .Header = startPath

            }

        _tv.Items.Add(tItem)

        Dim dp = New DockPanel

        dp.Children.Add(_tv)

        Me.Content = dp

        GetDirs(startPath, tItem)

        tItem.IsExpanded = True ' expand 1st node

    End Sub

    Sub GetDirs(ByVal path As String, ByVal parent As ItemsControl)

        Try

            Dim dirs = IO.Directory.GetDirectories(path, "*.*", IO.SearchOption.TopDirectoryOnly)

            For Each dirName In dirs

                Dim tItem = New MyTVItem(_tv) With {

                    .Header = IO.Path.GetFileName(dirName)

                }

                parent.Items.Add(tItem)

                GetDirs(dirName, tItem) ' recur

            Next

        Catch ex As Exception ' sometimes you get access denied

            MessageBox.Show("Excpt: " + ex.Message + " " + If(String.IsNullOrEmpty(ex.StackTrace), "", ex.StackTrace))

        End Try

    End Sub

End Class

Class MyTView

    Inherits TreeView

    Sub New()

        Dim XAMLStyle = _

<Style

    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:myns="clr-namespace:VBTVStyle;assembly=VBTVStyle"

    TargetType="myns:MyTVItem">

    <Setter Property="Foreground" Value="Blue"/>

    <Style.Triggers>

        <Trigger Property="IsMouseOver" Value="True">

            <Setter Property="Foreground" Value="Red"/>

        </Trigger>

    </Style.Triggers>

</Style>

        Try

            Me.ItemContainerStyle = CType(Windows.Markup.XamlReader.Load(XAMLStyle.CreateReader), Windows.Style)

        Catch ex As Exception

            MessageBox.Show("Excpt: " + ex.Message + " " + If(String.IsNullOrEmpty(ex.StackTrace), "", ex.StackTrace))

        End Try

    End Sub

End Class

Class MyTVItem

    Inherits TreeViewItem

    Sub New(ByVal tv As MyTView)

        Me.ItemContainerStyle = tv.ItemContainerStyle ' propagate to children

    End Sub

End Class

 

</Code Sample>