Windows Phone: NavigateToAction sometimes reinitializes view, sometimes not - c#

I've tried to solve the following problem for several hours now:
I'm developing a game, where I have to switch between several views. When I'm in the game view, at the end there is a button called "Return match" which navigates back to the "PlayerSelectView" where the players are set up:
<Button Tag="{Binding Source={StaticResource Options}, Path=Effect}" Width="300" MinHeight="70">
<localControls:DropShadowTextBlock Text="{Binding LocalizedText.GV_ReturnMatch}"/>
<i:Interaction.Triggers>
<ic:DataTrigger Binding="{Binding Result, ElementName=MessageBoxBehavior}" Value="OK">
<i:InvokeCommandAction Command="{Binding NewGameCommand}" />
<ic:NavigateToPageAction TargetPage="/Views/PlayerSelectView.xaml" />
</ic:DataTrigger>
</i:Interaction.Triggers>
<i:Interaction.Behaviors>
<behaviors:MessageBoxBehavior x:Name="MessageBoxBehavior" Text="{Binding LocalizedText.MAIN_YouWillLoseYourPreviousGame}" IsEnabled="{Binding IsGameInitialized}" />
</i:Interaction.Behaviors>
</Button>
The NewGameCommand doesn't reset the players list in the PlayerSelectViewModel.
At this time the constructor of PlayerSelectView and the constructor in the PlayerSelectViewModel is not called, so it preserves the state, as it should be, but, going back to the menu during the game with this code:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
GameViewModel.Instance.GameIsPaused = true;
NavigationService.Navigate(new Uri("/Views/MainPageView.xaml", UriKind.Relative));
}
and after that going back to the GameView with the Continue button:
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="{Binding IsGameInitialized, Converter={StaticResource BoolToVisibilityConverter}}" Tag="{Binding Source={StaticResource Options}, Path=Effect}" Width="300" MinHeight="70" FontWeight="Normal">
<localControls:DropShadowTextBlock Text="{Binding LocalizedText.MAIN_Continue}"/>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<ic:NavigateToPageAction TargetPage="/Views/GameView.xaml" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
When I now hit "Return Match", the PlayerSelectView always gets reinitialized!
Why does it now reinitialize the PlayerSelectView? The other thing is, that when the new players are set up again and the game is started, it just returns to the Game Over screen (which is a popup layer on the GameView).
Does anyone have an idea what to do?
UPDATE:
When the game starts, the MainView is shown. From there the user is taken to the PlayerSelectView with this button:
<Button Tag="{Binding Source={StaticResource Options}, Path=Effect}" Width="300" MinHeight="70">
<localControls:DropShadowTextBlock Text="{Binding LocalizedText.MAIN_NewGame}"/>
<i:Interaction.Triggers>
<ic:DataTrigger Binding="{Binding Result, ElementName=MessageBoxBehavior}" Value="OK">
<i:InvokeCommandAction Command="{Binding NewGameCommand}" />
<ic:NavigateToPageAction TargetPage="/Views/PlayerSelectView.xaml" />
</ic:DataTrigger>
</i:Interaction.Triggers>
<i:Interaction.Behaviors>
<behaviors:MessageBoxBehavior x:Name="MessageBoxBehavior" Text="{Binding LocalizedText.MAIN_YouWillLoseYourPreviousGame}" IsEnabled="{Binding IsGameInitialized}" />
</i:Interaction.Behaviors>
</Button>
Here players are created and edited. The game starts with this button:
<Button Command="{Binding StartGameCommand}" CommandParameter="{Binding NavigationService, ElementName=PlayerSelectViewControl}" Tag="{Binding Source={StaticResource Options}, Path=Effect}" Padding="0">
<localControls:DropShadowTextBlock Text="{Binding LocalizedText.PLSEL_StartGame}"/>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<ic:NavigateToPageAction TargetPage="/Views/GameView.xaml"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
...which runs this code as well:
private void StartGame()
{
BusinessLogic.GameLogic.Initialize(new List<Player>(Players));
}
From there, the user can go back to the MainView (menu), exit the game (the state is preserved) or change options.

Related

The KeyDown event will not fire, but the exact same code with PreviewMouseLeftButtonDown event will

I am currently working with WPF to create a simple minigame which requires pressing keys. I have done something similar with mouse clicking, yet I am struggling with keys. I have searched for a quite some time and I have found out that the most common way to work with keys is to define each key to its own event. But thats not my case and I want it to be able to fire it everytime any key is pressed. I have found out that this is possible to be done with MVVMLight and EventToCommand, but for some uknown reason to me, the KeyDown event will not fire (neighter KeyUp), but PreviewMouseLeftButtonDown will do.
xaml file:
<i:Interaction.Triggers>
// will not fire
<i:EventTrigger EventName="KeyDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
// will not fire
<i:EventTrigger EventName="PreviewKeyDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
// will fire
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
ViewModel:
public DelegateCommand onKeyDown
{
get
{
MessageBox.Show("Down");
return new DelegateCommand(() => MessageBox.Show("Down"));
}
}
(full xaml file)
<UserControl x:Class=".......AsteroidsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
Background="{DynamicResource ThemeBackgroundColor}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="PreviewKeyDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
<i:EventTrigger EventName="PreviewMouseLeftButtonDown">
<cmd:EventToCommand Command="{Binding onKeyDown, Mode=OneWay}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source=".......Module.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="100" />
<RowDefinition Height="200*" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="100*" />
<ColumnDefinition Width="100*" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0"
Style="{StaticResource ReturnBackButtonStyle}"
Command="{Binding ReturnFromSearchingCommand, Mode=OneWay}" />
<TextBlock Grid.Row="1" Grid.Column="1"
Text="Game"
FontSize="48"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<TextBlock Grid.Row="1" Grid.Column="2"
Text="Controls"
FontSize="48"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Canvas Grid.Row="2" Grid.Column="1"
Background="LightBlue"
Name="MyCanvas"
Focusable="True">
<Rectangle Name="player" Height="50" Width="60" Fill="Yellow" Canvas.Left="222" Canvas.Top="495"/>
<Label Name="scoreText" Content="Score: 0" FontSize="18" FontWeight="Bold" Foreground="White"/>
<Label Name="damageText" Content="Damage: 0" FontSize="18" FontWeight="Bold" Canvas.Right="0" Foreground="White"/>
</Canvas>
</Grid>
</UserControl>
Thanks in advance!
EDIT + UPDATE 1:
I have tried to force it and I have noticed something strange.
<UserControl.InputBindings>
<KeyBinding Key="Delete"
Command="{Binding onKeyDown, Mode=OneWay}" />
</UserControl.InputBindings>
Using the code above, I am still UNABLE to fire the onKeyDown event. I have no idea why, but I think its something a way way deeper in the code
There is a PreviewKeyDown event that you can try. The most common reason why it won't work with KeyDown and MouseDown is that the control already handles key presses and mouse interactions internally.
The PreviewKeyDown event will only be fired when the control is focused so you'll also have to set the Focusable property of the UserControl to true.
A better way to make sure that you always capture keypresses in a UserControl would be to handle the keypress event of the parent window programmatically:
public partial class AsteroidsView : UserControl
{
public AsteroidsView()
{
InitializeComponent();
Loaded += AsteroidsView_Loaded;
}
private void AsteroidsView_Loaded(object sender, RoutedEventArgs e)
{
Window parentWindow = Window.GetWindow(this);
parentWindow.PreviewKeyDown += ParentWindow_PreviewKeyDown;
}
private void ParentWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{
//TODO: handle...
}
}
Just in case someone needs the "handle" part, I have noticed that the core problem I had was that I had a different window focused. So, what I have done is that I have focused the keyboard to the Canvas that I needed and those events work like a charm. Here is a code:
public partial class AsteroidsView : UserControl
{
public AsteroidsView()
{
InitializeComponent();
Loaded += AsteroidsView_Loaded;
}
private void AsteroidsView_Loaded(object sender, RoutedEventArgs e)
{
Window parentWindow = Window.GetWindow(this);
parentWindow.PreviewKeyDown += ParentWindow_PreviewKeyDown;
}
private void ParentWindow_PreviewKeyDown(object sender, KeyEventArgs e)
{
Keyboard.Focus(this.MyCanvas); // `this` keyword is redundant
}
}
So, mm8 gave a correct solution, there was just this small piece of a missing puzzle for me. The missing piece of this puzzle was found here -> https://social.msdn.microsoft.com/Forums/vstudio/en-US/20d7dc78-53a0-494a-a3cc-b463a23b8196/keydown-does-not-get-fired-up?forum=wpf where I noticed that you need to have the element you want to use focused and visible

Setting IsChecked property to true/false doesn't fire checked/unchecked events in wpf

I have the following code. No checked/ unchecked event is fired when PlayVideoState value is set to true/false. Does anything missing? please suggest.
<CheckBox Style="{DynamicResource PlayButton}" Margin="6" Name="PlayButton" IsChecked="{Binding _Extensions.PlayVideoState, Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<ei1:GoToStateAction StateName="VideoOn"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<ei1:GoToStateAction StateName="VideoOff"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<TextBlock x:Name="textBlock2" FontFamily="{DynamicResource FontFamily1}" Foreground="{DynamicResource Text01}" Margin="0" VerticalAlignment="Center" FontSize="21.333"><Run Language="en-gb" Text="Video"/></TextBlock>
</CheckBox>

XAML Hub Control Windows 8.1 Universal, InvokeCommandAction not firing

I have a hub control on my main page and in the HubSection header i cant get the element to fire when i click on the button, however when i move the XAML into the DataTemplate the event if fired. Can you please explain to me why this is, do i need to enable something in the HubSection.Header so that the event can fire?
here is the code that doesn't fire:
<HubSection >
<HubSection.Header>
<StackPanel >
<TextBlock
Text="{Binding
WhatToWatch.Name,
Mode=OneWay}" />
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Tapped">
<core:InvokeCommandAction
Command="{Binding ViewMoreCommand}"
CommandParameter="{Binding WhatToWatch.Name}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</StackPanel>
</HubSection.Header>
<DataTemplate>
<controls:RowGridView
ItemsSource="{Binding
WhatToWatch.Data,
Mode=TwoWay}" />
</DataTemplate>
</HubSection>
And here is the code that does fire the Event:
<DataTemplate>
<StackPanel >
<StackPanel >
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Tapped">
<core:InvokeCommandAction Command="{Binding ViewMoreCommand}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
<TextBlock
Text="{Binding
WhatToWatch.Name,
Mode=OneWay}" />
</StackPanel>
<controls:RowGridView
ItemsSource="{Binding
WhatToWatch.Data,
Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</HubSection>
Its the same code, but in the second one the core:InvokeCommandAction action is in the DataTemplate, is this what allows the XAML to call the event? why is this so?
You have to put a reference to your page that owns the ViewModel.
Set a name for your page for example: "pageRoot"
then change your Behavior to
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="Tapped">
<core:InvokeCommandAction Command="{Binding DataContext.ViewMoreCommand, ElementName=pageRoot}" />
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>

Windows Phone 7 - Can not trigger the event from ViewModel.

I want to write the event for list box from View Model. I try like this:-
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Gray" Padding="5" BorderThickness="1">
<StackPanel Orientation="Horizontal">
<Border BorderBrush="Wheat" BorderThickness="1">
<Image Name="ListPersonImage" Source="{Binding PersonImage}" Height="100" Width="100" Stretch="Uniform" Margin="10,0,0,0"/>
</Border>
<TextBlock Text="{Binding FirstName}" Name="firstName" Width="200" Foreground="White" Margin="10,10,0,0" FontWeight="SemiBold" FontSize="22" />
<Button DataContext="{Binding DataContext, ElementName=listBox1}" Command="{Binding addPerson}" Height="80" Width="80" >
<Button.Background>
<ImageBrush ImageSource="{Binding imagePath, Converter={StaticResource pathToImageConverter}}" Stretch="Fill" />
</Button.Background>
</Button>
</StackPanel>
</Border>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<i:InvokeCommandAction Command="{Binding ItemSelectedCommand,Mode=OneWay}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My ViewModel:-
public RelayCommand<MVVMListBoxModel> ItemSelectedCommand { get; private set; }
public MVVMListBoxViewModel()
{
ItemSelectedCommand = new RelayCommand<MVVMListBoxModel>(ItemSelected);
}
private void ItemSelected(MVVMListBoxModel myItem)
{
MessageBox.Show("Name==>" + myItem.FirstName);
//throw new NotImplementedException();
}
But nothing happening. Please let me know where I did mistake.
Thanks in advance.
Check output window to see if you got binding error. It seems that you got one, because you have ItemSelectedCommand defined in MVVMListBoxViewModel but ListBoxItem's DataContext is corresponding MVVMListBoxModel, so binding engine couldn't find the command.
Try to move definition of ItemSelectedCommand to MVVMListBoxModel and see if message box get displayed this way.
Do you want the trigger to be upon the SelectionChanged of the Listbox Item? Then the trigger should be outside the <ListBox.ItemTemplate> ... </ListBox.ItemTemplate>.
And the trigger should bind the CommandParamter to the SelectedItem
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<i:InvokeCommandAction Command="{Binding ItemSelectedCommand,Mode=OneWay}" CommandParameter="{Binding SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>

WPF MVVM Checkbox stop Command from firing on Data Bind

I have WPF MVVM application and I am currently trying to use a Checkbox that is bound to a column in a list that it is bound to. I have a EventTriggers set and the command bound to the VM. Everything fires great....Except I do NOT want the events to fire when populated from the list, ONLY when the user checks or unchecks the checkbox. See Code:
<StackPanel Orientation="Vertical" Background="Transparent" DockPanel.Dock="Right" Margin="2,0" VerticalAlignment="Center">
<Label Content="Active" />
<CheckBox x:Name="CbArchiveAoi" VerticalAlignment="Center" HorizontalAlignment="Center" FlowDirection="RightToLeft" IsChecked="{Binding Path=PatientAoi.AoiIsActive}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding ArchiveAoiCommand, Mode=OneWay}"
CommandParameter="{Binding ElementName=CbArchiveAoi}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding ArchiveAoiCommand, Mode=OneWay}" CommandParameter="{Binding ElementName=CbArchiveAoi}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</StackPanel>
public ICommand ArchiveAoiCommand
{
get { return new RelayCommand<object>(ArchiveAoiExecute, AlwaysTrueCanExecute); }
}
private void ArchiveAoiExecute(object obj)
{
string dddd = obj.ToString();
}
I'd remove the Interaction.Triggers and use the CheckBox.CommandandCommandParameter properties instead.
<CheckBox x:Name="CbArchiveAoi"
VerticalAlignment="Center"
<-- snip -->
Command="{Binding ArchiveAoiCommand, Mode=OneWay}"
CommandParameter="{Binding ElementName=CbArchiveAoi}" />

Categories

Resources