Windows 8 ads showing up on top of settings flyout - windows-8

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.

Related

UWP Light dismiss ContentDialog

Is there a way to make the ContentDialog light dismiss?, so when the user clicks on any thing outside the ContentDialog it should be closed.
Thanks.
By default, ContentDialog is placed in PopupRoot. Behind it, there is a Rectangle which dim and prevent interaction with other elements in the app. You can find it with help of VisualTreeHelper and register a Tapped event to it, so when it's tapped you can hide ContentDialog.
You can do this after calling ShowAsync outside ContentDialog code or you can do it inside ContentDialog code. Personally, I implement a class which derives from ContentElement and I override OnApplyTemplate like this:
protected override void OnApplyTemplate()
{
// this is here by default
base.OnApplyTemplate();
// get all open popups
// normally there are 2 popups, one for your ContentDialog and one for Rectangle
var popups = VisualTreeHelper.GetOpenPopups(Window.Current);
foreach (var popup in popups)
{
if (popup.Child is Rectangle)
{
// I store a refrence to Rectangle to be able to unregester event handler later
_lockRectangle = popup.Child as Rectangle;
_lockRectangle.Tapped += OnLockRectangleTapped;
}
}
}
and in OnLockRectangleTapped:
private void OnLockRectangleTapped(object sender, TappedRoutedEventArgs e)
{
this.Hide();
_lockRectangle.Tapped -= OnLockRectangleTapped;
}
Unfortunately ContentDialog does not offer such behavior.
There are two alternatives you can consider:
Popup - a special control built for this purpose, which displays dialog-like UI on top of the app content. This control actually offers a IsLightDismissEnabled for the behavior you need. Since the Anniversary Update (SDK version 1607) also has a LightDismissOverlayMode, which can be set to "On" to automatically darken the UI around the Popup when displayed. More details are on MSDN.
Custom UI - you can create a new layer on top of your existing UI in XAML, have this layer cover the entire screen and watch for the Tapped event to dismiss it when displayed. This is more cumbersome, but you have a little more control over how it is displayed

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.

Win 8.1 Metro Hub Navigation

In a Hub view App with subItems Pages, my question is when I navigate to a sub item detail Page and then use command navigate goback, the view always returns to pageroot hub section01.
How can I return the MainHub Page to the original calling section that went to the sub page in the first place?
My research has been fruitless. I don't think snaps are my answer but hey any advice is appreciated.
I apologize if this is a very simple question but...
Thx.
Ok. Thanks for the answers. After looking at this problem for three days I have found a solution but not quite an answer.
this.NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
By enabling Navigation Caching the page will return to it's sender position. However I still desire to return to the Hub root page to a specific section. If anyone still has info on how to achieve this I would be grateful.
Seasons Greetings.
Well the newbie here has also discovered the MyHub.ScrollToSection(MyHub.Sections[0]);
This allows you to navigate directly to a section thereby bringing it into the current view.
I'm trying to find an answer to the same question. This is what I've found so far. I welcome any better solutions.
Option 1
Enable caching for the page. Note that this must be set in the page constructor or XAML. This will increase memory usage but will improve performance of your app when you navigate back to a cached page.
this.NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled;
More information here: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/windows.ui.xaml.controls.page.navigationcachemode.aspx
Option 2
Manually save a controls state between page navigations. The example below is using the NavigationHelper class which is added to a new Windows Store project by default.
private void OnNavigationHelperSaveState(obj sender, SaveStateEventArgs e)
{
e.PageState["SelectedSection"] = this.MainHub.SectionsInView;
}
private void OnNavigationHelperLoadState(obj sender, LoadStateEventArgs e)
{
if (e.PageState != null)
{
var sections = e.PageState["SelectedSection"] as IList<HubSection>;
if (sections != null && sections.Any())
{
this.MainHub.ScrollToSection(sections[0]);
}
}
}
More information here: http://msdn.microsoft.com/en-gb/library/windows/apps/hh986968.aspx
you could get the Hub's descendant scrollviewer and register to scrollchanged events, store the scrollOffsets and restore them as soon as the user navigates back to the page by applying the values to the hub's scrollviewer.
I guess you would have to register to the hub's loaded event to get the descending scrollviewer (you can use an Extension method from WinRt XAML Toolkit that allows you to get the descendants by Type (e.g. Scrollviewer)
greetings!
you can delete un back stack with this :
if(this.Frame.CanGoBack)
{
this.Frame.BackStack.RemoveAt(0);
}
Have you tried what i suggested?
Unforunately Hub can't be extended to do this and access it's Scrollviewer so you have to do this with an attached Property or plainly in your page.cs .
First you register an handler for the Loaded event of your hub. In the handler you get the descending scrollviewer (with the help of WINRT XAML Toolkit maybe) and register for it's ViewChanged Event.
You store the paremeters you like somewhere they don't get deleted on page navigation and restore and attach them to the scrollviewer on backwards-navigation.
I can give you example code in the afternoon.
Greetings
It's not a ridiculous request. Try this:
public static class Concurrency
{
public static HubSection GotoSection { get; set; }
}
public class MainPage : Page
{
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (Concurrency.GotoSection != null)
MainHub.ScrollToSection(Concurrency.GotoSection);
Concurrency.GotoSection = null;
base.OnNavigatedTo(e);
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
Concurrency.GotoSection = MainHub.SectionsInView.First();
base.OnNavigatedFrom(e);
}
}
The reason this.NavigationCacheMode = Windows.UI.Xaml.Navigation.NavigationCacheMode.Enabled; may not be the correct solution is because you might want your hub to be refreshed. If the detail page resulted in an edit (or especially a delete) a back navigation would show stale data, and subject your app to un unexpected state if the user interacts with dead data.
Best of luck!
Enable cache mode on your page at initialization
public MainHubPage()
{
. .......
this.NavigationCacheMode = NavigationCacheMode.Enabled;
.......
}
You need to add Loaded method to Page constructor.
MainHub.Loaded += async (s, e) => await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
//here you can scroll
MainHub.ScrollToSection(Loyaltysection);
});

How do I UnSnap a Snapped app?

I registered to the OnSizeChanged event of my Page, like that:
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
ApplicationViewState myViewState = ApplicationView.Value;
if (myViewState == ApplicationViewState.Snapped)
{
Windows.UI.ViewManagement.ApplicationView.TryUnsnap();
}
}
I'm tyring to set the application-view to Filled/Portrait state when the user trying (manually....) to resize it to snapped view.
but the TryUnsnap method fails and it stays in snapped state...
Help!
Thanks.
To understand TryUnsnap() we need to understand the 2 types of Windows 8 events:
Programmatic events
Programmatic events do not require the user to do anything. For example the Loaded event of a Page or the Tick event of a Timer.
User-initiated events
User-initiated events require the user to do something. For example the Click event of a Button or the Tapped event of a Control.
The important part
Depending on the type of event, only certain Windows 8 APIs can be called. Adding a Secondary Tile, for example. And (as you might have guessed) un-Snapping an app.
That means you can call those APIs all you want from programmatic events but they will never deliver the results you desire. Unsnap in the StateChanged event, and it will fail for this reason. Unsnap in the Button.Click event, and it will succeed for this reason.
The rationale behind this behavior is the user experience. If the app can change it's 'orientation' on the user without the user's interaction then the behavior of the app becomes both confusing and unpredictable. Windows 8 is a pro-user operating system. When you discover developer 'constraints', 99% of the time it is this philosophy behind it.
Let me demonstrate:
If you attached to the StateChanged event, your code would look like this:
this.ApplicationViewStates.CurrentStateChanged += (s, args) =>
{
System.Diagnostics.Debug.WriteLine("After StateChanged: {0}", this.ApplicationViewStates.CurrentState.Name);
if (this.ApplicationViewStates.CurrentState == this.Snapped)
{
System.Diagnostics.Debug.WriteLine("Before Unsnap: {0}", this.ApplicationViewStates.CurrentState.Name);
Unsnap();
}
};
However, the resulting output (in the debugger) would look like this:
After StateChanged: FullScreenLandscape
After StateChanged: Snapped
Before Unsnap: Snapped
After TryUnsnap: Snapped
This is frustrating for a developer who does not understand the difference between programmatic and user-initiated events in Windows 8. The API appears to "not work" when, in fact, it works perfectly. Just not like they want it to.
If you attached to the Click event, your code would look like this:
MyButton.Click += (s, args) =>
{
System.Diagnostics.Debug.WriteLine("After Button.Click: {0}", this.ApplicationViewStates.CurrentState.Name);
if (this.ApplicationViewStates.CurrentState == this.Snapped)
{
System.Diagnostics.Debug.WriteLine("Before Unsnap: {0}", this.ApplicationViewStates.CurrentState.Name);
Unsnap();
}
};
Then, the resulting output would look like this:
After Button.Click: Snapped
Before Unsnap: Snapped
After TryUnsnap: Snapped
After StateChanged: FullScreenLandscape
This gets you what you want, but it brings up an important point. See how After TryUnsnap the state REMAINS "Snapped"? The transition of a Visual State from one to another is not a synchronous event. Calling for a change takes an unpredictable amount of time. It's probably done with a dispatch post, but I would have to check to be sure.
Having said all that, the state does change. And, after the change the CurrentStateChanged event is raised and you can handle the new Snapped state. By the way, it does not matter if there is another snapped app, this works either way.
The MSDN docs say it only works when it is in the foreground. This is pretty stupid since user interaction can't occur on a background app, and background apps have their threads suspended anyway. But, to be fair to MSDN, this API does not work when your app is in the background - whatever that's worth.
I hope this helps clear it up.
And now to your question:
You want to go from Snapped to Portrait? Of course in Portrait, Snapped is not possible so this is not a possibility for you to code. You want to go from Snapped to Filled as soon as the app is snapped. The event raised from the Snapped action is a programmatic event. As a result, you have to lure the user into doing something in your UI first. So, no you can't do what you are asking. You can't Unsnap() until the user interacts with your app somehow (like a button click event).
Oh, and here's the Unsnap() method if you wanted to reference all my code. I am not doing anything special, but you might be interested:
void Unsnap()
{
if (Windows.UI.ViewManagement.ApplicationView.TryUnsnap())
// successfully unsnapped
System.Diagnostics.Debug.WriteLine("After TryUnsnap: {0}", this.ApplicationViewStates.CurrentState.Name);
else
// un-successfully unsnapped
System.Diagnostics.Debug.WriteLine("After TryUnsnap: {0}", this.ApplicationViewStates.CurrentState.Name);
}
Have a great day and best of luck!
var CurrentSnappedState = ApplicationView.Value;
if (CurrentSnappedState == ApplicationViewState.Snapped && !ApplicationView.TryUnsnap())
{
return;
}
Should do the trick. Remember that you can still snap the page, but when you try to do anything in the snapped page you will be redirected to the fullview.

CoreDispatcher.ProcessEvents() causes an indirect crash?

I have to port some legacy code, that uses modal dialog boxes all over the place to Metro/WinRT (using C++/CX). Because these dialog boxes provide their own message loop (using DialogBoxParam()), the calling code will wait until the user has clicked a button on the message box.
I'm currently trying to write a replacement for the old message box class, that uses XAML and the popup control. To reproduce the same behavior, I have to wait in the calling thread, but also have to keep the UI responsive. I've found out, that CoreDispatcher::ProcessEvents() can be used in a loop, to keep processing events (yeah I realize that this isn't very beautiful, but I don't want to change all of our legacy code to a new threading model). However I'm running into an issue that keeps crashing my app.
Here is a minimal example that reproduces the issue (just create a XAML app and wire this to a button):
void CPPXamlTest::MainPage::Button_Click_1(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
bool cancel = false;
auto popup = ref new Popup();
auto button = ref new Button();
button->Content = "Boom";
auto token = (button->Click += ref new RoutedEventHandler([&cancel] (Object ^, RoutedEventArgs ^) { cancel = true; }));
popup->Child = button;
popup->IsOpen = true;
while (!cancel)
{
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
}
popup->IsOpen = false;
button->Click -= token;
}
This seems to work well for the first one or two tries of opening and closing the popup, using the two buttons. After a few tries however, the application will instantly crash deep in Windows.UI.Xaml.dll, while trying to dereference a null pointer. I can also reproduce this in C# (with practically the same code).
Does anyone have an idea, what is going on in here? Or a suggestion for an alternative approach?
If anyone is interested: I asked the same question a few days later on the MSDN forums and got a response there from a Microsoft employee:
http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/11fa65e7-90b7-41f5-9884-80064ec6e2d8/
Apparently the problem here is the nested message loop that is caused by calling ProcessEvents inside an event handler. It seems that this is not supported by WinRT, but instead of failing in a well-defined manner, this will or may cause a crash.
Alas this was the best and only answer I could find, so I ended up working around the problem, by dispatching the event handler (and a lot of other code) into another thread. I could then emulate the waiting behavior of DialogBox()/DialogBoxParam() (outside the main thread), by waiting on an event that was signaled when the user clicked/tapped a button on my XAML "dialog" popup.
A workaround that works fine for me is to replace the line:
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
with:
auto myDispatchedHandler = ref new DispatchedHandler([&](){
Window::Current->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
});
dispatcher->RunAsync(CoreDispatcherPriority::Normal,myDispatchedHandler);
For more info see this post at MSDN.