UWP - Save attributes of a xaml page (Slider/Combobox) - xaml

I've got the following problem: In my main xaml page I've got a button which navigates to an other page which is called settings and which also includes settings for the app. I jump to the page with the following method:
this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(Settings::typeid));
As you can understand I want the UI-Elements (Comboboxes/Sliders) to save theier attributes for the next time. Not even for the next launch of the app, just for the next jump on the settings page. If I go back from settings to main page and back to settings again, the values of the comboboxes and slider are reseted. I need them to be saved for my program's logic.
In my c++-desktop app I'm using registry entrys in order to save it, but this is not quite possible in uwp and it's not the easiest solution. In Java I would use a global static variable which saves the values and which is bind to UI-elements. How can I implement this in UWP ?

You can achieve that with the Page.NavigationCacheMode Property. With that property you are able to store the state of the page in the cache of the application.
You can either use it in the xaml-tag of the page, or set in the constructor in the code-behind of the page. You can find the possible values of the properties here.
Example-XAML:
<Page
x:Class="Foo.Namespace.SettingsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Foo.Namespace"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
NavigationCacheMode="Enabled">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
</Grid>
</Page>
Example CS:
public sealed partial class SettingsPage : Page
{
public SettingsPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Enabled;
}
}

Related

Template10 ModalDialog xaml error - Cannot create an abstract class

I have a UWP application based on the Template10 hamburger template. I added the following modal dialog.
<Controls:ModalDialog x:Name="LoginModal"
CanBackButtonDismiss="False"
DisableBackButtonWhenModal="True">
<Controls:ModalDialog.ModalContent>
<views:LoginView x:Name="loginPart"
HorizontalAlignment="Center"
VerticalAlignment="Center"
HideRequested="LoginHide"
LoggedIn="LoginLoggedIn" />
</Controls:ModalDialog.ModalContent>
</Controls:ModalDialog>
My login view is declared like this
[Export]
public sealed partial class LoginView : Page, IView
{
....
}
For some reason the xaml extract above gives me a design time error saying "Cannot create an abstract class." The project builds and runs ok but the xaml designer won't work.
Anyone know what I'm doing wrong here?
LoginView would need to be a UserControl not a Page. The other properties would be added to that codebehind of that usercontrol to allow for interaction with the ModalDialog
From the Samples folder...
https://github.com/Windows-XAML/Template10/blob/master/Samples/Search/Controls/LoginPart.xaml.cs
if this doesn't work then I would suspect the MEF [Export]

What element to use if I only need an placement target element

I want to show a flyout at a specific place. I want to specify a placement target element in XAML, but I want to make sure I am using the "lightest" element possible, given that I don't want that element to ever be visible or interacted with.
Is there a "recommended" or "correct" element to use? If not, what would be the "lightest" element to use? Or am I overthinking this and should just use a button?
I want to show a flyout at a specific place.
The place of FrameworkElements are based on the panel that you are using to hold them. If you want to show your flyout based on a FrameworkElement being placed in a specific place, you can use Canvas to position your FrameworkElement.
I want to specify a placement target element in XAML, but I want to make sure I am using the "lightest" element possible.
Flyout.ShowAt takes FrameworkElement as it's placement target. So I think the "lightest" element would be an empty custom FrameworkElement like below:
public class MyElement:FrameworkElement
{
}
And you can put it into XAML and use Canvas to position it:
<Page
x:Class="PopupSample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PopupSample"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Canvas>
<Button Name="btnClick" Canvas.Left="50" Canvas.Top="500" Click="btnClick_Click">Click Me</Button>
<local:MyElement x:Name="myEle" Canvas.Left="100" Canvas.Top="100"></local:MyElement>
</Canvas>
Code-Behind:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void btnClick_Click(object sender, RoutedEventArgs e)
{
Flyout flyout = new Flyout();
TextBlock tbContent = new TextBlock
{
Text= "this is a flyout content"
};
flyout.Content = tbContent;
flyout.ShowAt(myEle);
}
}
Grid is a pretty light element, it's just a simple Panel-derived class without any child elements. Button is a Control, meaning it has a template which will create many child elements that make up its visual appearance.
Are you saying you want to use a dummy element just for the purpose of specifying the position of the flyout which you will show programmatically? If you want to avoid the element altogether, then maybe a Popup would be a better choice.

CompositeCollection containing an ICollectionView

I'm trying to implement a tab control, where each item comes from an ICollectionView of my viewmodel. Each tab page, for the items from the ICollectionView will be the same. However, I would like there to be an extra tab page for configuration options.
So an example tab header 'screenshot' might be:
tabA | tabB | tabC | config
on another instance, it could be
tabA | config
or
config
I can define the header for each item using ItemTemplateSelectors, and the content using the ContentTemplateSelectors. So that bit should be okay.
I'm having trouble with adding the config page item since I do not know where to add it. I thought I could set the tab's ItemsSource to be a CompositeCollection, where the final item is the config page object. I have failed to achieve this.
In the following example, I can view the tab headers being populated correctly according to the designer sample data which I have set up - I have not yet added the config page.
<controls:MetroTabControl ItemsSource="{Binding View}">
<controls:MetroTabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value.siteDisplayName}" />
</DataTemplate>
</controls:MetroTabControl.ItemTemplate>
<controls:MetroTabControl.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value.siteComment}"/>
</DataTemplate>
</controls:MetroTabControl.ContentTemplate>
</controls:MetroTabControl>
As you see, I have set the ItemsSource to be {Binding View}. This "View" comes from my ViewModel and is an ICollectionView.
Ideally i'd be able to do some magic like:
<controls:MetroTabControl>
<controls:MetroTabControl.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding View}"/>
<SomeConfigPageObject/>
</CompositeCollection>
</controls:MetroTabControl.ItemsSource>
...snip...
</controls:MetroTabControl>
But the problem is that when I do the above, the designer preview of the control acts as if there are no items in the ItemsSource.
For reference, each item in the {Binding View} is a object which contains a Value property, the value property containing an object that contains, in this example, a siteDisplayName and siteComment.
For reference, the DataContext for the tab is defined the dockpanel that contains it, as follows.
<DockPanel DataContext="{Binding Source={StaticResource Configurator}}"
d:DataContext="{d:DesignInstance cfuid:ConfigSiteVMSampleData, IsDesignTimeCreatable=true}"
LastChildFill="True">
For reference, the Configurator is my viewmodel and is instantiated in the xaml as:
<UserControl.Resources>
<ResourceDictionary>
...snip...
<cfvmc:ConfigSiteVM x:Key="Configurator" />
...snip...
So, the actual question would be:
How do I add my "config page" at the end of the tab control? Preferably via using the above-hoped method of adding an extra config-page object on the CompositeCollection; however if this is not possible [1] i'm open for suggestions.
[1] I think it doesn't work because the {Binding View} is an ICollectionView and the CompositeCollection requires a "collection" and doesn't accept a "view"
Thank you.
Peter.
I decided to do it through code behind. This means that I do lose my ability to use the design-time data to preview my UI; but it works at run time.
So, in the xaml I have.
<controls:MetroTabControl Grid.Column="0" Grid.ColumnSpan="2"
Grid.Row="0" Grid.RowSpan="2"
ItemsSource="{Binding ElementName=ucMe, Path=TabSitesCollection}">
Where ucMe is the UserControl and TabSitesCollection is a
protected CollectionViewSource m_TabSitesCollectionViewSource;
protected CompositeCollection m_TabSitesComposites;
public ICollectionView TabSitesCollection
{
get { return m_TabSitesCollectionViewSource.View; }
}
That gets initialised in the constructor as follows
public ConfigSiteView()
{
m_TabSitesComposites = new CompositeCollection();
m_TabSitesCollectionViewSource = new CollectionViewSource();
m_TabSitesCollectionViewSource.Source = m_TabSitesComposites;
InitializeComponent();
}
Then, on the Loaded event I can do
m_TabSitesComposites.Add(new CollectionContainer() { Collection = GetModel.View });
m_TabSitesComposites.Add(new TabItem() { Header = "hi" });
m_TabSitesComposites.Add(new TabItem() { Header = "ho" });
This results in almost my desired UI
I now simply need to spiff up my settings tab item and i'm done.
For reference, the xaml designer does not have any preview data - Unless I change the xaml so that the preview loads up (which then breaks the actual execution)
It would have been nice to have it both work while running, and on preview, but I haven't figured out how to do that, and it's not a current priority.

Navigate to the last frame from SwapChainBackgroundPanel

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.

ApplicationBar not working after navigation Windows 8

I am developing simple app on Windows 8.
I have two UserControls: Locations and LocationsMap.
I am trying to navigate between them. For that I have added to static methods into App. They are like this
public static void ShowLocationsMap()
{
var page = new LocationsMap();
Window.Current.Content = page;
}
Navigation works fine.
But there is a problem. I am calling this method from button in ApplicationBar. XAML looks like this
<ApplicationBar x:Name="BottomAppBar" Height="88" VerticalAlignment="Bottom" Style="{StaticResource AppBarStyle}" Grid.Row="1">
<StackPanel Orientation="Horizontal">
<!-- Margin="left,top,right,bottom" -->
<StackPanel Orientation="Vertical" Margin="5,14,5,14">
<Button Content="Map" Click="MapButton_Click"></Button>
</StackPanel>
</StackPanel>
</ApplicationBar>
And I am navigating back by calling other function from next page.
The problem is that when I navigates back, ApplicationBar stopping to work. It is not showing after right click. If I set BottomAppBar.IsOpen to true, it shows up, but didn't closing.
Where is the problem?
P.S.
ApplicationBar is not working as well in case when I am navigating to other page from button on controls XAML, so problem is not on button inside AppBar.
For navigation I was using sample code downloaded from internet. That code was using static functions defined in App class, which were changing Window.Current.Content.
That was bad idea. Instead if that I just need to use Frame navigation.
When using it we need to change type of our controls from UserControl to Page.
Application bar works great with navigation now.
Hope this will help someone.