I have a StackPanel (menu) in my View and Show this control when user click a button in application bar.
I would like to LostFocus the StackPanel it closed but it does not work, you do not event triggers
XAML
<StackPanel x:Name="StackMenu" Background="{StaticResource PhoneAccentBrush}"
Orientation="Vertical"
Visibility="{Binding StackPanel_IsVisible, Mode=TwoWay,
Converter={StaticResource BooleanToVisibilityConverter}}"
LostFocus="StackMenu_LostFocus">
</StackPanel>
C#
private void StackPanel_LostFocus(object sender, RoutedEventArgs e)
{
}
The LostFocus event is only raised when other controls outside the (StackPanel in this situation) receives focus.
Example:
In the view you have your StackPanel and some TextBlock controls.
In this case the LostFocus event will not be raised since TextBlock cannot gain Focus
In the view you have your StackPanel and some TextBox controls or other input enabled controls.
In this case the LostFocus event will be raised as soon as one of the other controls gains Focus.
Note:
If you don't have any TextBox controls, there is a workaround by catching the Tap event on the Container of the StackPanel:
When a Tap event occurs in the container, and the position is also in the StackPanel area, the StackPanel will catch the event and will not propagate it to the container.
When the Tap occurs outside of the StackPanel it will only be raised on the container or other controls present in the container (this is when your StackPanel loses Focus).
Related
To make a chat page, I followed an example I found that sets the ListView rotation to 180, so the list builds from the bottom and then set things in the DataTemplate to rotate 180, so the items will be upright. It's a great solution, but when the keyboard opens, the ListView gets shorter which causes a redraw. During the redraw, the ListView initially appears with rotation 0 and I see an animation as if RotateTo(360) is being called. After initially displaying, I get to watch the list view rotate around in full circle. Click off the message editor, and the ListView gets taller, and it does it again.
Has anyone seen this?
Here's what the Xaml looks like. I can't make a gif of what it looks like, but imagine watching:
MessageList.Rotation = 0;
MessageList.RotateTo(360, 500, Easing.Linear);
each time the keyboard shows and hides, and you'll get the idea...
<ListView
X:Name="MessageList"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1"
Rotation="180"
ItemsSource="{Binding ChatMessages}"
SelectionMode="None"
HasUnevenRows="True"
SeparatorColor="Transparent">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame
BackgroundColor="LightGray"
FlowDirection="LeftToRight"
Rotation="180"
Padding="10"
HasShadow="false"
Margin="80,2,0,5">
<Label Text="{Binding ChatText}"/>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I followed the same tutorial you mentioned and you are probably using a ContentPage renderer to handle your keyboard layout updates on iOS. If you check the sample project https://github.com/rdelrosario/ChatUIXForms you'll notice he resizes the keyboard ContentView with a ContentView renderer for the Editor box at the bottom using the Margin property, rather than the entire ContentPage. Which doesn't trigger the above issue.
What I wound up doing was to make a custom ListView renderer that was keyboard aware in iOS and sets a translation X to move the top of the listview up when the keyboard appears and back down when it goes away. As a result, the listview is not getting resized, and thus does not redraw.
It may be messy, but it makes it work...
I'm trying to test touchscreen of a tablet (Surface) and therefore I'm developing an app that is able to detect tap event and tell its coordinates.
I made a tap event handler to main Grid in MainPage and wrote this to MainPage.xaml.cs:
outputText.Text = e.GetPosition(this).X.ToString() + "\t";
outputText.Text += e.GetPosition(this).Y.ToString();
outputText is just a TextBlock to output coordinates.
This code should give its coordinates based on Grid, but it only gives coordinates if I touch it within TextBlock area.
How does this Tapped event handler work in a way that it only detects tap events inside TextBlock and not from entire screen (app runs in fullscreen mode)?
My MainPage.xaml looks like this:
<Grid Tapped="Grid_Tapped" PointerPressed="Grid_PointerPressed">
<TextBlock x:Name="outputText" HorizontalAlignment="Left" Height="62" Margin="806,374,0,0" Text="TextBlock" TextWrapping="Wrap" VerticalAlignment="Top" Width="182"/>
</Grid>
The problem is that the Grid.Background is null, so the tap events pass through it. The only place where the Grid has any actual "surface" is the TextBlock, which is exactly what you are seeing.
You will have to set the background to any other value like Transparent. This way it will handle the events properly.
In my nativescript app I noticed that sometimes the tap does not trigger right a way. I have to tap several times to trigger the event. This happens on both, android and ios.
How can I increase the tap hot zone? What else could be causing this to happen?
Thank you.
P.S. I tried increasing the padding of the element whose tap event I am capturing, but that did not seem to help.
I often increase the height and width of the view that have the tap event. You can give it a try.
There are a few factors at play here.
First, when you intercept a page-level event in NativeScript it seems to stop events from other widgets from firing. For example, if you tap on a text field but have a page-level listener for tap events, the tap on the TextField will be intercepted by the page-level listener.
Second, Double-tapping seems to exploit a timing issue in events, allowing the tap event to bubble up to the next listening widget.
Finally, when you have padding on the element you're trying to tap, the tap does not register on the padded areas. It will appear that you can only tap in the middle of the widget (inside of the padded area). In my case, the TextField on which I had padding had to be tapped directly in the vertical center (and that was with a padding of 5px).
To test it, try removing the padding from the element and see if the tapping works normally again.
I was able to create a very smooth / natural experience with the software keyboard by doing the following:
Wrap the TextField in a StackLayout and putting padding on the StackLayout instead of the widget
Add the page-level listener that dismisses the software keyboard ONLY when the textfield is tapped, and remove it once that listener is fired.
ex: XML file
<StackLayout id="loginFieldWrapper" padding="5 5 5 5">
<TextView hint="Enter Login ID" id="loginField" keyboardType="number" returnKeyType="done" returnPress="{{hideKeyboard}}" />
</StackLayout>
Backing javascript file
loginField.on(gestures.GestureTypes.tap, function(args) {
page.on(gestures.GestureTypes.tap, function (args) {
loginField.dismissSoftInput();
page.off(gestures.GestureTypes.tap);
});
});
Wrap the item inside some layout to increase the clickable area
<StackLayout (tap)="select(param)">
<Label text="{{description}}" textWrap="true" marginTop="40px" marginBottom="40px">
</Label>
</StackLayout>
I have a page with two text boxes, a check box and another two text boxes below at the bottom.
When I click on the check box, i want to set focus to the text box below it.
This works fine, the soft-keyboard appears and the screen scrolls up to reveal the text box above the keyboard.
However, if either TextBox1 or TextBox2 is currently in focus and the keyboard is already showing, setting focus from the CheckBox_Click event will reset the screen and it scrolls back down.
I'm guessing that the events clash with one another
- TextBox loses focus and hides the keyboard + scroll the screen back down
- TextBox got focus from outside and shows the keyboard (but doesn't scroll the screen up)
Can this be prevented somehow?
Here's a simplified version of the xaml and code
The xaml:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel Margin="0,100,0,0">
<TextBox x:Name="TextBox1" />
<TextBox x:Name="TextBox2" />
<CheckBox Content="Click Me" Click="CheckBox_Click" />
<TextBox x:Name="TextBox3" />
<TextBox x:Name="TextBox4" />
</StackPanel>
</Grid>
the code behind:
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
TextBox3.Focus();
}
The problem you have is that the OS will try and move the page when the focus is on a control that isn't in a scrollable container and is obscured by the SIP.
I've worked around this by putting all the content in a ScrollViewer and adjusting the VerticalScrollOffset based on the selected control and if the SIP is shown or not. This was a lot of very messy, fiddely code. Ask yourself if the value of moving the focus is worth the effort before starting as there isn't a simple solution.
I've got a ListBox (dynamically populated via code):
(i can't insert the code, bah)
I need, with a button, to move this listbox vertically. The listbox have a fixed height, and also the items.
Can someone help me?
Per MSDN, it looks like this is a viable answer for you?
ListBox.ScrollIntoView Method
Edit - Comment Summary of Answer: The question here was targetting scrolling itself, not to a particular object. As such, the necessary action was to attain a reference to the ListBox's ScrollViewer. From there, a call needed to be placed to the ScrollViewer's ScrollToVerticalOffset method. As the OP wanted to scroll down a certain amount from the original position, the ScrollViewer's VerticalOffset property was incorporated into the call.
This works. Set the ListBox to not scroll, then add a ScrollViewer around it. Now in your code behind you can set the ScrollViewer to whatever you want.
XAML:
<!--Disable the ListBox scroll and add a ScrollViewer so we have control over the scroll position.-->
<ScrollViewer
Name="scrlvwrListBoxMessages"
VerticalScrollBarVisibility="Auto" >
<ListBox x:Name="lstbxMessages"
ScrollViewer.VerticalScrollBarVisibility="Disabled" >
</ListBox>
</ScrollViewer>
Code:
private void ScrollToBottom()
{
//Scroll to the bottom.
Dispatcher.BeginInvoke(() =>
{
this.scrlvwrListBoxMessages.ScrollToVerticalOffset(double.MaxValue);
});
}