locked
Help with InvokeCommandAction in a Screen Navigation WPF App Test RRS feed

  • Question

  • I am working out a simple navigation system for hiding and showing grids on a single borderless window.  I have a home and back button and a series of buttons that take me to specific grids.  I want to easily go back or the the main screen.  The code below is my test program that works well.   But now I am trying to implement the same concept with a custom slider control and I need to use the Invoke CommandAction in order to get it to work.  I don't understand how to code the ICommand interface to get my Navitation functions to work though.   I would have used the Button Command if I could have figured it out.  That's why I used the Button Click event and the Tag attribute for the parameter.  But now with the slider which doesn't have a Click event and I am using the Tag attribute for its label I need to get the Command working.

    In this demo you should be able to click on any of the buttons on the MAIN SCREEN and it will navigate you to a new screen. Then press the Back or Home buttons to return.  If you click on the text label of the Slider it should do the same thing the buttons do.  

    Code Behind

    Class MainWindow 
    
    	Private Sub Window_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs)
            Me.DragMove()
        End Sub
    	
        Private Sub ExitButton_Click(sender As Object, e As RoutedEventArgs)
    		Application.Current.Shutdown()
        End Sub
    
    	Dim Screens as New List(Of String)
    
    	Private Sub NavigateToScreen(sender As Object, e As RoutedEventArgs)
    		Screens.Add(sender.tag)
    		ShowHideScreen(sender.tag,True)
    	End Sub
    
    	Private Sub NavigateToScreenName(ScreenName as String)
    		Screens.Add(ScreenName)
    		ShowHideScreen(ScreenName,True)
    	End Sub
    
    	Private Sub NavigateBack(Sender As Object, e As RoutedEventArgs)
    		If Screens.Count > 0 Then
    			ShowHideScreen(Screens(Screens.Count-1),False)
    			Screens.Remove(Screens(Screens.Count-1))
    		End If
    	End Sub
    
    	Private Sub NavigateHome(Sender As Object, e As RoutedEventArgs)
    		do while screens.count > 0
    			ShowHideScreen(Screens(Screens.Count-1),False)
    			Screens.Remove(Screens(Screens.Count-1))
    		loop 
    	End Sub
    
    	Private Sub ShowHideScreen(ScreenName as String,ShowHide as Boolean)
    		Dim GridObject as Object =  LayoutRoot.FindName(ScreenName)
    		If GridObject IsNot Nothing Then
            	GridObject.Visibility = IIf(ShowHide, Visibility.Visible, Visibility.Hidden)
    			GridObject.Opacity = iif(ShowHide,100,0)
    		End If
    	
    	End Sub
    End Class

    XAML

    <Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	xmlns:local="clr-namespace:TestGrid" 
    	xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
    	xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
    	x:Class="MainWindow"
        Title="MainWindow" MouseLeftButtonDown="Window_MouseLeftButtonDown" Height="778" Width="1376" Background="Transparent" WindowStyle="None" AllowsTransparency="True">
    	<Window.Resources>
    		<Style x:Key="SliderStyle1" TargetType="{x:Type Slider}">
    			<Setter Property="Template">
    				<Setter.Value>
    					<ControlTemplate TargetType="{x:Type Slider}">
    						<Grid >
    							<Frame BorderBrush="White" BorderThickness="2" Margin="52.857,335.714,1022.857,335.143" />
    							<Slider x:Name="slider" Width="248.571" VerticalAlignment="Top" Margin="72.857,394.285,0,0" Height="48.572" HorizontalAlignment="Left" Maximum="100" SmallChange="1" IsSnapToTickEnabled="True"/>
    							<Button Tag="{TemplateBinding Tag}" HorizontalAlignment="Left" Height="37.207" Margin="72.857,352.078,0,0" Style="{DynamicResource ButtonStyle1}" VerticalAlignment="Top" Width="156"/>
    							<Label Width="53.214" VerticalAlignment="Top" Margin="268.214,352.078,0,0" Height="37.207" HorizontalContentAlignment="Right" HorizontalAlignment="Left" FontSize="16" Foreground="White" >
    								<TextBlock DataContext="{Binding Value, ElementName=slider}" Text="{Binding StringFormat=\{0\}%}"/>
    							</Label>
    						</Grid>
    					</ControlTemplate>
    				</Setter.Value>
    			</Setter>
    		</Style>
    		<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
    			<Setter Property="Template">
    				<Setter.Value>
    					<ControlTemplate TargetType="{x:Type Button}">
    						<Grid>
    							<Label Content="{TemplateBinding Tag}" Foreground="White" FontSize="16"/>
    						</Grid>
    						<ControlTemplate.Triggers>
    							<Trigger Property="IsFocused" Value="True"/>
    							<Trigger Property="IsDefaulted" Value="True"/>
    							<Trigger Property="IsMouseOver" Value="True"/>
    							<Trigger Property="IsPressed" Value="True"/>
    							<Trigger Property="IsEnabled" Value="False"/>
    						</ControlTemplate.Triggers>
    					</ControlTemplate>
    				</Setter.Value>
    			</Setter>
    		</Style>
    	</Window.Resources>
    	<Grid x:Name="LayoutRoot">
    		<Grid x:Name="Main_Screen" Background="Blue">
    			<Label Content="MAIN SCREEN" FontSize="48" Foreground="White"  HorizontalAlignment="Center" VerticalAlignment="Center" />
    			<Button Content="Projects" Tag="Projects_Screen" Click="NavigateToScreen" HorizontalAlignment="Left" Height="41.364" Margin="302.857,214.285,0,0" VerticalAlignment="Top" Width="90"/>
    			<Button Content="Player" Tag="Player_Screen" Click="NavigateToScreen"  HorizontalAlignment="Left" Height="42" Margin="428.571,214.285,0,0" VerticalAlignment="Top" Width="80"/>
    			<Button Content="System" Tag="System_Screen" Click="NavigateToScreen"  HorizontalAlignment="Left" Height="42" Margin="552.857,214.285,0,0" VerticalAlignment="Top" Width="80"/>
    			<Button Content="Set EQ" Tag="EQ_Screen" Click="NavigateToScreen"  HorizontalAlignment="Left" Height="42" Margin="668.571,214.285,0,0" VerticalAlignment="Top" Width="80"/>
    			<Slider Tag="VOICE"  Style="{DynamicResource SliderStyle1}" >
    				<i:Interaction.Triggers>
    					<local:RoutedEventTrigger Event="{x:Static ButtonBase.ClickEvent}" >
    						<i:InvokeCommandAction Command="{Binding NavigateToScreenName}" CommandParameter="Voice_Setup"/>
    					</local:RoutedEventTrigger>
    				</i:Interaction.Triggers>
    			</Slider>					
    		</Grid>
    		<Grid x:Name="Player_Screen" Background="Red" Opacity="0" Visibility="Hidden">
    			<Label Content="Player Audio" FontSize="48" Foreground="White"  HorizontalAlignment="Center" VerticalAlignment="Center" />
    		</Grid>
    		<Grid x:Name="Projects_Screen" Background="Green" Opacity="0" Visibility="Hidden">
    			<Label Content="Projects SCREEN" FontSize="48" Foreground="White"  HorizontalAlignment="Center" VerticalAlignment="Center" />
    		</Grid>
    		<Grid x:Name="Settings_Screen" Background="Purple" Opacity="0" Visibility="Hidden">
    			<Label Content="Settings SCREEN" FontSize="48" Foreground="White"  HorizontalAlignment="Center" VerticalAlignment="Center" />
    		</Grid>
    		<Grid x:Name="System_Screen" Background="Cyan" Opacity="0" Visibility="Hidden">
    			<Label Content="System SCREEN" FontSize="48" Foreground="White"  HorizontalAlignment="Center" VerticalAlignment="Center" />
    		</Grid>
    		<Grid x:Name="EQ_Screen" Background="Orange" Opacity="0" Visibility="Hidden">
    			<Label Content="Set EQ" FontSize="48" Foreground="White"  HorizontalAlignment="Center" VerticalAlignment="Center" />
    		</Grid>
    		<Grid x:Name="Voice_Setup" Background="Gray" Opacity="0" Visibility="Hidden">
    			<Label Content="Voice Setup" FontSize="48" Foreground="White"  HorizontalAlignment="Center" VerticalAlignment="Center" />
    		</Grid>
    		<Button Content="Back" Click="NavigateBack" HorizontalAlignment="Left" Height="35" Margin="10,10,0,0" VerticalAlignment="Top" Width="60"/>
    		<Button Content="Home" Click="NavigateHome" HorizontalAlignment="Left" Height="35" Margin="90,10,0,0" VerticalAlignment="Top" Width="60"/>			
    		<Button Content="Settings" Tag="Settings_Screen" Click="NavigateToScreen"  HorizontalAlignment="Left" Height="35" Margin="170,10,0,0" VerticalAlignment="Top" Width="60"/>
    		<Button Content="Exit" Click="ExitButton_Click" HorizontalAlignment="Left" Height="35" Margin="1274.286,10,0,0" VerticalAlignment="Top" Width="60" />
    	</Grid>
    </Window>
    

    RoutedEventTrigger Class which is only needed to bubble up the Button Click event from the custom Slider.  

    Imports System
    Imports System.IO
    Imports System.Windows
    Imports System.Windows.Controls
    Imports System.Windows.Data
    Imports System.Windows.Media
    Imports System.Windows.Media.Animation
    Imports System.Windows.Interactivity
    
    Public Class RoutedEventTrigger
        Inherits TriggerBase(Of UIElement)
    		Public Property [Event]() As RoutedEvent
    			Get
    				Return DirectCast(GetValue(EventProperty), RoutedEvent)
    			End Get
    			Set
    				SetValue(EventProperty, value)
    			End Set
    		End Property
    
    		Public Shared ReadOnly EventProperty As DependencyProperty = DependencyProperty.Register("Event", GetType(RoutedEvent), GetType(RoutedEventTrigger), New PropertyMetadata(Nothing, AddressOf OnEventNameChanged))
    
    		Public Property MarkHandled() As Boolean
    			Get
    				Return CBool(GetValue(MarkHandledProperty))
    			End Get
    			Set
    				SetValue(MarkHandledProperty, value)
    			End Set
    		End Property
    
    		Public Shared ReadOnly MarkHandledProperty As DependencyProperty = DependencyProperty.Register("MarkHandled", GetType(Boolean), GetType(RoutedEventTrigger), New PropertyMetadata(True))
    
    		Protected Overrides Sub OnAttached()
    			MyBase.OnAttached()
    
    			Me.SubscribeEvent(Me.[Event])
    		End Sub
    
    		Private Sub SubscribeEvent(eventName As RoutedEvent)
    			If Me.AssociatedObject IsNot Nothing AndAlso eventName IsNot Nothing Then
    				Me.AssociatedObject.[AddHandler](eventName, New RoutedEventHandler(AddressOf Me.EventHandler))
    			End If
    		End Sub
    
    		Private Sub EventHandler(sender As Object, e As RoutedEventArgs)
    			If Me.MarkHandled Then
    				e.Handled = True
    			End If
    			Me.InvokeActions(sender)
    		End Sub
    
    		Protected Overrides Sub OnDetaching()
    			MyBase.OnDetaching()
    
    			Me.UnsubscribeEvent(Me.[Event])
    		End Sub
    
    		Private Sub UnsubscribeEvent(eventName As RoutedEvent)
    			If Me.AssociatedObject IsNot Nothing AndAlso eventName IsNot Nothing Then
    				Me.AssociatedObject.[RemoveHandler](eventName, New RoutedEventHandler(AddressOf Me.EventHandler))
    			End If
    		End Sub
    
    		Private Shared Sub OnEventNameChanged(sender As Object, args As DependencyPropertyChangedEventArgs)
    			DirectCast(sender, RoutedEventTrigger).OnEventNameChanged(DirectCast(args.OldValue, RoutedEvent), DirectCast(args.NewValue, RoutedEvent))
    		End Sub
    
    		Friend Sub OnEventNameChanged(oldEventName As RoutedEvent, newEventName As RoutedEvent)
    			Me.UnsubscribeEvent(oldEventName)
    			Me.SubscribeEvent(newEventName)
    		End Sub
    
    End Class
    


    Jeff Davis

    Thursday, July 11, 2013 1:02 AM

All replies

  • Decided to go another route and keep it simple.   I removed the RouteEventTrigger class.   I changed my slider template to use the Name property for the label and used Tag for the grid name like the buttons.  I added the Click Event to the Button within the template.

    Template changes

    		<Style x:Key="SliderStyle1" TargetType="{x:Type Slider}">
    			<Setter Property="Template">
    				<Setter.Value>
    					<ControlTemplate TargetType="{x:Type Slider}">
    						<Grid >
    							<Frame BorderBrush="White" BorderThickness="2" Margin="52.857,335.714,1022.857,335.143" />
    							<Slider x:Name="slider" Width="248.571" VerticalAlignment="Top" Margin="72.857,394.285,0,0" Height="48.572" HorizontalAlignment="Left" Maximum="100" SmallChange="1" IsSnapToTickEnabled="True"/>
    							<Button Content="{TemplateBinding Name}" Click="NavigateToScreen" Tag="{TemplateBinding Tag}" HorizontalAlignment="Left" Height="37.207" Margin="72.857,352.078,0,0" Style="{DynamicResource ButtonStyle1}" VerticalAlignment="Top" Width="156"/>
    							<Label Width="53.214" VerticalAlignment="Top" Margin="268.214,352.078,0,0" Height="37.207" HorizontalContentAlignment="Right" HorizontalAlignment="Left" FontSize="16" Foreground="White" >
    								<TextBlock DataContext="{Binding Value, ElementName=slider}" Text="{Binding StringFormat=\{0\}%}"/>
    							</Label>
    						</Grid>
    					</ControlTemplate>
    				</Setter.Value>
    			</Setter>
    		</Style>

    Xaml changes

    			<Slider x:Name="VOICE" Tag="Voice_Setup"  Style="{DynamicResource SliderStyle1}" />


    Jeff Davis

    Friday, July 12, 2013 12:48 AM