Flyout changes Page's theme - c#

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;
}
}

Related

Extended WPF Toolkit - ChildWindow do not allow focus parent

I have a ChildWindow that overlays a view that has inputs and buttons. If the ChildWindow is opened i am not able to click any of the buttons which is good. But with TAB i am able to switch the focus and select one of the buttons and hit enter.
Any idea how I can prevent this?
Any help is appreciated...
The code is really simple and nothing special...
MainWindow.xaml
<Grid>
<xctk:ChildWindow Name="chWindow" IsModal="True" WindowStartupLocation="Center">
<TextBlock Text="Hello World ..." />
</xctk:ChildWindow>
<StackPanel>
<Button Content="Load" Click="OnLoadClicked"/>
<Button Content="Re-Initialize" Click="OnInitClicked"/>
<Button Content="Modal dialog" Click="OnModalClicked" />
<ListBox x:Name="listBox" />
</StackPanel>
</Grid>
MainWindow.xaml.cs
public MainWindow(IModuleCatalog moduleCatalog, IModuleManager moduleManager)
{
InitializeComponent();
this.DataContext = this;
this.ConfirmationRequest = new InteractionRequest<IConfirmation>();
this.moduleCatalog = moduleCatalog;
this.moduleManager = moduleManager;
UpdateModulesList();
this.Loaded += (s, e) => this.chWindow.Show();
}
Update: try setting KeyboardNavigation.TabNavigation to Cycle on the child window; this should be a much better solution.
You could try handling the PreviewLostKeyboardFocus event and simply not allowing it through; this should keep focus in your child window.

UWP InkCanvas crashing unexpectedly with a XAML Parse Exception

Whilst using the InkCanvas in an app I'm currently developing I found after moving between pages that had InkCanvases on them the app would crash with a Xaml Parse Exception. It seemed random, however I created a simple app to get rid of as many variables that could be causing this. I added 2 pages to move between with multiple (10) InkCanvases on the second page. The app consistently crashes after moving back and forth between the pages 10 or more times. Below I have added my simple test pages.
Page 1:
<Page>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Content="Navigate"
Click="ButtonBase_OnClick"/>
</Grid>
</Page>
Page 1 Code behind:
public sealed partial class MainPage : Page {
private Frame rootFrame;
public MainPage() {
this.InitializeComponent();
rootFrame = Window.Current.Content as Frame;
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e) {
rootFrame.Navigate(typeof (PageTwo));
}
}
Page 2:
<Page>
<StackPanel>
<TextBlock Text="Sign 1"/>
<InkCanvas Width="100"
Height="100"/>
<TextBlock Text="Sign 2"/>
<InkCanvas Width="100"
Height="100"/>
<!-- Another 8 InkCanvases -->
</StackPanel>
</Page>
I checked the memory profiler to see if the InkCanvases or pages were being held onto in memory but from what I could see they weren't.
Has anyone else experienced this issue? Or is there any known workaround?
Just set the NavigationCacheMode of pagetwo to Required or Enabled as follows:
public Page2()
{
this.NavigationCacheMode = NavigationCacheMode.Required;
this.InitializeComponent();
}
I have tested your code , navigate to pagetwo from pageoneand then navigate from pagetwo to pageone , after about thirteen rounds, the app crashes and throw the exception:
Cannot create instance of type 'Windows.UI.Xaml.Controls.InkCanvas'
So it seems the instance size of InkCanvas for the frame is exceeded. Every time you navigate you will create ten instances for the InkCanvas. So we set the NavigationCacheMode to require , it means
The page is cached and the cached instance is reused for every visit regardless of the cache size for the frame.
You also can set it to Enabled.It depends on your requirements.
More details about instance cache, please see NavigationCacheMode

WPF popup wont close even with StaysOpen="false"

I am trying to achieve the following:
User brings up a context menu in a datagrid.
User selects a context menu item which then opens a popup and displays some information.
when the user clicks anywhere else in the application, not in the popup, the popup closes.
Everything works fine until I come to closing the popup.
From searching elsewhere I am aware that I need Staysopen to be set to false ( which it is)
I also read the best way is to bind the IsOpen value to a property in the view model and set its binding to 2 way ( also done )
As a side note I have found that if I add a textbox and click inside the box, when I then click outside the popup it closes as desired.
Another thing I unsuccessfully tried as a workaround was to programmatically set the keyboard focus on the text box to get the "autoclose" functionality I desired.
Here is code:
xaml -
<Popup Name="PredictionsPopup" Height="200" Width="200" AllowsTransparency="false" StaysOpen="False" IsOpen="{Binding DisplaySummaryPopup, Mode=TwoWay}">
<StackPanel Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
<TextBlock Text="here is some stuff" />
<TextBox Name="hiddenBox" Text="moo"/>
</StackPanel>
</Popup>
Codebehind that sets the property on the viewmodel when the menu item is selected.
private void CurrentPredicitions_OnClick(object sender, RadRoutedEventArgs e)
{
PredictionsPopup.Placement = PlacementMode.MousePoint;
ViewModel.DisplaySummaryPopup = true;
}
Viewmodel property
public bool? DisplaySummaryPopup
{
get
{
return this.displaySummaryPopup;
}
set
{
this.displaySummaryPopup = value;
RaisePropertyChanged(() => this.DisplaySummaryPopup);
}
}
Please let me know if you need anymore details.
Here you have a working example:
MainWindow XAML:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Popup Name="PredictionsPopup" Height="200" Width="200" AllowsTransparency="false" StaysOpen="False" IsOpen="{Binding DisplaySummaryPopup, Mode=TwoWay}">
<StackPanel Background="Red">
<TextBlock Text="here is some stuff" />
<TextBox Name="hiddenBox" Text="moo"/>
</StackPanel>
</Popup>
<DataGrid AutoGenerateColumns="False" Name="dataGrid1" IsReadOnly="True" >
<DataGrid.Columns>
<DataGridTextColumn Header="Site" Width="150" />
<DataGridTextColumn Header="Subject" Width="310" />
</DataGrid.Columns>
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Click Me" Click="ButtonBase_OnClick">
</MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
</Grid>
</Window>
MainWindow cs :
public MainWindow()
{
InitializeComponent();
DataContext = new TestViewModel();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
PredictionsPopup.Placement = PlacementMode.MousePoint;
PredictionsPopup.IsOpen = true;
}
ViewModel:
public class TestViewModel : INotifyPropertyChanged
{
private bool _displaySumarry;
public bool DisplaySummaryPopup
{
get { return _displaySumarry; }
set
{
_displaySumarry = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
I think that your implementation for INotifyPropertyChanged is the one which causes the problem. I tried myself the code and is working now.
After trying to track this problem down I worked out that the issue is something to do with the context menu. I know this because as per the answer above instead of launching my popup via a context menu I launched it from a test button and all worked as expected.
I still don't know the exact reason for this issue but I think its something to do with the fact that the context menu is itself a subclass of popup and the focus isn't being set correctly on the new popup, so it never detects popup loss and closes.
To get round my problem I have added a close button to the popup, and then whenever the active tab in the control that hosts the popup changes it fires an event that the popup picks up and closes.
Had the same problem. The reason was, that the toggle button's ClickMode property was set to "Press". Setting it back to "Release" solved it :).
For me, the solution was to add this line in the constructor of the popup's code-behind:
LostFocus += delegate { this.IsOpen = false; };
Many hours were spent, when such a quickie line was all it took :)
I faced same problem a few times. Every time it was occuring, when a popup was changing its "isOpen" property to true from an event, which was raised from listview or datagrid element, like selectedItemChanged event, or items mouseUp event. I don't know reason, however resolved it by opening the popup from another task with code as below:
Task.Run(()=> Dispatcher.Invoke( () => myPopup.IsOpen = true));
Dispatcher is used to avoid an exception from changing any GUI object property from another than the main thread.

Windows Phone 8.1 MenuFlyout Bug?

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.

Xaml TextBox not behaving

I am trying to create UI from XAML at runtime, with something like
private void Application_Startup (object esender, StartupEventArgs e)
{
this.RootVisual = (UIElement)(XmlReader.Load(e.InitParams["Xaml"])
If I feed it this XAML:
<Canvas
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sdk="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls">
<StackPanel>
<TextBox Width="120" Margin="8" Text="Edit Me" />
<CheckBox Margin="8">Normal</CheckBox>
<ComboBox Margin="8" Width="120" SelectedIndex="1">
<ComboBoxItem Content="First Normal Item" />
<ComboBoxItem Content="Second Normal Item" />
</ComboBox>
</StackPanel>
</Canvas>
then the check box and list behave as expected, but my TextBox does not respond to typing, it stays with its initial value.
The really weird (to me) part is that if I put a handler for KeyDown on to the RootVisual, and in there display a message box, it works. If I have an empty handler or no handler it doesn't.
Do I need to set up some explicit handling for some events? If so, which ones, and how do I handle them?
Upadate: as suggested, I tried putting the dynamic markup into the MainPage of a new app, like this:
public MainPage()
{
InitializeComponent();
var dynamic = XamlReader.Load(xaml);
this.LayoutRoot.Children.Add(dynamic as UIElement);
}
where xaml is a string literal containing the content as above, and everything else is just how VS2010 wizard left it. That works. But I can't see what the effective difference is.
Update update: that's a red herring; the difference is the environment. It works in VS, but not in the Silverlight ActiveX control that I am using in the real app.
Did you define the root namespace on your root element?
<param name="initParams" value="xaml=<TextBox xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' Text='hi'/>" />
Just a shot in the dark here, but have you tried adding the dynamically created content as the child of a static "MainPage.xaml" Grid instead of as RootVisual?
Check for IsEnabled="True" property in your main XAML file, if it is set to false then controls will not be editable.

Categories