I have got some Rectangles, what I'm trying to implement is:
user touch the screen, he could slide between Rectangles. then his finger Lift off, and the last touched rectangle is selected.
(Lift off outside rectangle will trigger nothing)
Just like my lumia 920's keyboard, once you recognized that your finger was in a wrong place, you could slide to the right place, lift off, and the right character show on the screen.
many thanks to you heroes!
That's trickier than it seems, as the MouseLeftButtonUp event will be triggered only if the MouseLeftButtonDown has first been triggered on the control.
I see two ways to achieve this result:
Assign the same MouseLeftButtonDown and MouseLeftButtonUp event handler to all your rectangles. In the MouseLeftButtonDown, call the CaptureMouse method (it tells the control to continue tracking the mouse events even if the cursor isn't on top of the control anymore):
private void MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
((UIElement)sender).CaptureMouse();
}
In the MouseLeftButtonDown, release the mouse, then use the VisualTreeHelper.FindElementsInHostCoordinates to find the rectangle on which the cursor was when the even was triggered:
private void MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var element = (UIElement)sender;
element.ReleaseMouseCapture();
var mouseUpRectangle = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(this), this.ContentPanel)
.OfType<Rectangle>()
.FirstOrDefault();
if (mouseUpRectangle != null)
{
Debug.WriteLine("MouseUp in " + mouseUpRectangle.Name);
}
}
(replace ContentPanel by the name of the container in which you've put all your controls)
Not tested but it might work. Subscribe to the MouseLeftButtonUp event of the container in which you've put all your rectangles. Then use the same logic to retrieve the rectangle at the coordinates of the pointer:
private void MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var mouseUpRectangle = VisualTreeHelper.FindElementsInHostCoordinates(e.GetPosition(this), this.ContentPanel)
.OfType<Rectangle>()
.FirstOrDefault();
if (mouseUpRectangle != null)
{
Debug.WriteLine("MouseUp in " + mouseUpRectangle.Name);
}
}
You can find more information in that article I wrote a few months ago.
Related
I have a sound button in my menu screen.It has two images.one is normal and other is checked(indicating sound is OFF).
I am using a boolean variable to get the state of this button.If it is true,sound will play else sound will be OFF.I am using it to control in-game sounds.
public boolean soundBool=true;
created soundButton like this:Here soundTexture1 is normal image(ON) and soundTexture2 has a cross mark(OFF).
private void drawSoundButton() {
soundButton = new ImageButton(new TextureRegionDrawable(soundTexture1),
new TextureRegionDrawable(soundTexture2), new TextureRegionDrawable(soundTexture2));
stage.addActor(soundButton);
soundButton.setPosition(UiConstants.SOUND_X, UiConstants.SOUND_Y, Align.bottom);
soundButton.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
if (!game.buttonClickSoundBool)
buttonClickSound.play();
soundButton.scaleBy(0.025f);
if(game.soundBool)
game.soundBool=false;
else
game.soundBool=true;
}
});
}
I am calling all sounds with play() only when this soundBool is true.
Now when I click this button,crossmark will come,sound will be off and works fine in terms of sound.
Whenever I come back to menu,the image with cross mark should be displayed because the sound is OFF.But it does not shows the cross mark image.It shows the first image.But functionality is fine.If I click,sound will go ON.
It would be helpful if someone explains how to solve this.
Use setChecked(boolean status); on soundButton according to the status of soundBool.
private void drawSoundButton() {
soundButton = new ImageButton(new TextureRegionDrawable(soundTexture1),new TextureRegionDrawable(soundTexture2), new TextureRegionDrawable(soundTexture2));
soundButton.setChecked(!soundBool); // setChecked according to boolean status
stage.addActor(soundButton);
soundButton.setPosition( UiConstants.SOUND_X,UiConstants.SOUND_Y,Align.bottom);
...
}
Also don't forget to save status of soundBool in preference so that you can restore that value, when you come back in your game.
I'm currently developing an Universal Application, but here is a problem. I have a Frame with the TextBox for User Phone Number.
So, I want to change the height of my LayoutRoot (GRID) so it can fits in the free space.
I'm using InputPane.GetForCurrentView().Showing and InputPane.GetForCurrentView().Hiding for that purposes.
Here is my code.
public UserRegistrationAuthorization_PhoneNumber()
{
this.InitializeComponent();
LayoutRootInitialHeight = LayoutRoot.ActualHeight;
InputPane.GetForCurrentView().Showing += UserRegistrationAuthorization_PhoneNumber_Showing;
InputPane.GetForCurrentView().Hiding += UserRegistrationAuthorization_PhoneNumber_Hiding;
}
private void UserRegistrationAuthorization_PhoneNumber_Showing(InputPane sender, InputPaneVisibilityEventArgs args)
{
LayoutRoot.Height = LayoutRoot.ActualHeight - args.OccludedRect.Height;
LayoutRoot.VerticalAlignment = VerticalAlignment.Top;
args.EnsuredFocusedElementInView = true;
}
private void UserRegistrationAuthorization_PhoneNumber_Hiding(InputPane sender, InputPaneVisibilityEventArgs args)
{
// TODO: Get rid of that shit
LayoutRoot.Height = LayoutRootInitialHeight;
args.EnsuredFocusedElementInView = false;
}
When I click outside the TextBox keyboard hides and leaves after that a black hole on the screen. 2
But, the most interesting is that when I press that physical Back Button on my Lumia, keyboard hides normally and my LayoutRoot gets the Frame's initial height.
Is it a bug or I'm doing something wrong?
It happens because by the time you saving your LayoutRootInitialHeight in the constructor, LayoutRoot actually isn't loaded and it's ActualHeight == 0. Then you setting LayoutRoot.Height to 0, so it becomes not visible. So you should probably save your LayoutRootInitialHeight in LayoutRoot's Loaded event handler.
I would also suggest you not to change LayoutRoot's height at all. It causes your whole visual tree to be rendered from scratch and it's bad practise in general. Instead, modify RenderTransform of all necessary elements so they get moved to appropriate positions. RenderTransform is the right way to handle movements and animations on the screen, and you can achieve some nice visual effects with Next button moving up same as keyboard.
Roughly your code can look like this:
<Button Content="Next" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center">
<Button.RenderTransform>
<CompositeTransform x:Name="NextButtonTransform" TranslateY="0"/>
</Button.RenderTransform>
</Button>
...
private void UserRegistrationAuthorization_PhoneNumber_Showing(InputPane sender, InputPaneVisibilityEventArgs args)
{
NextButtonTransform.TranslateY = -300;
EnsuredFocusedElementInView = true;
}
private void UserRegistrationAuthorization_PhoneNumber_Hiding(InputPane sender, InputPaneVisibilityEventArgs args)
{
NextButtonTransform.TranslateY = 0;
args.EnsuredFocusedElementInView = false;
}
And more complicated way is to run some storyboard which makes your Next button move up and down in same speed with keyboard, always appearing on top of it. Although, since InputPane.GetForCurrentView().Showing gets fired after keyboard already shown fully, you should hook up all animations to TextBox.GotFocus and TextBox.LostFocus events. On mobile, keyboard is always shown when text box has focus, so it will work nicely.
Using the new AutoSuggestBox control in Windows Phone 8.1 (WinRT XAML), I am trying to keep the suggestion box open all the time -- even after the user clicks a suggestion.
I have no problem starting with the suggestion box open by programmatically setting AutoSuggestBox.IsSuggestionListOpen = true;
Then I hook the SuggestionChosen event like this:
private void AutoSuggestBox_SuggestionChosen(AutoSuggestBox sender, AutoSuggestBoxSuggestionChosenEventArgs args) {
sender.Text = args.SelectedItem.ToString();
sender.IsSuggestionListOpen = true;
}
But unfortunately the suggestion box still closes after selecting an item, even though I set IsSuggestionListOpen to true.
Any help with getting it to stay open after a selection would be appreciated.
The solution I found to this is to hook the LayoutUpdated event.
I have the AutoSuggestBox in a PickerFlyout, so I only want the suggestion box open if the PickerFlyout is open (obviously). So I set a Tag property on the button that opens the PickerFlyout to identify if the PickerFlyout is open or closed. Then in the LayoutUpdated event of the AutoSuggestBox I set the IsSuggestionListOpen property to true if the PickerFlyout is open (and false if it's not).
The code:
private void PickerFlyout_Opened(object sender, object e) {
ActivatePickerFlyoutButton.Tag = "open";
}
private void PickerFlyout_Closed(object sender, object e) {
ActivatePickerFlyoutButton.Tag = "closed";
}
private void AutoSuggestBox_LayoutUpdated(object sender, object e) {
AutoSuggestBox.IsSuggestionListOpen = ((ActivatePickerFlyoutButton.Tag as string).Equals("open"));
}
That is the only place I need to set the IsSuggestionListOpen property, since the LayoutUpdated event fires at all the right times.
In the WinRt/WP 8.1 MapControl, how do I differentiate between when the user changed the center of the screen by swiping vs a programmatic change?
The WinRt/WP 8.1 MapControl has a CenterChanged event ( http://msdn.microsoft.com/en-us/library/windows.ui.xaml.controls.maps.mapcontrol.centerchanged.aspx ), but this does not provide any info about what caused the center change.
Is there any other way of knowing whether or not the user changed the map center?
/* To give some more context, my specific scenario is as follows:
Given an app which shows a map, I want to track the gps position of a user.
If a gps position is found, I want to put a dot on the map and center the map to that point.
If a gps position change is found, I want to center the map to that point.
If the user changes the position of the map by touch/swipe, I no longer want to center the map when the gps position changes.
I could hack this by comparing gps position and center, but he gps position latLng is a different type & precision as the Map.Center latLng. I'd prefer a simpler, less hacky solution.
*/
I solved this by setting a bool ignoreNextViewportChanges to true before calling the awaitable TrySetViewAsync and reset it to false after the async action is done.
In the event handler, I immediately break the Routine then ignoreNextViewportChanges still is true.
So in the end, it looks like:
bool ignoreNextViewportChanges;
public void HandleMapCenterChanged() {
Map.CenterChanged += (sender, args) => {
if(ignoreNextViewportChanges)
return;
//if you came here, the user has changed the location
//store this information somewhere and skip SetCenter next time
}
}
public async void SetCenter(BasicGeoposition center) {
ignoreNextViewportChanges = true;
await Map.TrySetViewAsync(new Geopoint(Center));
ignoreNextViewportChanges = false;
}
If you have the case that SetCenter might be called twice in parallel (so that the last call of SetCenter is not yet finished, but SetCenter is called again), you might need to use a counter:
int viewportChangesInProgressCounter;
public void HandleMapCenterChanged() {
Map.CenterChanged += (sender, args) => {
if(viewportChangesInProgressCounter > 0)
return;
//if you came here, the user has changed the location
//store this information somewhere and skip SetCenter next time
}
}
public async void SetCenter(BasicGeoposition center) {
viewportChangesInProgressCounter++;
await Map.TrySetViewAsync(new Geopoint(Center));
viewportChangesInProgressCounter--;
}
None of my screen-touch events (ManipulationStarted, MouseLeftButtonDown, MouseMove, Tap etc.) are fired when stopping or reversing a scroll fling on a ScrollViewer. How do I capture a screen-touch event even when this happens?
These events are fired OK after the ScrollViewer has completely stopped flinging, just not when stopping or reversing an existing fling.
EDIT: I need to get the actual element that was touched.
I think you can try to make use of FrameReported event, in which you can read gesture from TouchPanel. Simple example can look like this:
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework;
public MainPage()
{
InitializeComponent();
TouchPanel.EnabledGestures = (GestureType)1023; // read all gestures
Touch.FrameReported += Touch_FrameReported;
}
private void Touch_FrameReported(object sender, TouchFrameEventArgs e)
{
if (TouchPanel.IsGestureAvailable)
{
GestureSample gesture = TouchPanel.ReadGesture();
float Xposition = gesture.Position.X;
float Yposition = gesture.Position.Y;
}
}
Depending on your purpose you can enable some gestures and read various properties from them.