Creating Pages or Windows in WPF - wpf

I'm new to using WPF. I have the following program I want to create:
-Application opens up with one button
-User clicks button and it takes them to a new page with various input.
I'm confused about how I need to do this. I tried opening a new window, but I don't want a window to open up, I want it to be all one Window. I tried creating a new page and navigating to it using NavigationService but couldn't get it to work.
Basically I want to create a workflow where the user enters some stuff, clicks the next button and is taken to a new page to enter some more information. Can anyone point me in the right direction?

Use Pages in your application and use NavigationService to switch between them.
For example, if you have two pages in your paplication, "Page1" and "Page2" you can include the following in Page1.xaml:
<Button Content="Next" Click="NextClicked" />
and this in your Page1.xaml.cs:
void NextClicked(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Page2());
}
Alternatively you could use this:
NavigationService.Navigate(new Uri("Page2.xaml", UriKind.Relative));
Generally it is easier to do the first, because you can also set properties of Page2. For example, if Page2 has a public "CurrentItem" property you could say:
NavigationService.Navigate(new Page2 { CurrentItem = this.Something });
You can't do that with the Uri-based syntax.
You can also create instances of various pages (Page1, Page2, etc) and store them in your Application object, then switch to them like this:
NavigationService.Navigate(App.Page2);
This way if you ever navigate to Page2 later you will get exactly the same Page2 object. Alternatively you could use NavigationService's Journaling feature to help with this.

Initially there doesn't seem to be much of a difference in the preference of what should be used: Pages or Windows. However, looking at the intended goal of the application, I would suggest using UserControls instead of Pages, as Pages seem to focus on Web related content, though they can be used in stand alone applications as well. Another argument that has been made in another post is referring to the MSDN-documentation, and points out that in using a Page the NavigationWindow that it is hosted in does not remember the instance of the content that is navigated to and thus other WPF-techniques are needed to store that content in your navigation history.
NavigationWindow does not store an instance of a content object in navigation history. Instead, NavigationWindow creates a new instance of the content object each time it is navigated to by using navigation history. This behavior is designed to avoid excessive memory consumption when large numbers and large pieces of content are being navigated to. Consequently, the state of the content is not remembered from one navigation to the next. However, WPF provides several techniques by which you can store a piece of state for a piece of content in navigation history.
If you use a UserControl, you wouldn't have that problem if your goal is to create a native application anyway. You can download this template as an example to use UserControls instead.

The use of the NavigationService is the right way to do that. You have to add a frame to your windows to show your pages, then navigating between them with the NavigationService.

You can change your application object's MainWindow reference to another Window object.
Application.Current.MainWindow = new SecondWindowToBeDisplayed();

Related

WPF fail. Using a WPF page as an instance

Think about a WPF program that has 2 pages which you navigate between. (Upload and Crop)
In the first page, you load an image using a button, select the image, and your image appears in the WPF Image control. Then, you press the "Crop" button. That sends the navigation to the second page, which you can crop the image.
Then, you crop the image in the second page. Then you press "next". Next button must redirect you to the first page, but wait a minute, the image you loaded no longer exist in the page. Because it's a new page.
Dim CropPage As New Crop(Crop_Bmp, Crop_BmpSource)
Me.NavigationService.Navigate(CropPage)
You may think it's okay. Because we pass the parameters and we can refill the WPF Image controls using that parameters. But, there is actually 8 upload panels in the page 1. So, other ones are important.
Or think about another method I found. Instead of using a new page instance, navigate back that you used.
Upload.Crop_Bmp = Crop_Bmp
Upload.Crop_BmpSource = Crop_BmpSource
Me.NavigationService.GoBack()
Upload.Crop()
But in the second one, it throws errors.
"Reference to a non-shared member requires an object reference."
Then, back to the Upload page, I made the variables and functions "Shared". But then, more problems come up. Because you cannot edit the local variables unless you also make them Shared. So, all of the variables and functions need to be "Shared".
I'm searching about a solution for a few days and I could not get rid of them. What method should I use? Redirecting back, or opening a new instance?
In old-type applications, it was very easy. All was that:
Form1.Crop_Bmp = Crop_Bmp
Me.Hide()
Form1.Crop()
And it was working perfectly. Because the forms were not instances like WPF pages. That's the reason I find WPF quite weird.
I found it a way to do this. When navigating to the Crop page, I sent the Upload page as a parameter to Crop Page.
Dim CropPage As New Crop(Crop_Bmp, Crop_BmpSource, Me)
Me.NavigationService.Navigate(CropPage)
Then, in Crop:
Public Sub New(ByVal Crop_Bitmap_ As Bitmap, ByVal Crop_BitmapSource_ As BitmapSource, ByVal pg As Upload)
' This call is required by the designer.
InitializeComponent()
UploadPage = pg
Then, in the Crop page, I accessed that parameter to modify its elements. For example:
Me.NavigationService.Navigate(UploadPage)
UploadPage.Crop()
This sounds like a bad use-case for the Pages metaphor. Pages are for loosely coupled peer screens (E.G. A separate page for each department), but you are using them in a tightly coupled parent-child relationship. (The "Crop" page is the child of the "Upload" page) For what you are doing, launching the crop screen as modal dialog might be more fitting.
If you want to keep everything in the same window, you can keep both functions in the same window, and toggle their visibility as needed.

Out-of-Browser Silverlight and many "pages"

I'm building a Silverlight out-of-browser app that will eventually run on a Windows 7 touchscreen tablet, independent of any browser - it will run just like any other app.
My code, at the moment, is all within one XAML and corresponding .cs file but this is messy and I'd like to split it out and call each page as and when required i.e. Main.xaml, AboutUs.xaml, Contact.xaml etc.
Is this possible in an OOB app? I tried to use the frame and pages controls, but when I set the source to one of my new XAMLs via a button click i.e. "/AboutUs.xaml", it tells me that it's an invalid URI.
Thanks,
Greg.
Try and create a root canvas (e.g: myCanvas) in your MainPage.xaml to act as a container which displays all your pages.
On navigation clicks, write this.
myCanvas.Children.Clear();
myCanvas.Children.Add(new myPage());
A good practice is to set a public property on every page
public MainPage parentPage;
in this case, to which you can assign the parent page that hold that root canvas (myCanvas in case). On further pages, you just navigate using
parentPage.myCanvas.Clear();
anotherPage tempPage = new anotherPage();
tempPage.parentPage = parentPage;
parentPage.myCanvas.Add(tempPage);

How to make WPF page navigation code look better?

I want to make a program by WPF which includes several pages.
I have a Window and several Pages now.
In order to navigate, I use
this.Content = new Page1();
in the main window (from Window to Page), and
((Window)this.Parent).Content = new Page1();
between pages (from Page to Page), because Page can only be sub-element of Window or Frame.
However, the second line of code above looks quite ugly.
Is there a better way to achieve the same goal?
I have coded from several Windows Phone applications before, and I think it might be better to navigate between Pages rather than hide/show elements (such as Grids).
If your navigation code is on your Page class, either :
move it to the window class
create an event in the Page class, and react to it on the Window class.
Is there any reason why you can't just put a Frame in your Window ?
You could use NavigationService.
http://msdn.microsoft.com/en-us/library/ms750478.aspx
http://www.paulstovell.com/wpf-navigation
Maybe this could help:
http://azerdark.wordpress.com/2010/04/23/multi-page-application-in-wpf/

How do I get the NavigationService without being a Page?

This seems to be a really naive question, but how on earth does one get the NavigationService from outside of a page, like say perhaps a view model? Everybody says that navigation should occur at the view, but I keep thinking, this is not a web page, its an application. The view model and business logic should control application flow, not the view. Is this in fact naive?
As far as I understand it, operations involving the View, i.e. UI, should be done by the View exclusively. When working with MVVM, the UI should not be controlled by the ViewModel or BusinessLogic directly (since they are not supposed to know anything about the concrete implementation of the View) but work with Messages.
That means, if we want to open an Editor window from the ViewModel we send a Message from the ViewModel that we want to open it and receive it in the View and open the window there. The same is valid for Navigating through different pages, where you would receive the Message in the MainPage (or whatever holds you pages that you want to navigate through) and handle everything there.
An alternative to that would be using a DialogService or something like that, which handles opening windows in a central place. However, since the NavigationService is a property of the Page class, we need to handle the message in the Page.
Example code, using the MVVM Light Toolkit: (not tested, partly taken from Shawn Wildermuth's RiaXBoxGames example):
ViewModel (e.g., put that in a Command for a Button):
Messenger.Default.Send<bool>(true, "GoToNextPage");
View (e.g. put that in a Constructor):
Messenger.Default.Register<bool>(this, "GoToNextPage", ignore =>
{
// your code to go to next page
});
another option is to create an event on ViewModel, fire this event when Command occurs and subscribe View to this event. Inside EventArgs you can carry which page to navigate to etc. I think simple and testable solution.
Robert
I just pass a reference to the Frame when I create the View-Model.

How do you switch between "pages" of a Silverlight application?

I am currently loading the default file, page.xaml, but in that page, I am loading the content from another xaml file. With each "page" change, I just load the content from a different xaml file, and on and on.
Example: this.Content = new StartPage();
I'm running into some syntax issues, however, because of the way I am changing my content, and was wondering if there is a definitive answer on how to accomplish this?
For example, when trying to capture user's keystrokes, I would normally do:
this.Keydown += new KeyEventHandler(this_KeyDown);
but that event handler doesn't even fire in my situation. So, I'm looking for a new approach to my content-switching approach before revisiting the keystroke problem.
Have you looked at using Silverlight 3. It has a new Page Navigation functionality.Silverlight 3 Navigation
As far as content switching goes, I've always done what you propose in the question. Normally I create a MainPage.xaml which has has the frame of the application (usually a Grid for me). One of the cells in the Grid is considered the content area of the app. When the user takes an action that I would consider to be navigation, I create a new instance of a Page, which for me is a file like MyUserControl.xaml, and then add it to the appropriate content cell in the Grid. MainPage stays around for the life of the application and assists with navigation.
If you want something fancier, and want to take advantage of browser based back/forward buttons, you could look into the SL3 navigation like Correl suggested.
A Big problem with what your're doing is that journalization doesnt take place automatically when you swap out framework elements by creating them and plugging them in the codebehind. This means that you lose the back and forward functionality of the browser. You can manually journalize stuff when you swap out pages, but this is simply a hack to get your navigation approach working.
Take a look at Prism at www.compositewpf.codeplex.com/, specifically the MVVM method of GUI design, it'll save you alot of time later on. And remember, you dont need to go hardcore when you look at MVVM, u could always cut out alot of "dynamic" functionality if you're a one man band
Also swap to silverlight 3 and use the navigation application. If you cant, take a look at helix 0.3, it'll provide a more asp oriented approach to navigation. the link provides a really really good starting point, its a three part article, i suggest you read all three and download the sample application and understand it.
A book could have been written on your question, this has to suffice for now.

Resources