I am attempting to use MVVM Light to create a simple page for adding/editing/deleting Contacts and for users to send faxes from the other parts of the software. The MainPage has a simple header with some corporate info and two links, one to the Contacts page and the other to the Fax History page; most of the MainPage page is a navigation frame that is the target of the links, where the pages are loaded. I am using VS 2010/.NET 4.0/SL 4.0.
The Contacts page has two datagrids, one for Search Contacts Results ('gridContacts') and the other for Selected Contacts (those contacts who will receive the fax--'gridSelected'). There's a Delete button for the user to delete the contact of the selected row in the Search grid. There's also a Send Fax button to send the fax to those contacts in the gridContacts grid.
Problem is, if I ever select a row in the Search grid, navigate to Fax History, then come back, I get a StackOverflowException before the navigation occurs. If I navigate to the other page first, then come back, and then select a row, I'll get the exception at that point. I found that the Send Fax button also has causes the same exception when I removed the Delete button. On both buttons, I am able to work around the problem just coding everything in code-behind; obviously this is not ideal, so I want to learn to get it to work with MVVM.
When I step through the code for the problem with the Delete button, I see that the exception occurs in the DelegateCommand that the Delete button is bound to. In the CanExecute method, the first time through, the object parameter is correctly a Contact (since the grid is bound to a List of Contacts). It fires CanExecuteChanged(this,new EventArgs()) as part of the code logic--but then comes BACK into the function, but with null as the parameter passed in. Here is where an infinite loop becomes evident: CanExecute fires in a loop and alternates between having a Contact object and null as the parameter passed in. The stack trace shows External Code between the calls to CanExecute, but that's the only method present. The infinite loop eventually causes the StackOverflowException.
Here's the code in question:
public bool CanExecute(object parameter) //parameter alternates between Contact object and null
{
bool temp = _funcCanExecute(parameter); //_funcCanExecute is set to CanDelete in the DelegateCommand constructor.
if (_bCanExecuteCache != temp)
{
_bCanExecuteCache = temp;
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, new EventArgs()); //this line somehow leads to another call into here --> infinite loop
}
}
return _bCanExecuteCache;
}
The Search grid ItemSource is bound to a VM via a Locator like so:
<sdk:DataGrid AutoGenerateColumns="False" x:Name="gridContacts" IsTabStop="False" Grid.Row="3" ItemsSource="{Binding Path=SearchContactsViewModel.Contacts, Mode=OneWay, Source={StaticResource Locator}}" SelectionMode="Single">
Here are the Delete button Command and CommandParameter (the overall data context is set as DataContext="{Binding Source={StaticResource Locator}, Path=SearchContactsViewModel}"):
<Button x:Name="btnDelete" Style="{StaticResource ButtonStyle}" Command="{Binding Path=SearchContactsViewModel.DeleteContactCommand, Source={StaticResource Locator}}" Grid.Row="1" Grid.Column="1"
CommandParameter="{Binding Path=SelectedItem, ElementName=gridContacts}" HorizontalAlignment="Right">
Here's the simplified code in the SearchContactsViewModel:
public DelegateCommand DeleteContactCommand
{
get;
private set;
}
private bool CanDeleteContact(object param)
{
Contact c = param as Contact;
if (c == null)
return false;
return true;
}
private void DeleteContact(object param)
{
int contactID = ((Contact)param).ID;
_ServiceAgent.DeleteContact(contactID,
(s, e) =>
{
if (!CheckErrorAndResult(e.Error, e.Result, e.errMsg))
return;
SearchContacts();
MessageBox.Show("Delete successful.");
});
}
Here is the line of code that wires up the command in the VM:
DeleteContactCommand = new DelegateCommand(DeleteContact, CanDeleteContact);
BUT, if I replace CanDeleteContact with "(x) => true" for testing, I do NOT get the problem.
Please let me know if I can provide more information. I'm trying to figure out the problem with the Delete button first and hopefully apply the same solution to the Send Fax button.
Thanks,
J
***UPDATE 9/6/2011: I have noticed that in Silverlight navigation, a new instance of the page is created each time. So would that account for why this problem only happens after navigation? And why the values handled in what I thought was an infinite loop are alternating between null and non-null values? Like maybe the old page now has null, but the new page is being shown and is correct, but both are tied to the same static VM object. Just shooting in the dark here.
I think problem is that you are mixing CanExecute and CanExecuteChanged. CanExecuteChanged is definitely going to make somebody call CanExecute (which is calling CanExecuteChanged...an so on...).
So those call should be separate - CanExecute should only return some value (bCanExecuteCache). And CanExecuteChanged should be called on specific events/calls/cases.
Here is some example on Silverlight forum that might help you (shows the use of CanExecuteChanged): concrete post | whole thread
Related
I am making a UWP app which is supposed to be on xbox for now and maybe in future ill release it on pc and other platforms. I know that on PC and for mobile we can enable this feature with following 2 properties on the GridView or ListView.
CanReorderItems=True
CanDrop=True
But according to Microsoft Docs, drag and drop feature is not available or supported on xbox.
So what are any other options to achieve this reorder feature on xbox GridView?
UPDATE 1
So here is my backend code for the gridview. selection mode is single but I am not using selectionchanged event because that just creates lot of confusion and for now just assume that we always need to swap the items I will set the boolean later once the swapping in working perfectly.
private void SamplePickerGridView_ChoosingItemContainer(Windows.UI.Xaml.Controls.ListViewBase sender, ChoosingItemContainerEventArgs args)
{
if (args.ItemContainer != null)
{
return;
}
GridViewItem container = (GridViewItem)args.ItemContainer ?? new GridViewItem();
//should be xbox actually after pc testing
if (DeviceTypeHelper.GetDeviceFormFactorType() == DeviceFormFactorType.Desktop)
{
container.GotFocus += Container_GotFocus;
container.LostFocus += Container_LostFocus;
//container.KeyDown += Container_KeyDown;
}
args.ItemContainer = container;
}
private TVShow GotItem, LostItem;
private void Container_LostFocus(object sender, RoutedEventArgs e)
{
LostItem = OnNowAllGridView.ItemFromContainer(e.OriginalSource as GridViewItem) as TVShow;
GotItem = null;
}
private void Container_GotFocus(object sender, RoutedEventArgs e)
{
GotItem = OnNowAllGridView.ItemFromContainer(e.OriginalSource as GridViewItem) as TVShow;
if (GotItem != null && LostItem != null)
{
var focusedItem = GotItem;
var lostitem = LostItem;
var index1 = ViewModel.Source.IndexOf(focusedItem);
var index2 = ViewModel.Source.IndexOf(lostitem);
ViewModel.Source.Move(index1, index2);
}
LostItem = null;
}
u can try the code with adaptivegridview or just normal gridview of uwp if it works with that it should work with adaptivegridview as well.
Current Bheaviour items are swaped but the focus remains at same index.
Expected the focus should also move along with the item.
Your finding is true, drag and drop is not supported on Xbox out of the box (although when mouse support comes to Xbox in the future, I guess it will work).
So if you need this functionality, you will have to implement it manually from the start. One option would be to add a button, that will display on Xbox only and will read like Reorder Grid.
When this "reorder" mode were enabled, you have several solutions available.
The easiest solution for you would be to set the SelectionMode to Single and when a item is selected, you would bring it to fromt of the underlying collection.
collection.Remove( selectedItem );
collection.Insert( 0, selectedItem );
This bring to front solution was implemented on the Xbox One dashboard for reordering tiles.
Second option would be to set the SelectionMode to Multiple, where user would first select one item and then a second one. After that you could move the first selected item before the second selected:
collection.Remove( firstSelectedItem );
var targetIndex = collection.IndexOf( secondSelectedItem );
collection.Insert( targetIndex, firstSelectedItem );
The last solution is the most complex. With SelectionMode = Single you would select a single item and then observe the direction in which the user focus moves and move the tile "in real time". This is the most user friendly, but hardest to implement reliably.
Just as an outline of the third solution - you could capture the GotFocus event if you implement a custom template of the GridView:
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Horizontal"
GotFocus="GridViewItem_GotFocus"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
Now within this GotFocus handler you could retrieve the item that has currently focus from the EventArgs.OriginalSource. This way you could know which item got the focus and you could swap it with the item the user selected.
Update - hacky solution
I have come up with a hacky approach that solves the GotFocus/LostFocus mess.
The problem with GotFocus is that when we move the item in collection, the focus gets confused. But what if we didn't physically move the items at all?
Suppose your item type is TVShow. Let's create a wrapper around this type:
public class TVShowContainer : INotifyPropertyChanged
{
private TVShow _tvShow;
public TVShow TvShow
{
get => _tvShow;
set
{
_tvShow = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Now change the collection item type to this new "wrapper" type. Of course, you also have to update your GridView DataTemplate to have the right references. Instead of "{Binding Property}" you will now need to use "{Binding TvShow.Property}", or you can set the DataContext="{Binding TvShow}" attribute to the root element inside the DataTemplate.
But you may now see where I am going with this. Currently you are using Move method to move the items in the collection. Let's replace this with a swap:
var item1 = focusedItem.TvShow;
focusedItem.TvShow = LostItem.TvShow;
LostItem.TvShow = item1;
This is a big difference, because we no longer change the collection itself, but just move the references to items that are wrapped in a "static" container. And thanks to bindings the items will properly display where they should.
This is still a hacky solution, because it requires you to wrap your items just for the sake of the reordering, but it at least works. I am however still interested in finding a better way to do this.
I've implemented a UWP SplitView similar to the one made by Diederik Krols. I prefer the approach of using a ListView over using RadioButtons as shown by Jerry Nixon's implementation of the SplitView.
However, I have a problem when I add secondary commands at the bottom of the SplitView, which Diederik doesn't do. These secondary commands are implemented by another ListView bound to a collection of Commands. So I have TWO ListViews that should only allow ONE item to be selected among them at a time.
I've tried two things:
I've bound the SelectedItem property of both ListViews to the same object. The idea was that maybe ListView doesn't display a selection if SelectedItem is not in the list bound to ItemsSource. Sadly, it simply goes on displaying the last selected item.
I've bound each ListView's SelectedItem to its own property. When one of the ListViews' item is selected, the SelectedItem of the other property is set to 'null' by the ViewModel. This produces the same result as in 1.
Any ideas on how to solve this problem?
I had the same problem.
I have a fix, but I'm not that proud of it ;) it's a dirty hack and I'm hoping other solutions will present itself so I can change it too.
But here it is:
First the listviews hook up to the SelectionChanged event even though we also bind the selected item to the viewmodel ( full code shown here https://github.com/AppCreativity/Kliva/blob/master/src/Kliva/Controls/SidePaneControl.xaml )
<ListView x:Name="TopMenu"
SelectionChanged="OnTopMenuSelectionChanged"
Background="Transparent"
ItemsSource="{x:Bind ViewModel.TopMenuItems}"
ItemTemplateSelector="{StaticResource MenuItemTemplateSelector}"
ItemContainerStyle="{StaticResource MenuItemContainerStyle}"
SelectedItem="{x:Bind ViewModel.SelectedTopMenuItem, Mode=TwoWay, Converter={StaticResource XBindItemCastingConverter}}"
Grid.Row="0" />
In that SelectionChanged, we'll deselect the 'other' listviews selection! ( full code shown here https://github.com/AppCreativity/Kliva/blob/master/src/Kliva/Controls/SidePaneControl.xaml.cs )
Note that we need to keep track that we are already in a deselecting process otherwise we'll end up with an endless loop. This is done with the _listViewChanging field.
private void OnBottomMenuSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!_listViewChanging)
{
_listViewChanging = true;
TopMenu.SelectedIndex = -1;
_listViewChanging = false;
}
}
Last thing to do is making sure we handle the selection and clear it again in the viewmodel for next itteration ( full code shown here https://github.com/AppCreativity/Kliva/blob/master/src/Kliva/ViewModels/SidePaneViewModel.cs )
public MenuItem SelectedBottomMenuItem
{
get { return _selectedBottomMenuItem; }
set
{
if (Set(() => SelectedBottomMenuItem, ref _selectedBottomMenuItem, value))
{
if (value != null)
{
if (string.IsNullOrEmpty(SelectedBottomMenuItem.Title))
HamburgerCommand.Execute(null);
if (SelectedBottomMenuItem.Title.Equals("settings", StringComparison.OrdinalIgnoreCase))
SettingsCommand.Execute(null);
SelectedBottomMenuItem = null;
}
}
}
}
In Prism , MVVM, Windows 8.1 StoreApp I want the ViewModel to capture the SelectItem in a ListView. The ListView contains an ObservableCollection of objects. The ViewModel needs to lookup more details of the selected object and notify the View. The View in turn should show the details of the object.
I have implemented this, but the View allways shows the former object (after selecting a new one)
Of course what I'm looking for is an immediate and correct reaction in the View on selecting an object. Here are my codesnippets, all in VB code.
EDIT: I have put up another - smaller- example, using this approach. I made a recording of the process in this video. Please take a look at it before you read further!!
The objects come from the ViewModel as:
Public Property Persons As New ObservableCollection(Of Person)
They are bound to a usercontrol:
<Grid>
<ListView
ItemsSource="{Binding Persons}"
ItemTemplate="{StaticResource BusinessCard}">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="SelectionChanged">
<Behaviors:ListViewSelectionChangedAction/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</ListView>
</Grid>
Via the Behavior eventually this ends up in the ViewModel through this code:
Sub New(InjectedEventAggregator As IEventAggregator)
LocalEventAggregator = InjectedEventAggregator
LocalEventAggregator.GetEvent(Of PersonIsSelectedEvent)().Subscribe(AddressOf HandlePersonIsSelected, True)
This event is handled by this routine
Public Sub HandlePersonIsSelected(ByVal SelectedPerson As Person)
ActualPerson = SelectedPerson
End Sub
The last part of all this is the property that contains the ActualPerson like so:
Private Property _ActualPerson As Person
Public Property ActualPerson As Person
Get
Return _ActualPerson
End Get
Set(value As Person)
SetProperty(_ActualPerson, value)
End Set
End Property
EDIT: and this is the XAML that should show the selected ActualPerson:
<StackPanel DataContext="{Binding ActualPerson}" >
<Image Source="{Binding Photo}" Stretch="Fill" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}" />
<TextBlock Text="{Binding FamilyName}" />
<TextBlock Text="{Binding Gender}" />
</StackPanel>
</StackPanel>
When I step through the code, I can see that the SelectedItem event is caught in the ViewModel, the handler for the selected person is called, the property is updated. Using Prism this would also mean, that the NotifyPropertyChanged event is fired. It IS fired indeed, otherwise the former object would not show either I guess.
But why is the View not updated immediatelty with the right (Person) object?
If you have a clue.... be my honored guest!
Regards
Let me try to understand what you said in "no reaction on the View". Are you saying the UI is NOT CHANGED, even though the 'ActualPerson = SelectedPerson' is called?
The controls have a binding property called MODE which decides the data flow. The MODE for the TextBlocks that display the Person information can be OneWay. It is possible that the binding is OneTime which is causing the issue.
Can you please confirm what is coming from your Repository? I'm assuming it isn't an observable collection. At least it shouldn't be, I'd think it would be a serialisable POCO object. This means that you will need to add the items to the observable collection. The way I do this if not using a CollectionView is to have a readonly variable of type ObservableCollection, which is never changed. Then when you make the request to messages, I would ensure the collection is cleared, ready for new the new items. Once the messages are returned, loop through each model item (message) within the response and convert them to MessageViewModels (a new class that contains bindable properties and validation (data annotations) as required. As each ViewModel item is created it is added to the observablecollection. The act of adding items to the collection will raise an event the listview is listening for and therefore will display the item (as long as the MessageViewModel has an associated data template.
private readonly _messages = new ObservableCollection<MessageViewModel>();
Public ObservableCollection<MessageViewModel> Messages {get { return _messages;}}
OnNavigateTo
Messages.Clear;
foreach(var message in await _messageRepository,GetMessagesAsync())
{
Messages.Add(new MessageViewModel(){Name = message.Name, Text = message.Text});
}
Does that make sense?
One bad solution, but maybe it is helpful. You can call "again" OnProperyChanged. I say "again" because it is supposed that SetProperty calls it, but I am having some issues with VB.NET and SetProperty too.
Private Property _ActualPerson As Person
Public Property ActualPerson As Person
Get
Return _ActualPerson
End Get
Set(value As Person)
SetProperty(_ActualPerson, value)
OnPropertyChanged("ActualPerson")
End Set
End Property
Edited 04/02/15: the good solution is here: OnPropertyChanged not fired when SetProperty is called
As simple as removing the word "Property" in the private declaration. It is because it is passed ByRef, so it cannot be a property.
I am writing a Windows Store app using C++/XAML with DirectX interop - SwapChainBackgroundPanel.
The application is based on the template "Split Page". From each list view item, a DirectX page may be launched using code below.
Window::Current->Content = ref new MyD3Components::DirectXPage();
Window::Current->Activate();
This is working fine and DirectX page opens up and plays very well.
What I would like to have a button in the app bar which helps user to go back and display the "Split Page" to allow selecting another DirectX page. This I have not been able to accomplish yet.
Among several things I have tried, below is the most logical one to my opinion. It gives a "Platform::DisconnectedException" when user wants to go back to the last page.
Windows::UI::Xaml::Controls::Frame^ rootFrame = SDL::App::GetRootFrame();
Window::Current->Content = rootFrame;
Window::Current->Activate();
Please look to see if you have a suggestion or better a solution.
Here the sample example for your question :
What i am creating : 2 pages...
You will have (go to page 2)link on page 1...If u click that,the second page should appear that says "Page 2" at the top. Notice that there is a back button to the left of the page title. Click the button to return to the first page...
1.) Find the TextBlock element named pageTitle and change the Text property to Page 1. The XAML should look like this:
<TextBlock x:Name="pageTitle" Grid.Column="1" Text="Page 1"
Style="{StaticResource PageHeaderTextStyle}"/>
2.)Add the following XAML as a second child element to the root Grid. The StackPanel element should be a sibling to the Grid that contains the back button and page title.
<StackPanel Grid.Row="1"
Margin="120,0,120,60">
<HyperlinkButton Content="Click to go to page 2" Click="HyperlinkButton_Click_1"/>
</StackPanel>
3.)Make the following changes to BasicPage2.xaml.
Find the TextBlock element named pageTitle and change the Text property to Page 2. The XAML should look like this:
<TextBlock x:Name="pageTitle" Grid.Column="1" Text="Page 2"
Style="{StaticResource PageHeaderTextStyle}"/>
4.)Add the following XAML as a second child element to the root Grid. The StackPanel element should be a sibling to the Grid that contains the back button and page title.
<StackPanel Grid.Row="1"
Margin="120,0,120,60">
<TextBlock HorizontalAlignment="Left" Name="tb1" Text="Hello World!"/>
</StackPanel>
5.)Add the following code to the BasicPage1 class in BasicPage1.Xaml.cs
private void HyperlinkButton_Click_1(object sender, RoutedEventArgs e)
{
this.Frame.Navigate(typeof(BasicPage2));
}
6.)Now that we've prepared the new pages, we need to make BasicPage1 the first thing that appears when the app starts. Open app.xaml.cs and change the OnLaunched method to call Frame.Navigate by using BasicPage1 instead of the BlankPage. The entire OnLaunched method should look like the following:
protected override void OnLaunched(LaunchActivatedEventArgs args)
{
// Create a Frame to act navigation context and navigate to the first page
var rootFrame = new Frame();
rootFrame.Navigate(typeof(BasicPage1));
// Place the frame in the current window and ensure that it is active
Window.Current.Content = rootFrame;
Window.Current.Activate();
}
Now you are ready to test the app. Start the app, and click the link that says Click to go to page 2. The second page should appear that says "Page 2" at the top. Notice that there is a back button to the left of the page title. Click the button to return to the first page.
Thats it! hope it helps u.
After a bit of trial and error, I am in the position to answer my own question. It seems that all I needed to do was to remove my rendering callbackfrom the CompositionTarget.
It was added like below.
m_eventToken = CompositionTarget::Rendering::add(ref new Windows::Foundation::EventHandler<Object^>(this, &DirectXPage::OnRendering));
Before replacing the current window and activating it, I called below.
CompositionTarget::Rendering::remove(m_eventToken);
I guessed this helped DirectX not to output to rendering pipeline and complain (disconnectedexception) when the target is not there.
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.