Windows Phone 8.1 MenuFlyout Bug? - c#

I have an Page AppBar that contains an CommandBar in this command bar I have AppBar Buttons that when on clicked open a MenuFlyout like below:
<AppBarButton Icon="World" Label="Maps" ToolTipService.ToolTip="Map Providers!" IsCompact="True">
<AppBarButton.Flyout>
<MenuFlyout>
<MenuFlyoutItem Click="mapProviderMenuFlyoutItem_Click">Unison Maps</MenuFlyoutItem>
<MenuFlyoutItem Click="mapProviderMenuFlyoutItem_Click">Google Maps</MenuFlyoutItem>
<MenuFlyoutItem Click="mapProviderMenuFlyoutItem_Click">Bing Maps</MenuFlyoutItem>
<MenuFlyoutItem Click="mapProviderMenuFlyoutItem_Click">OpenStreetMap</MenuFlyoutItem>
<MenuFlyoutItem Click="mapProviderMenuFlyoutItem_Click">OpenCycleMap</MenuFlyoutItem>
<MenuFlyoutItem Click="mapProviderMenuFlyoutItem_Click">OCM Transport</MenuFlyoutItem>
<MenuFlyoutItem Click="mapProviderMenuFlyoutItem_Click">OCM Landscape</MenuFlyoutItem>
<MenuFlyoutItem Click="mapProviderMenuFlyoutItem_Click">MapQuest OSM</MenuFlyoutItem>
</MenuFlyout>
</AppBarButton.Flyout>
</AppBarButton>
The first button works great, it shows all menu items in the menu flyout, however the other buttons are stripping out menu items as the MenuFlyout is not large enough to display all results.
The above code can be added multiple times in the project and results in the same bug.
Does anyone have a solution for this?

EDIT: it appears to be a known bug. See this answer for a workaround.
I don't think MenuFlyout is designed for use with an AppBarButton. It's more suitable as a longpress menu on a ListViewItem. In any case, I've never seen MenuFlyout used on an AppBarButton in any official Microsoft apps. Usually they'd use ListPickerFlyout instead.
For example, you could use the following XAML:
<Page
x:Class="App7.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Page.BottomAppBar>
<CommandBar>
<AppBarButton Icon="World" Label="Maps" ToolTipService.ToolTip="Map Providers!" IsCompact="True">
<AppBarButton.Flyout>
<ListPickerFlyout ItemsSource="{Binding MapProviders}" />
</AppBarButton.Flyout>
</AppBarButton>
</CommandBar>
</Page.BottomAppBar>
<Grid></Grid>
</Page>
with code behind:
public sealed partial class MainPage : Page
{
public List<string> MapProviders { get; private set; }
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
MapProviders = new List<string>
{
"Unison Maps",
"Google Maps",
"Bing Maps",
"OpenStreetMap",
"OpenCycleMap",
"OCM Transport",
"OCM Landscape",
"MapQuest OSM"
};
}
}
to produce a flyout like this (which is scrollable):
Of course, this is a very simplified example and you could set the ItemsSource by other means.

Related

WPF plugin architecture itemscontrol binding not working

We encountered an interesting behavior on .Net 4.5 (4.6.2 also tested).
The project has multiple plugin dlls.
main exe will load DataTemplates (view) and ViewModels from DLLs using MEF.
if StepView and StepVm and main frame code are in one project (not using MEF), The 2 buttons I show below are working.
if move StepView and StepVm to plugin dll, only second button will work. First one shows binding error in output console. need to talk to manager if I can post error msg here, just wpf standard binding error.
Can anyone share some insights here?
Thanks.
StepView
<UserControl
x:Class="StepView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ScriptHighlighter"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DataContext="{d:DesignInstance local:StepVm}"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<ItemsControl x:Name="XItemsControl" ItemsSource="{Binding Names}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Button
Content="Not Wokring in plugin mode"
Command="{Binding ElementName=XItemsControl, Path=DataContext.DeleteCommand}"
CommandParameter="{Binding}" />
<Button
Content="Wokrs in plugin mode"
Command="{Binding Path=DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}"
CommandParameter="{Binding}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
StepVm
public class StepVm:ViewModelBase
{
public StepVm()
{
this.Names = new List<string>(){"1", "2", "3"};
}
public List<string> Names { get; set; }
public ICommand DeleteCommand => new RelayCommand<string>(n =>
{
Debug.WriteLine($"logic to delete {n}");
});
}
Because MEF loads your UserControl dynamically into the Visual Tree, you are likely to have issues with NameScope, which I think is whats happening here.
WPF XAML Namescopes
To be honest, your use of ElementName binding is problematic, because your are in a DateTemplate which is an encapsulation boundary, so although it works outside MEF its not a typically supported scenario.

Blend UWP flyout tool not staying open

I am currently making a UWP in Blend in Visual Studio 2017 but I am having trouble with the flyout tool. I was hoping to manually control when it opens and when it closes essentially disabling the feature when it closes by itself when it loses focus so that I may be able to interact with other tools or objects in the app before closing the flyout. I have tried adding some C# codes to attempt this but I have had no success. I'm not sure either if this would need to be altered in the template or if it can be done from XAML or preferably C#. I have attached the flyout to a stackpanel and added a button click event in a separate location with the following code:
flyout.AllowFocusOnInteraction = true;
flyout.AllowFocusWhenDisabled = true;
flyout.ShowAt(stackpanel);
I was hoping this would work to keep the flyout open but it doesn't. I have another button that I had in mind to close it with the following C# code:
flyout.Hide();
But it would seem that it is not necessary because it closes automatically still regardless of the code. Does anyone have any suggestions?
Represents a control that displays lightweight UI that is either information, or requires user interaction. Unlike a dialog, a Flyout can be light dismissed by clicking or tapping outside of it, pressing the device’s back button, or pressing the ‘Esc’ key.
For your scenario, the Flyout control is not reasonable choice. You could achieve this by using ContentDialog. And the following code realizes the feature of contentDialog.
<ContentDialog
x:Class="AppUIBasics.ControlPages.ContentDialogExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:AppUIBasics.ControlPages"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="SIGN IN"
PrimaryButtonText="sign in"
SecondaryButtonText="cancel"
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
SecondaryButtonClick="ContentDialog_SecondaryButtonClick">
<StackPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<TextBox Name="userNameTextBox" Header="User name"/>
<PasswordBox Name="passwordTextBox" Header="Password" IsPasswordRevealButtonEnabled="True"/>
<CheckBox Name="saveUserNameCheckBox" Content="Save user name"/>
<TextBlock x:Name="errorTextBlock" />
<TextBlock Text="Lorem ipsum dolor sit amet, consectetur adipisicing elit." TextWrapping="Wrap" />
</StackPanel>
</ContentDialog>
This the official code sample about UWP UI basic that you can refer to. If you insist on using Flyout contorl. You could refer to my code sample. However it is not suggested by the official.
MainPage.xaml
<Button Content="Show Flyout">
<Button.Flyout>
<Flyout x:Name="flyout" Closing="flyout_Closing" >
<StackPanel>
<TextBox x:Name="MyTextBox" Text="You can edit this text by tapping it."/>
<Button Content="close" Click="Button_Click"/>
</StackPanel>
</Flyout>
</Button.Flyout>
</Button>
MainPage.xaml.cs
private bool manual = false;
private void flyout_Closing(FlyoutBase sender, FlyoutBaseClosingEventArgs args)
{
if(manual == true)
{
args.Cancel = false;
}
else
{
args.Cancel = true;
}
manual = false;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
manual = true;
flyout.Hide();
}

Binding the visibility of app bar buttons to controls

I have a very simple Windows Phone 8.1 app. This app has two screens, and for simplicity's sake and because I have some common functions, I've implemented both of these screens within MainPage.xaml. I want to bind the visibility of the AppBar buttons to these screens / panels. Here's what I tried
<Page.BottomAppBar>
<CommandBar>
<CommandBar.PrimaryCommands>
<AppBarButton Icon="Add" IsCompact="False" Visibility="{Binding ElementName=ViewItemsPanel, Path=Visibility}" Label="Add" Click="AddButton_Click" />
<AppBarButton Icon="Cancel" IsCompact="False" Visibility="{Binding ElementName=EditItemPanel, Path=Visibility}" Label="Cancel" Click="CancelButton_Click" />
<AppBarButton Icon="Save" IsCompact="False" Visibility="{Binding ElementName=EditItemPanel, Path=Visibility}" Label="Save" Click="SaveButton_Click" />
</CommandBar.PrimaryCommands>
<CommandBar.SecondaryCommands>
</CommandBar.SecondaryCommands>
</CommandBar>
</Page.BottomAppBar>
Unfortunately this doesn't work - all three buttons are visible on both screens. I could create a dynamic property in code-behind for each of these but I thought there might be a nice elegant way to do something like this - is it possible?
The AppBar isn't in the same namespace as the page and so the bindings to the page's elements resolve. This is the case for any binding of the AppBar to the page.
You can set the AppBar's DataContext to the page in the page Loaded event and then bind to properties on the page.
you could create a grid panel to mimic the app bar, name the grid drop the app bar buttons in it and collapse or make visible as needed. Might not be the most elegant way to do it but it will get the job done.
You can create several app bars in your code behind and set the ApplicationBar property of you page to the appbar you like to display.
I used this solution in a pivot view with 3 pages
var applicationBars = new List<Microsoft.Phone.Shell.ApplicationBar>();
private void MainPivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
switch (mainPivot.SelectedIndex)
{
case 0: ApplicationBar = applicationBars[0]; break;
case 1: ApplicationBar = applicationBars[1]; break;
case 2: ApplicationBar = applicationBars[2]; break;
...
}
}

Flyout changes Page's theme

I'm fighting with little problem on WP8.1 - it took some time, but finally I've managed to localize it - let say that we have a button with a flyout:
<Grid x:Name="LayoutRoot">
<Button Content="reset" VerticalAlignment="Center">
<Button.Flyout>
<MenuFlyout Placement="Top">
<MenuFlyoutItem Text="first item"/>
<MenuFlyoutItem Text="second item"/>
</MenuFlyout>
</Button.Flyout>
</Button>
</Grid>
It works fine, but if we set the DataContext of a page:
public MainPage()
{
this.InitializeComponent();
this.DataContext = this; // without this works fine every button click
}
then there is a problem - the first time we click our button - works fine, but when we click it the second time, along with flyout, the page's theme changes to Light (the changed theme persists after we dismiss the flyout, you will have to reload the page). It looks more or less like in the images below:
Does anybody know what can cause the problem? Any workarounds?
If somebody wants to try - here is a sample code.
I don't know why it's happening, but you can force your page's RequestedTheme when the page is loaded:
XAML
<Page
...
x:Name="myPage">
C#
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
if (App.Current.RequestedTheme == ApplicationTheme.Dark)
{
myPage.RequestedTheme = ElementTheme.Dark;
}
else
{
myPage.RequestedTheme = ElementTheme.Light;
}
}

Show flyout using BottomAppBar

I'm trying to show a simple Flyout (with informational content) when a AppBarToggleButton within BottomAppBar is pressed, but my solution doesn't work. :(
This is my code:
<Page.BottomAppBar>
<CommandBar>
<AppBarToggleButton x:Uid="MapPageAppBarLegend" Label="" Icon="List">
<FlyoutBase.AttachedFlyout>
<Flyout>
<TextBlock Text="Informations here..."/>
</Flyout>
</FlyoutBase.AttachedFlyout>
</AppBarToggleButton>
</CommandBar>
</Page.BottomAppBar>
Nothing appears.. Can anyone help me to showing this flayout?
Thank you very much and sorry for my english language. :)
Pame
Everything is quite clearly described at MSDN (there is also a very good example there):
Nothing appears, because Flyouts open automatically only for buttons (and AppBarToggleButton doesn't derive from Button class):
A flyout attached to a button opens automatically when the user clicks the button. You don't need to handle any events to open the flyout. (This includes controls derived from Button, like AppBarButton
Of course you can add a Flyout to any FrameworkElement but you will have to open it manually:
You can attach a Flyout control to any FrameworkElement object by using the FlyoutBase.AttachedFlyout attached property. If you do so, you must respond to an interaction on the FrameworkElement, such as the Tapped event, and open the Flyout in your code.
In XAML - define your Flyout in Resources and attach it to button:
<Page.Resources>
<Flyout x:Key="myFlyout" Placement="Top">
<TextBlock Text="Informations here..."/>
</Flyout>
</Page.Resources>
<Page.BottomAppBar>
<CommandBar>
<AppBarToggleButton x:Uid="MapPageAppBarLegend" Label="First" Icon="List"
FlyoutBase.AttachedFlyout="{StaticResource myFlyout}"
Click="AppBarToggleButton_Click"/>
</CommandBar>
</Page.BottomAppBar>
And event in code behind:
private void AppBarToggleButton_Click(object sender, RoutedEventArgs e)
{
FlyoutBase.ShowAttachedFlyout((FrameworkElement)sender);
}

Categories