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)
MyBase.new(Query, 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
Else
'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
sp.ReleaseMouseCapture()
End If
If e.LeftButton = MouseButtonState.Pressed Then
_mdownPt = Mouse.GetPosition(sp) ' record mouse pos relative to sp
sp.CaptureMouse()
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 = _
<Popup
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Placement="Right"
IsOpen="False"
>
<StackPanel Orientation="Vertical">
<StackPanel.RenderTransform>
<ScaleTransform ScaleX="1" ScaleY="1"/>
</StackPanel.RenderTransform>
<TextBlock Foreground="Black" Background="LightYellow">
<%= cSrcFile + " " + CType(lbi.Content.size / 1024, Int32).ToString("n0") + "K" %>
</TextBlock>
<MediaElement
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Name="MyVid" Height="250">
<MediaElement.Triggers>
<EventTrigger RoutedEvent="MediaElement.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<MediaTimeline Source=<%= cSrcFile %>
Storyboard.TargetName="MyVid"
RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</MediaElement.Triggers>
</MediaElement>
</StackPanel>
</Popup>
_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)
_lvTimer.Start()
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
gv.Columns.Add(gvc)
If coltype <> "String" Then
gvc.Width = 80
Dim XAMLdt = _
<DataTemplate
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
>
<StackPanel Orientation="Horizontal">
<TextBlock Name="tb"
Text=<%= "{Binding Path=" + mem.Name + "}" %>
Foreground="Black"
FontWeight="Bold"
Background="SpringGreen">
</TextBlock>
</StackPanel>
</DataTemplate>
gvc.CellTemplate = System.Windows.Markup.XamlReader.Load(XAMLdt.CreateReader)
Else
gvc.DisplayMemberBinding = New Binding(mem.Name)
gvc.Width = 180
End If
End Select
Next
Dim XAMLlbStyle = _
<Style
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
TargetType="ListBoxItem">
<Setter Property="Foreground" Value="Blue"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="Aquamarine"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
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)
Me.Items.SortDescriptions.Clear()
Dim sd = New System.ComponentModel.SortDescription(sortby, dir)
Me.Items.SortDescriptions.Add(sd)
Me.Items.Refresh()
End Sub
End Class
</Sample Code>
Comments
Anonymous
November 29, 2007
PingBack from http://www.absolutely-people-search.info/?p=1043Anonymous
November 30, 2007
In the last post Create your own media browser: Display your pictures, music, movies in a XAML tooltipAnonymous
November 30, 2007
In the last post Create your own media browser: Display your pictures, music, movies in a XAML tooltipAnonymous
January 05, 2008
PingBack from http://birthdays.247blogging.info/?p=4042Anonymous
March 27, 2008
The comment has been removedAnonymous
August 21, 2008
Today’s digital cameras take pictures with much higher resolution than many computer screens. My Canon