UWP - Page navigation within another Page ('iOS UIContainerView with UINavigationController embeded' equivalent?) - c#

I'm porting an iOS app to a UWP project and there is something I'd love to do to save a bit of repetition but not sure how to do it.
On iOS I would embed a UINavigationController inside a UIContainerView and be able to push/pop only a section of the screen instead of pushing a full page on top of another.
Is there any way to do something similar on a UWP project? I effectively want to have a Page within a Page, and on the Inner page, be able to push a new page on top of that page.
Example: Have 3 navigation buttons along the top of the page. They are 'Tabs' which load 1 page per button into the area below it. It's a highly customised TabBar. The buttons would be nice to have in their own page with the content for each 3 pages in it's own page.
Currently I'm, doing this by either re-using the buttons along the top in multiple pages. Or I can swap out multiple UserControls manually based on which button is pressed. One UserControl for each page.
Any help on the preferred method for this would be grand!
Cheers,
Dave.

Is there any way to do something similar on a UWP project? I effectively want to have a Page within a Page
If I didn't understand it wrong, you can use Frame.
For Example: On MainPage.Xaml you can define one Frame with three Buttons:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel>
<Button Name="btnPageOne" Content="Page One" Click="btnPageOne_Click"></Button>
<Button Name="btnPageTwo" Content="Page Two" Click="btnPageTwo_Click"></Button>
<Button Name="btnPageThree" Content="Page Three" Click="btnPageThree_Click"></Button>
<Frame Name="MyFrame" Width="500" Height="600"></Frame>
</StackPanel>
</Grid>
And on the click events of three buttons you can navigate the Frame to three pages:
private void btnPageOne_Click(object sender, RoutedEventArgs e)
{
MyFrame.Navigate(typeof(PageOne));
}
private void btnPageTwo_Click(object sender, RoutedEventArgs e)
{
MyFrame.Navigate(typeof(PageTwo));
}
private void btnPageThree_Click(object sender, RoutedEventArgs e)
{
MyFrame.Navigate(typeof(PageThree));
}
and on the Inner page, be able to push a new page on top of that page.
You can define a button on PageOne inside a StackPanel like below:
<Grid Name="rootGrid" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Name="myStackPanel">
<Button Name="myBtn" Click="myBtn_Click">Click Me to add Page</Button>
</StackPanel>
</Grid>
And in the Click event add new Frames to that StackPanel:
private void myBtn_Click(object sender, RoutedEventArgs e)
{
Frame newFrame = new Frame{
Width=100,
Height=100
};
myStackPanel.Children.Add(newFrame);
newFrame.Navigate(typeof(SubPageOne));
}
Here is the basic Demo that I made: FrameNavigationSample

Related

How can I capture WPF events from a Winforms app

I have an WPF User control which is is hosted in an Elementhost. I use elementhost to include an WPF user control in my classical Windows forms app.
Now, from Windows forms side I am trying to capture the mouseDown event that is produced in an WPF label but I don't know how to do it.
Any ideas?
A case might be able to help you. The winform form calls the wpf control.
Create a WPF custom control. The xaml code of the control is as follows.
<Grid>
<Image Margin="10,10,10,90" x:Name="img" Stretch="Uniform" Opacity="1">
<Image.BitmapEffect>
<DropShadowBitmapEffect Opacity="1" />
</Image.BitmapEffect>
</Image>
<TextBox Background="Transparent" Foreground="White" Height="40" FontSize="32" Margin="44,0,56,36" x:Name="txtBox1" Opacity="0.5" Text="" VerticalAlignment="Bottom" /> </Grid>
You need to add the corresponding function to set the effect. The code is as follows.
public void SetSource(string fileName)
{
img.Source = new BitmapImage(new Uri(fileName) );
}
public void SetOpacity(double opacity)
{
img.Opacity = opacity;
}
//
public string GetText()
{
return txtBox1.Text;
}
Create a Winform application and add a reference, otherwise the control will not work properly. The list of references is pictured below.
Regenerate the solution. On the left toolbar, a WPF control appears and drag it to the form.
Use the button control in the winform project to call the corresponding function.
private void button1_Click(object sender, EventArgs e)
{
((UserControl1)elementHost1.Child).SetSource(#"C:\Users\Admin\Pictures\Saved Pictures\9837f99502eba3d01d4fb671cab20c15.jpg");
}
private void button2_Click(object sender, EventArgs e)
{
((UserControl1)elementHost1.Child).SetOpacity(0.5);
}
private void button3_Click(object sender, EventArgs e)
{
string text = ((UserControl1)elementHost1.Child).GetText();
label1.Text = text;
}
Test items: The left side is the traditional Winform control. The right side is the imported WPF control. You can clearly see the "translucent" effect of the picture.
Not sure what exactly you're trying to achieve. Below is a simple example.You can edit the MouseDown event of the UserControl as needed.
If there is a problem, please make your problem clearer and show me the complete code sample that can reproduce your problem for analysis.
UserControl:
<Grid>
<Label x:Name="label" Content="Label" MouseDown="label_MouseDown" Background="AliceBlue" Width="300" Height="200" />
</Grid>
private void label_MouseDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("hello");
}
Add the UserControl reference in the WinForms project, drag and drop the UserControl on the Form1 designer after rebuilding the WinForms project.
The result of running the project and clicking the Label in the UserControl is shown in the figure.

How to create an onClick method for a button that will send the user to the bottom of the page in Xamarin?

In my Xamarin mobile app I'm trying to give a button the functionality to send the view to the bottom of the page whenever the button is clicked. As of right now, the button reveals hidden entries and the user must scroll down to see the entries revealed. I want it to snap to the bottom of the page so the user won't have to scroll.
Thanks!
You could put your content into a ScrollView,and then use ScrollToAsync method to scroll to the position of your entry which you want display.
For example :
<ScrollView x:Name="scroll">
<StackLayout Orientation="Vertical">
<Button Clicked="Button_Clicked" Text="ToBottom"></Button>
....... //your content
<Entry x:Name="entry" Placeholder="entry"></Entry>
</StackLayout>
</ScrollView>
in your page.xaml.cs :
private void Button_Clicked(object sender, EventArgs e)
{
scroll.ScrollToAsync(entry,ScrollToPosition.Start, false);
}

How to save state of a frame that's inside a page?

The question is, when a XAML page is used inside another XAML page, how can I load saved states of both pages?
Details
To make my ProfilePage.xaml simple and reusable, I've created it separately and use it inside pivot of the MainPage.xaml (is that a good approach?)
<Grid>
<Pivot>
<PivotItem>
<Grid/>
</PivotItem>
<PivotItem>
<Frame x:Name="ProfileFrame"/>
</PivotItem>
</Pivot>
</Grid>
When MainPage is loaded, ProfileFrame navigates to ProfilePage.xaml:
this.ProfileFrame.Navigate(typeof(ProfilePage), parameter);
Each page saves state normally using NavigationHelper
private void NavigationHelper_SaveState(object sender, SaveStateEventArgs e)
{
e.PageState["collection"] = collection;
}
The problem is that the MainPage saves state, and then when come back again to the MainPage, ProfilePage needs to be created new, without loading the old saved data.
How can I load state of ProfilePage.xaml when it is used inside frame control of the MainPage.xaml?

Loading a default home page in WebBrowser - Windows Phone

I'm trying to create a page in my app which will show simple text updates, and I'm planning on using a browser window to show this, so, to put it simply I want a browser windows within the app that will only show one page, I don't want the user to be able to navigate to another site.
I've got the browser window added in XAML like so:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<phone:WebBrowser HorizontalAlignment="Left" Margin="12,6,0,0" Name="webBrowser1" VerticalAlignment="Top" Height="595" Width="438"/>
</Grid>
I've then got this in the C# file:
private void WebBrowser_OnLoaded(object sender, RoutedEventArgs e)
{
//SaveFilesToIsoStore();
webBrowser1.Navigate(new Uri("http://www.nokia.ie/"/*, UriKind.Relative*/));
}
Basically, first of all, am I doing this the right way, and if so, how do I get the browser to display the web page?
Thanks.
listen to the browser navigation and stop navigation to any sites that you haven't defined
private void WebBrowser_OnLoaded(object sender, RoutedEventArgs e)
{
webBrowser1.Navigate(new Uri("http://www.nokia.ie/"));
webBrowser1.Navigating += OnNavigating;
}
private void OnNavigating(object sender, NavigatingEventArgs e)
{
//every navigation to any sites that is not www.nokia.ie will be blocked
if(e.Uri.OriginalString != "http://www.nokia.ie/")
{
e.Cancel=true;
}
}

Toolbar Overlay over WindowsFormsHost

I have a SWF object embedded in a WindowsFormsHost Control inside a WPF window.
I'd like to add a toolbar over the swf movie.
The problem with the snippet of code I have below, is that when the new child is added to the host control (or the movie is loaded, I haven't figured out which yet), the toolbar is effectively invisible. It seems like the z-index of the swf is for some reason set to the top.
Here is what it looks like:
XAML:
<Grid Name="Player">
<WindowsFormsHost Name="host" Panel.ZIndex="0" />
<Grid Name="toolbar" Panel.ZIndex="1" Height="50"
VerticalAlignment="Bottom">
[play, pause, seek columns go here]
</Grid>
</Grid>
C#:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
flash = new AxShockwaveFlashObjects.AxShockwaveFlash();
host.Child = flash;
flash.LoadMovie(0, [movie]); // Movie plays, but no toolbar :(
}
Any insight on this issue would be much appreciated.
Update: Since no suitable answer was posted, I've placed my own solution below. I realize this is more of a hack than a solution so I'm open to other suggestions.
Here is my hackaround the WindowsFormsHost Z-index issue.
The idea is to place whatever you need to be overlayed nested inside a Popup. Then to update that popup's position as per this answer whenever the window is resized/moved.
Note: You'll probably also want to handle events when the window becomes activated/deactivated, so the pop disappears when the window goes out of focus (or behind another window).
XAML:
<Window [stuff]
LocationChanged="Window_LocationChanged"
SizeChanged="Window_SizeChanged" >
<Grid Name="Player">
[same code as before]
<Popup Name="toolbar_popup" IsOpen="True" PlacementTarget="{Binding ElementName=host}">
[toolbar grid goes here]
</Popup>
</Grid>
</Window>
C#:
private void resetPopup()
{
// Update position
// https://stackoverflow.com/a/2466030/865883
var offset = toolbar_popup.HorizontalOffset;
toolbar_popup.HorizontalOffset = offset + 1;
toolbar_popup.HorizontalOffset = offset;
// Resizing
toolbar_popup.Width = Player.ActualWidth;
toolbar_popup.PlacementRectangle = new Rect(0, host.ActualHeight, 0, 0);
toolbar_popup.Placement = System.Windows.Controls.Primitives.PlacementMode.Top;
}
private void Window_LocationChanged(object sender, EventArgs e)
{ resetPopup(); }
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{ resetPopup(); }
Another solution I've discovered is to use Windows Forms' ElementHost control. Since I'm using a Windows Form inside a WPF window anyway, why not just use an entire Windows Form and save myself Z-Issue headaches.
The ElementHost control is really useful, because I can still use my toolbar UserControl, and embed it inside the Windows Form. I've discovered that adding a child can be finicky with Windows Forms, so here's a snippet describing the solution:
First, toss in the ActiveX object, then an ElementHost Control, using the designer.
Form1.Designer.cs:
private AxShockwaveFlashObjects.AxShockwaveFlash flash;
private System.Windows.Forms.Integration.ElementHost elementHost1;
Form1.cs
public Form1(string source)
{
InitializeComponent();
toolbar = new UserControl1();
this.elementHost1.Child = this.toolbar;
this.flash.LoadMovie(0, source);
}
Note that the child was not set in the designer. I found that for more complex UserControls the designer will complain (though nothing happens at runtime).
This solution is, of course, still not entirely ideal, but it provides the best of both worlds: I can still code my UserControls in XAML, but now I don't have to worry about Z-indexing issues.

Categories