Use the DispatcherTimer, Popup and even a movie to enhance your data presentation
We can subclass the prior Windows Presentation Foundation (WPF) class called Browse that displays the results of a query. This subclass will add a WPF Popup to it.
The popup can easily be added to either a ListView or the ListBox sample I posted earlier (Use LINQ with WPF : Styles and DataTemplates in code)
The code sample below is exactly the same code as the prior Browse post except that it uses a subclass of the Browse class called BrowseWithPopup.
This class has a DispatcherTimer Class (System.Windows.Threading) that delays the opening of the descriptive popup. The timer starts when an item is selected. If it's been selected for, say 200 ms, then the popup displays. Thus, if the user is actively scrolling, no popup shows.
The System.Timers.Timer class runs in a different thread from the UI thread. WPF runs UI and rendering in different threads. See WPF Threading Model.
To add a movie to any UI element is quite simple. To make it repeat after playing once, you need to use the StoryBoard class to animate it. Try making it repeat forever!
<Code Sample>
Imports System.Windows.Controls.Primitives ' for Popup
Partial Public Class Window1
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 proc In System.Diagnostics.Process.GetProcesses _
Select proc.Id, proc.ProcessName, ThreadCount = proc.Threads.Count, proc.MainWindowTitle
'Me.Content = New Browse(Query, Me) ' the Browse will fill the entire window
Me.Content = New BrowseWithPopup(Query, Me)
End Sub
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"
Dim gvc As New GridViewColumn
gvc.Header = mem.Name
gv.Columns.Add(gvc)
If coltype = "Int32" Then
gvc.Width = 80
Dim dt As New DataTemplate
Dim factSP = New FrameworkElementFactory(GetType(StackPanel))
dt.VisualTree = factSP
factSP.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal)
Dim factTb = New FrameworkElementFactory(GetType(TextBlock))
factTb.SetBinding(TextBlock.TextProperty, New Binding(mem.Name))
factTb.SetValue(TextBlock.FontWeightProperty, FontWeights.Bold)
' factTb.SetValue(TextBlock.BackgroundProperty, Brushes.SpringGreen)
factSP.AppendChild(factTb)
'factTb = New FrameworkElementFactory(GetType(Button))
'factTb.SetValue(Button.ContentProperty, "hit me")
'factSP.AppendChild(factTb)
gvc.CellTemplate = dt
Else
gvc.DisplayMemberBinding = New Binding(mem.Name)
gvc.Width = 180
End If
End Select
Next
Dim MyListboxStyle As New Style(GetType(ListBoxItem))
Dim tr = New Trigger
tr.Property = ListBoxItem.IsSelectedProperty ' when Selected
tr.Value = True ' is true
tr.Setters.Add(New Setter(ListBoxItem.ForegroundProperty, Brushes.Bisque))
MyListboxStyle.Triggers.Add(tr)
tr = New Trigger
tr.Property = ListBoxItem.IsMouseOverProperty ' when mouseover
tr.Value = True ' is true
tr.Setters.Add(New Setter(ListBoxItem.ForegroundProperty, Brushes.Red))
tr.Setters.Add(New Setter(ListBoxItem.BackgroundProperty, Brushes.Aquamarine)) ' this trigger sets both fore and back properties
MyListboxStyle.Setters.Add(New Setter(ListBoxItem.ForegroundProperty, Brushes.RoyalBlue)) ' set style for all items
MyListboxStyle.Triggers.Add(tr)
Me.ItemContainerStyle = MyListboxStyle
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
Class BrowseWithPopup
Inherits Browse
Sub New(ByVal Query As Object, Optional ByVal Parent As Object = Nothing)
MyBase.new(Query)
Dim sp As New StackPanel
_lvPopUp.Child = sp
_tbListViewItemDescription.Foreground = Brushes.Black
_tbListViewItemDescription.Background = Brushes.LightYellow
sp.Children.Add(_tbListViewItemDescription)
'Return ' the rest of this method is fluff
Dim btnTest As New Button ' just for fun, let's add a button to the popup tip.
btnTest.Content = "foo"
btnTest.AddHandler(Button.ClickEvent, New RoutedEventHandler(AddressOf HandleClick))
sp.Children.Add(btnTest)
Dim MyVid As New MediaElement ' For more fun, let's add a movie to the popup tip
MyVid.MaxHeight = 100
MyVid.MaxWidth = 100
MyVid.Source = New Uri("d:\tshort.avi") ' change to point to your movie file
sp.Children.Add(MyVid)
End Sub
Sub HandleClick()
MsgBox("You Clicked me!")
End Sub
Dim _lvPopUp As New Popup
Dim WithEvents _lvTimer As New System.Windows.Threading.DispatcherTimer
Dim _tbListViewItemDescription As New TextBlock
Sub HandlePopupTimerTick() Handles _lvTimer.Tick
Dim lbi As ListBoxItem = Me.ItemContainerGenerator.ContainerFromIndex(Me.SelectedIndex)
If Not lbi Is Nothing Then
_lvPopUp.PlacementTarget = lbi
_tbListViewItemDescription.Text = "This is the data: " + vbCrLf + lbi.Content.ToString
_lvPopUp.IsOpen = 1
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)
Dim lbi2 = lb.SelectedItem
If _lvPopUp.IsOpen Then
_lvPopUp.IsOpen = False
End If
_lvTimer.Stop() ' stop prior timer, if any
_lvTimer.Interval = TimeSpan.FromMilliseconds(500)
_lvTimer.Start()
_lvPopUp.AllowsTransparency = True
_lvPopUp.PopupAnimation = PopupAnimation.Fade
_lvPopUp.Placement = PlacementMode.Right
End If
End Sub
End Class
</Code Sample>
Comments
Anonymous
November 28, 2007
Using WPF, it’s great to use declarative XAML , but it’s also great to use dynamic code. With VB’s newAnonymous
November 28, 2007
Using WPF, it’s great to use declarative XAML , but it’s also great to use dynamic code. With VB’s newAnonymous
May 31, 2009
PingBack from http://woodtvstand.info/story.php?id=5570Anonymous
June 08, 2009
PingBack from http://insomniacuresite.info/story.php?id=5453