Create your own media browser: Display your pictures, music, movies in a XAML tooltip

In my prior post, I showed how to use XAML and XAMLReader to create inline XAML to display the results of a query.

Today, let's take it a step further: let's create a query of all the media (pictures, movies, music) in your "My Documents" folder and display the names and sizes in a ListView. As you navigate the list, a tooltip appears showing the media.

You can click on the tip and move it around the screen, or you can mousewheel to zoom in and out.

The code illustrates how to use inline XAML to create hierarchies of UI Elements and get references to those objects to add event handlers. It also shows how to create a databinding DataTemplate and Style with inline XAML.

To get your Foxpro database pictures into this code, see Various ways to display multiple photographs

Start Visual Studio 2008

Choose File->New Project->Visual Basic->WPF Application

You can use the WPF Forms designer, or you can write your code in a program.

Double click the form designer to bring up the Window1.xaml.vb file. Replace the contents with the code below.

Hit F5 to run the program

The query scans your "My Documents" folder for various file types. You can change those types in the query.

<Sample Code>

Imports System.Windows.Controls.Primitives ' for Popup

Partial Public Class Window1

    Dim _rootFolder As String = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)

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

        Me.Width = 800 : Me.Height = 800

        Dim Query = From file In IO.Directory.GetFiles(_rootFolder, _

                                "*.*", IO.SearchOption.AllDirectories) _

                                Select file, Ext = IO.Path.GetExtension(file).ToLower _

                                Where Ext.Length > 0 AndAlso ".avi .jpg .mid .mpg .wma .wmv".Contains(Ext) _

                         Select FileName = file.Substring(_rootFolder.Length + 1), _

                             Type = Ext.Substring(1), _

                             Size = (New IO.FileInfo(file)).Length

        Me.Content = New BrowseWithMedia(Query, Me)

        Me.Title = _rootFolder + " #Items = " + _

            CType(Me.Content, BrowseWithMedia).Items.Count.ToString

    End Sub

    Private Sub Window1_Deactivated(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Deactivated

        Dim pop = CType(Me.Content, BrowseWithMedia)._lvPopUp ' no popup if user changes active window (Alt-Tab)

        If Not pop Is Nothing AndAlso pop.IsOpen Then

            pop.IsOpen = False

        End If

    End Sub

    Private Class BrowseWithMedia : Inherits Browse

        Dim _Parent As Window1 ' reference to container

        Friend _lvPopUp As Popup ' popup window to show tip with movie

        Dim WithEvents _lvTimer As New System.Windows.Threading.DispatcherTimer ' timer: after delay, show tip

        Sub New(ByVal Query As Object, Optional ByVal Parent As Object = Nothing)

  , Parent)

            _Parent = Parent

        End Sub

        Sub HandleWheel(ByVal sp As StackPanel, ByVal e As System.Windows.Input.MouseWheelEventArgs) 'Handles Me.MouseWheel

            Dim transform = CType(sp.RenderTransform, ScaleTransform)

            Dim melem As MediaElement = sp.Children(1)

            If e.Delta > 0 Then

                melem.Height *= 1.1

                melem.Width *= 1.1

                'transform.ScaleX *= 1.1 ' to scale tip text too

                'transform.ScaleY *= 1.1


                'transform.ScaleX /= 1.1

    'transform.ScaleY /= 1.1

                melem.Height /= 1.1

                melem.Width /= 1.1

            End If

        End Sub

        Dim _mdownPt As Point

        Sub HandleClick(ByVal sp As StackPanel, ByVal e As MouseButtonEventArgs)

            If sp.IsMouseCaptured Then


            End If

            If e.LeftButton = MouseButtonState.Pressed Then

                _mdownPt = Mouse.GetPosition(sp) ' record mouse pos relative to sp


            End If

        End Sub

        Sub HandleMouseMove(ByVal sp As StackPanel, ByVal e As MouseEventArgs)

            If Mouse.LeftButton = MouseButtonState.Pressed Then

                If sp.CaptureMouse Then

               Dim curpt As Point = sp.PointToScreen(Mouse.GetPosition(sp))

                    _lvPopUp.HorizontalOffset = curpt.X - _mdownPt.X ' subtract mouse pos rel to sp

                    _lvPopUp.VerticalOffset = curpt.Y - _mdownPt.Y

                    _lvPopUp.Placement = PlacementMode.Absolute ' PlacementMode.Mouse

                End If

            End If

        End Sub

        Sub HandlePopupTimerTick() Handles _lvTimer.Tick ' show the popup

            _lvTimer.IsEnabled = False ' enabled in HandleRowSelected

            Dim lbi As ListBoxItem = Me.ItemContainerGenerator.ContainerFromIndex(Me.SelectedIndex)

            If Not lbi Is Nothing Then

                Dim sp As New StackPanel

                Dim cSrcFile = _Parent._rootFolder + IO.Path.DirectorySeparatorChar + lbi.Content.FileName.ToString

                Dim XAMLPopup = _







                    <StackPanel Orientation="Vertical">


                            <ScaleTransform ScaleX="1" ScaleY="1"/>


                        <TextBlock Foreground="Black" Background="LightYellow">

                            <%= cSrcFile + " " + CType(lbi.Content.size / 1024, Int32).ToString("n0") + "K" %>





                            Name="MyVid" Height="250">


                                <EventTrigger RoutedEvent="MediaElement.Loaded">




                                                <MediaTimeline Source=<%= cSrcFile %>











                _lvPopUp = System.Windows.Markup.XamlReader.Load(XAMLPopup.CreateReader)

                _lvPopUp.PlacementTarget = lbi

                _lvPopUp.IsOpen = True

                Dim stackpanel As StackPanel = _lvPopUp.Child ' only child is the stackpanel

                AddHandler stackpanel.MouseWheel, AddressOf HandleWheel ' mouse wheel will zoom in/out

                AddHandler stackpanel.MouseDown, AddressOf HandleClick ' mouse click/drag will move picture/movie

                AddHandler stackpanel.MouseUp, AddressOf HandleClick

                AddHandler stackpanel.MouseMove, AddressOf HandleMouseMove

            End If

        End Sub

        Sub HandleRowSelected(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles Me.SelectionChanged

            Dim lb = CType(sender, ListBox)

            If Not lb Is Nothing AndAlso (lb.SelectedIndex >= 0) Then

                Dim lbi As ListBoxItem = lb.ItemContainerGenerator.ContainerFromIndex(lb.SelectedIndex)

                If Not _lvPopUp Is Nothing AndAlso _lvPopUp.IsOpen Then

                    _lvPopUp.IsOpen = False

                End If

                _lvTimer.Stop() ' stop prior timer, if any

                _lvTimer.Interval = TimeSpan.FromMilliseconds(500)


            End If

        End Sub

    End Class

End Class

Class Browse

    Inherits ListView

    Sub New(ByVal Query As Object, Optional ByVal Parent As Object = Nothing)

        Dim gv As New GridView

        Me.View = gv

        Me.ItemsSource = Query

        If Not Parent Is Nothing Then

            If Parent.GetType.BaseType Is GetType(Window) Then

                CType(Parent, Window).Title = "# items = " + Me.Items.Count.ToString

            End If

        End If

        Me.AddHandler(GridViewColumnHeader.ClickEvent, New RoutedEventHandler(AddressOf HandleHeaderClick))

        For Each mem In From mbr In _

                        Query.GetType().GetInterface(GetType(IEnumerable(Of )).FullName) _

                            .GetGenericArguments()(0).GetMembers _

                        Where mbr.MemberType = Reflection.MemberTypes.Property

            Dim coltype = CType(mem, Reflection.PropertyInfo).PropertyType.Name

            Select Case coltype

                Case "Int32", "String", "Int64"

                    Dim gvc As New GridViewColumn

                    gvc.Header = mem.Name


                    If coltype <> "String" Then

                        gvc.Width = 80

                        Dim XAMLdt = _





                                <StackPanel Orientation="Horizontal">

                                    <TextBlock Name="tb"

        Text=<%= "{Binding Path=" + mem.Name + "}" %>







                        gvc.CellTemplate = System.Windows.Markup.XamlReader.Load(XAMLdt.CreateReader)


                        gvc.DisplayMemberBinding = New Binding(mem.Name)

                        gvc.Width = 180

                    End If

            End Select


        Dim XAMLlbStyle = _





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


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

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

                        <Setter Property="Background" Value="Aquamarine"/>


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

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




     Me.ItemContainerStyle = Windows.Markup.XamlReader.Load(XAMLlbStyle.CreateReader)

    End Sub

    Dim _Lastdir As System.ComponentModel.ListSortDirection = ComponentModel.ListSortDirection.Ascending

    Dim _LastHeaderClicked As GridViewColumnHeader = Nothing

    Sub HandleHeaderClick(ByVal sender As Object, ByVal e As RoutedEventArgs)

        If e.OriginalSource.GetType Is GetType(GridViewColumnHeader) Then

            Dim gvh = CType(e.OriginalSource, GridViewColumnHeader)

            Dim dir As System.ComponentModel.ListSortDirection = ComponentModel.ListSortDirection.Ascending

            If Not gvh Is Nothing AndAlso Not gvh.Column Is Nothing Then

                Dim hdr = gvh.Column.Header

                If gvh Is _LastHeaderClicked Then

         If _Lastdir = ComponentModel.ListSortDirection.Ascending Then

                        dir = ComponentModel.ListSortDirection.Descending

                    End If

                End If

                Sort(hdr, dir)

                _LastHeaderClicked = gvh

                _Lastdir = dir

            End If

        End If

    End Sub

    Sub Sort(ByVal sortby As String, ByVal dir As System.ComponentModel.ListSortDirection)


        Dim sd = New System.ComponentModel.SortDescription(sortby, dir)



    End Sub

End Class

</Sample Code>