Entry ReturnType Done not closing keyboard - xaml

When I use the ReturnType property and set the value to "Done" nothing happens on the keyboard. I'm expecting the keyboard to close when I press done on my keyboard and nothing happens.
The issue is on Android, but on ios it works.
<Entry ReturnType="Done" />

You can refer to Customize the return key.
ReturnType, of type ReturnType, specifies the appearance of the return button.
I created a project and tried to achieve your need:
<Entry x:Name="MyEntry"
ReturnType="Done"
Completed="Entry_Completed"/>
private void Entry_Completed(object sender, EventArgs e)
{
MyEntry.Unfocus();
}
The result is that entry lost focus as expected, but the keyboard did not disappear.
I searched relevant information about this and found it (Implement pending focus management logic in Handlers). You can follow it.

It seems the Focusable logic is still not implemented yet on Maui. They have stated it will be available in upcoming Previews.
So the workaround for this issue is setting the property IsEnabled to false and immediately setting it to true on your handler:
entry.IsEnabled=false; // This removes the focus and close the keyboard
entry.IsEnabled=true; // This re-enabled the Entry for interaction

Related

Detecting the end of scrolling in a ListView

Universal Windows 8.1 Store project here.
I want to know, when a ListView stops scrolling after user interaction. I found plenty of information on the net, but not one example reliably working on WP 8.1 (WPF/WP8 examples do not help much, and there are loads of them).
Here's what I do now.
1. The ListView
<ListView
x:Name="MessageList"
ItemsSource="{Binding Messages}"
VerticalAlignment="Bottom"
ItemContainerStyle="{StaticResource ChatListViewItemStyle}"
PointerEntered="MessageList_OnPointerEntered"
>
<ListView.ItemTemplate>
<DataTemplate>
<messages:MessageContainer />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
2. The ScrollViewer
I get a ScrollViewer reference from the ListView in code behind.
// GetChildElement<T>(this DependencyObject root) is a simple extension method of mine
Scroll = MessageList.GetChildElement<ScrollViewer>();
3. ListViewer.PointerEntered and ScrollViewer.ViewChanged
PointerEntered handler is used to detect the start of user interaction. When an interaction is detected, I subscribe to Scroll.ViewChanged and use IsIntermediate flag of the event to detect when the list stops scrolling (including inertia).
void MessageList_OnPointerEntered(object sender, PointerRoutedEventArgs e)
{
Debug.WriteLine("START MONITORING INTERACTION");
Scroll.ViewChanged += OnViewChangedByUser;
}
void OnViewChangedByUser(object sender, ScrollViewerViewChangedEventArgs e)
{
Debug.WriteLine("WAITING FOR INTERACTION TO END");
if (!e.IsIntermediate) {
Debug.WriteLine("INTERACTION ENDED");
Scroll.ViewChanged -= OnViewChangedByUser;
}
}
This does work to some extent.
The problem
The problem is, ViewChanged is not fired when the list is scrolled to the end/start and the user pulls it out of bounds and releases it, causing it to return back with inertia. So, the interaction start is detected, but the end is not. ViewChanged is not fired at all -- neither with IsIntermediate=True, nor with False.
What is a better way of doing what I want?
Sadly there's no good way to do this on Windows 8.1 aside from repeated polling and checking the ScrollOffset.
I'd just get an array of 10 doubles, and like 10 times a second I'd shift-in the current scroll offset. Than in that same handler check if the last 5 equals to the end of your list than raise an event.
As Tamás Deme puts it, there's no nice way of doing what is required. However, I've found a workaround that works in my case (nothing nice about it though).
In fact, I'm detecting, whether the list is scrolled to the bottom, when the scrolling stops. It's detecting the end of scrolling is what is causing so much trouble.
There are two parts of the problem: 1 - detecting the end of user interaction, 2 - detecting the end of inertia. Suprisingly, there's no good way of solving either of them. Thankfully, what I actually need is just knowing the value of VerticalOffset when scrolling (user-driven or inertia-animated) ceases. I don't actually have to know whether the user is still holding the list or not.
void MessageList_OnPointerEntered(object sender, PointerRoutedEventArgs e)
{
IsScrolledToLastLine = false; // this is to signal, that the user is
// holding the list, and there must be no
// automatic scrolling, when content is
// added to it.
Debug.WriteLine("[*]START MONITORING INTERACTION");
Scroll.ViewChanged += OnViewChangedByUser;
Scroll.LayoutUpdated += OnScrollLayoutUpdated;
}
void OnScrollLayoutUpdated(object sender, object e)
{
// will trigger multiple times during scrolling
// AND
// will trigger when inertia finally stops
// (regardless of the changes of VerticalOffset)
IsScrolledToLastLine = Scroll.ScrollableHeight == Scroll.VerticalOffset;
Debug.WriteLine("Interaction progress: {0}", IsScrolledToLastLine);
}
void OnViewChangedByUser(object sender, ScrollViewerViewChangedEventArgs e)
{
if (!e.IsIntermediate) {
IsScrolledToLastLine = Scroll.ScrollableHeight == Scroll.VerticalOffset;
Debug.WriteLine("Interaction end: {0}", IsScrolledToLastLine);
Scroll.LayoutUpdated -= OnScrollLayoutUpdated;
Scroll.ViewChanged -= OnViewChangedByUser;
}
}
Scroll.LayoutUpdated
LayoutUpdated is fired multiple times during scrolling. Unlike ViewChanged this event is also fired when inertia stops in the situation shown in the picture of the post. Unfortunatelly, there is no way to determine in LayoutUpdated, whether the list stopped scrolling completely or not.
ViewChanged works fine when you actually change VerticalOffset by scrolling; LayoutUpdated covers the over-scrolling situation.
There is another problem though: OnScrollLayoutUpdated may remain subscribed when scrolling over the edges of the list, as ViewChanged will not trigger. Fortunately, I can just ignore that, this doesn't break anything.

How to make a default button in UWP app using XAML?

I'm trying to declare a button as default in UWP app but receive an error:
The property 'IsDefault' was not found in type 'Button'
How can I make a default button in UWP app?
I down know what IsDefault is in WPF but to get if a button is pressed in UWP you can use CoreWindow.GetForCurrentThread().KeyDown. Create a Method that will be called from when the button is pressed or VirtualKey.Enter is clicked.
public MainPage()
{
this.InitializeComponent();
CoreWindow.GetForCurrentThread().KeyDown += MainPage_KeyDown; ;
}
private void MainPage_KeyDown(CoreWindow sender, KeyEventArgs args)
{
switch (args.VirtualKey)
{
case Windows.System.VirtualKey.Enter:
// handler for enter key
break;
default:
break;
}
}
You can use key down event which you can place on any textbox for example if you are making a login page then probably there will be 2 textboxes for username and password then just add key down event handler to textbox as it will be the last mandatory field like this:
<PasswordBox KeyDown="PasswordKeyDown"/>
then you can handle this event as:
using System.Windows.Input;
private void PasswordKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
Login();
}
Hope it will help you :)
There is not easy or clean way to solve your problem because IsDefault is not available for uwp apps.
if you are using MVVM or you want to reuse your code I recommend you to use Behaviors and follow the examples that the other guys posted.
I need a Button which user can invoke by pressing the ENTER key.
In an UWP app, by default a Button can be invoked by pressing the Enter key. So I guess what you want is setting the focus on this Button when there are some other UIElements in your page.
You can refer to Keyboard navigation among UI elements,
By default, the tab order of controls is the same as the order in which they are added to a design surface, listed in XAML, or programmatically added to a container.
To focus on the Button which is not the first element, you can just give the TabIndex="1" property to your Button, this property can make your Button get focus whenever the page is loaded, but if you change the focus on other controls in this page, you will need to reselect this button by mouse clicking, touching or TAB key.

Custom context menu XAML for WP8

I try to implement a custom ContextMenu in a LongListSelector.
I'm not using the ContextMenu from Microsoft.Phone.Controls.Toolkit, it's basically the same as in the Rowi App:
(source: hiddenpineapple.com)
Approach 1
My list item toggles a VisualState on hold and an overlay is shown with controls in it.
The problem
I can't find a way to go back to the default state when the user clicks outside of the list item (as in the default ContextMenu).
Approach 2
I've implemented a custom template for the toolkit ContextMenu which looks exactly the same. I had to move its margin top to -itemHeight, as by default it is below the item.
The problem
The problem with this solution is, that it automatically closes itself when opening and I couldn't figure out how to avoid this.
Another problem was that it didn't work well with TiltEffect.IsTiltEnabled from the Toolkit (visual problems).
I need your help
Any suggestions on how to get this working?
Answer
Thanks to Cheese, now I know how to properly close the menu when the user clicks outside.
His suggestion was to get the coordinates of a Tap event on the current page, and check if it's inside the menu. When not, close the menu.
So I added a Tap listener to the page when the menu opens, and removed it when the menu closes. From the page listener I got the event coordinates and could check if it's inside the control which holds the menu (same size and position). I received the position of the control with Point leftUpperPoint = control.TransformToVisual(page).Transform(new Point(0, 0)) and the rightLowerPoint by adding the ActualWidth and ActualHeight.
But then I realized:
Why should I even calculate if the tap is inside the menu? I always want to close the menu when the user taps anywhere on the screen. If it's outside, yes. If it's on a menu button, yes.
Another modification I made was to listen for MouseLeftButtonDown instead of Tap as it also triggers when the user swipes.
So I removed this code and came up with the following:
private void ToggleMenu(object sender, System.Windows.Input.GestureEventArgs e)
{
PhoneApplicationFrame frame = ((PhoneApplicationFrame)Application.Current.RootVisual);
VisualState state = this.States.CurrentState;
if (state == null || state.Name == "DefaultState")
{
frame.MouseLeftButtonDown += MouseDownDelegate;
this.State = "MenuState";
}
else
{
frame.MouseLeftButtonDown -= MouseDownDelegate;
this.State = "DefaultState";
}
}
private void MouseDownDelegate(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
ToggleMenu(sender, null);
}
This works perfectly!
Thanks to Cheese for the hint.
Something like this by #denniscode http://dotnet.dzone.com/articles/rowi-show-tap-menu
Approach 1 problem
The best solution would be:
Get the menus coordinates, when user makes a tap - you check are tap coordinates on menu or not, if not - dissmiss - simple.
Approach 2 problem
I guess you had some button in a corner and when you tapped on it - nothing happened? And when you dissmissed the Tilt all worked. It seems that tilt works faster than a click, so, tilt changes the button coordinates, and device thiks you have missed/or dragged off
You can use what #ScottIsAFool suggested and maybe create another Dependency Property on your TapMenu control of type UIElement named CloseWhenTappedElement and automatically listen for Tap events inside your control once set. For example
<Grid x:Name="TapArea"/>
<TapMenu CloseWhenTappedElement="{Binding ElementName=TapArea"}/>

Reset SelectedItem in LongListSelector after selection

I'm using Caliburn.Micro and the LongListSelector. Because binding SelectedItem is a problem I act on the SelectionChanged event. Problem is, after returning to the list, when I click the same item again, it is already selected. So the event doesn't fire. I could set the SelectedIndex to -1 or something, but in Caliburn.Micro I can't access UI controls. That's the point of MVVM, isn't it?! :)
Here's my XAML
<LongListSelector x:Name="NewsItems"
ItemsSource="{Binding NewsItems}"
cal:Message.Attach="[Event SelectionChanged] = [NavigateToArticle($eventArgs)]" />
How to solve this? How can I reset the SelectedItem when I can't access the LongListSelector from code?
Thanks!
You have to put your LongListSelector SelctionMode="Multiple",
or
You can get it using Gesture Tap event.
Did not understood real problem but
I think you can solve your problem if selection change event fire every time when user select item-
private void productList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
LongListSelector productList= (LongListSelector)sender;
if (productList.SelectedItem == null)
return;
//Write your code here
//For Tapping many times..
productList.SelectedItem = null;
}
The above code will make selection change event to fire on selection of same item every time.

Windows 8 ads showing up on top of settings flyout

First, a screenshot:
The title and image explain it pretty well. I have an ad set on the right side of my app's main group view (very very similar to the default grid template in this example), and when I pull up my About screen, the ad bleeds through.
The About screen is a user control set on a SettingsFlyout that I borrowed from some code samples handed out at a dev-camp (below).
class SettingsFlyout
{
private const int _width = 346;
private Popup _popup;
public void ShowFlyout(UserControl control)
{
_popup = new Popup();
_popup.Closed += OnPopupClosed;
Window.Current.Activated += OnWindowActivated;
_popup.IsLightDismissEnabled = true;
_popup.Width = _width;
_popup.Height = Window.Current.Bounds.Height;
control.Width = _width;
control.Height = Window.Current.Bounds.Height;
_popup.Child = control;
_popup.SetValue(Canvas.LeftProperty, Window.Current.Bounds.Width - _width);
_popup.SetValue(Canvas.TopProperty, 0);
_popup.IsOpen = true;
}
private void OnWindowActivated(object sender, Windows.UI.Core.WindowActivatedEventArgs e)
{
if (e.WindowActivationState == Windows.UI.Core.CoreWindowActivationState.Deactivated)
{
_popup.IsOpen = false;
}
}
void OnPopupClosed(object sender, object e)
{
Window.Current.Activated -= OnWindowActivated;
}
}
And, because I know it will be asked for, here is the line of XAML defining the ad on my page:
<ads:AdControl Visibility="{Binding IsTrial, Source={StaticResource License}, Converter={StaticResource BooleanToVisibilityConverter}}" Grid.Row="0" Grid.RowSpan="2" x:Name="LandscapeAdControl" ApplicationId="test_client" AdUnitId="Image_160x600" Width="160" Height="600" VerticalAlignment="Center" HorizontalAlignment="Right"/>
So, why is this happening, and how do I prevent it?
Suspicions
I am still on Consumer Preview b/c I have a show-and-tell Monday and didn't have time to work on migrating the OS on this box without risking being non-functional when I am showing this. As such, upgrading might fix it if it's a bug.
1.a. Update I have upgraded to Release Preview and have the same issue.
Is there some fancy ad-hiding-but-still-getting-impressions prevention technique at play here? Perhaps it thinks I am trying to cover the ad with a ui element and still get credit for it's impression without the user seeing it. If so, how do I manage this entirely legit use case?
Spoiler Alert: ZIndex isn't set anywhere.
It presents the same problem with overlaying the AppBar (top or bottom). I used the Opened and Closed events on the AppBar instance to hide/show the ad. This means the AdControl is bound to a local page property instead of binding directly to a ViewModel. Like you said, it's unfortunate but it works.
private void bottomAppBar_Opened(object sender, object e)
{
if (App.ViewModel.IsTrialVisibility == Visibility.Visible)
this.DefaultViewModel["AdVisibility"] = Visibility.Collapsed;
// else do nothing as we don't want to show it since it's not a trial
}
private void bottomAppBar_Closed(object sender, object e)
{
if(App.ViewModel.IsTrialVisibility == Visibility.Visible)
this.DefaultViewModel["AdVisibility"] = Visibility.Visible;
// else do nothing as it's not shown in the first place (not a trial)
}
There is a property on AdControl named: UseStaticAnchor
Setting this property to true will fix both performance problems with scrolling, as well as the AdControl drawing on top of everything else.
Original answer - this method is now outdated:
The AdControl has two methods on it: Suspend() and Resume().
Whenever you open a popup window or AppBar, you will want to call Suspend(), and Resume() when it is closed again.
I believe under the covers, the AdControl uses a WebView to display the ads. For whatever reason, a WebView will always display on top of everything else in your application. The fix for this is to temporarily disable the WebView, and instead display a WebViewBrush.
(This technique is described here: http://msdn.microsoft.com/library/windows/apps/windows.ui.xaml.controls.webviewbrush) So when you call Suspend() and Resume(), the AdControl is doing this under the covers.
What I've ended up doing is creating a UserControl (named SuspendingAdControl) that simply contains an AdControl and can be used anywhere in the app. Then whenever a window is opened or closed, I use Caliburn Micro's EventAggregator to publish an event. The SuspendingAdControl will subscribe and handle these events, and then appropriately call AdControl.Suspend() or Resume().
I ended up crafting some code to listen to an event on the flyout when it closed so I could high/show the ads manually. It's unfortunate that I had to do a workaround, but it works.
None of this is now necessary, as the flyout in 8.1 now is at the top of the Z-order.
I am still on Consumer Preview b/c I have a show-and-tell Monday and
didn't have time to work on migrating the OS on this box without
risking being non-functional when I am showing this. As such,
upgrading might fix it if it's a bug.
I haven't used any advertisements in my own metro applications yet, so I haven't seen any problems like this occurring. I'm using the Release Preview, and was using Consumer Preview prior to May 2nd.
There were some significant changes between the Consumer Preview and Release Preview. As such, upgrading might fix this, or it may break something else.
You're going to have to upgrade eventually. I'd suggest trying that first before you attempt to solve the problem.