How to switch between two pages without losing their data: WPF, C# - c#

I am using a <Frame ..../> in the MainWindow.xaml to switch between two pages. The problem is that, when I return to a page all data (like textBox.Text and so on) are erased. How can I switch between the pages and keep their information all?
Loading a page is done by ClickHandler of a button in the MainWindow.xaml.cs. below is the code of ClickHandler.
private void ClickHandlerButton1(object sender, RoutedEventArgs e)
{
mainFrame.Content = new page1();
}
private void ClickHandlerButton2(object sender, RoutedEventArgs e)
{
mainFrame.Content = new page2();
}
I believe, once I click the button it creates a new page(), so I actually don't return to the same page() but go to a new page(). Therefore, there are no data to show back. However, I don't know how to get rid of this issue.
Thank you in advance.

You just use cache.
Example.
Page page1 = new Page();
Page page2 = new Page();
private void ClickHandlerButton1(object sender, RoutedEventArgs e)
{
mainFrame.Content = page1;
}
private void ClickHandlerButton2(object sender, RoutedEventArgs e)
{
mainFrame.Content = page2;
}

You are instantiating a new page and storing its reference in the Content property that was referencing the previous page.
There are multiple ways to achieve what you need:
One would be to share the viewmodel (the page where the mainFrame is has a viewmodel shared with page 1 and page 2).
Other way would be to (depending on how is your layout) to use navigation pages, carouselviews or another control that behaves like you expect. This way you keep alive the references of the views.
The third one is what Taehyung Kim said. Another way to keep the references alive is to have 2 variables. Every variable referencing an instance, in your case, page1 and page2. Then everytime that the page has to be loaded, you don't create a new instance, instead, you reuse the stored reference.
Fourth would be using datacontext of the page (for the bindings).
Fifth would be passing data at the constructor of the page (it is less performant than the second way).
Here is a link to microsoft docs that has some parts on passing data between navigations hierarchical navigation

Related

Is there any way to verify if a page is open within frame in WPF?

I'm trying to create a simple application with two pages.
Using one window, I created a frame called frameHolder and within it, I want to open two pages, one is the MainMenuPage and the other is the PicturesPage. I can use frameHolder.Navigate(MainMenuPage) and frameHolder.Navigate(PicturesPage), but every time I click on the button of one of the pages, it creates another instead of going to the one which was already created.
In a simple application like mine there's no problem, but in a big application where you need to save memory it would. How can I verify if a page is open using Frame? If it's not I want to open, if it's open I want to go there.
---- I solved it, for the moment -----
As I said, it's a simple program that only have two pages. It makes it easy to fix using Frame.CanGoBack() and Frame.CanGoForward().
private void goMainMenu(object sender, MouseButtonEventArgs e)
{
if (frameHolder.CanGoBack == true)
{
frameHolder.GoBack();
}
else
{
frameHolder.Navigate(mainPage);
}
}
private void goPicturesPage(object sender, MouseButtonEventArgs e)
{
if (frameHolder.CanGoForward == true)
{
frameHolder.GoForward();
}
else
{
frameHolder.Navigate(picPage);
}
}
I'm basically telling the program that if I can go forward, then do it. If not, create a picPage, for example.
Not sure how I would do it if I had more than two pages though.

UWP Navigate to same Page

I have a Page (showDocuments) that shows documents and folders (like in Dropbox or Google Drive). When a user clicks on a folder I'm trying to navigate to a new instance of the showDocuments Page in order to show the content of the clicked folder. However, when I render the new information, it appears both the new documents and the previous ones.
I could do it by just having one page and cleaning it each time, but I need different pages in order to go back to the parent folders using frame.GoBack(), since it is much faster rather than using frame.Navigate(...) and compute and print everything again.
I'm not using a MVVM model, I just have a page and I decide which objects I need to show on the xaml.cs file.
Should I use views instead of pages?
Thanks for your time.
Try by handle the back button operation to catch parameters and navigating back.
You could have global vars of parent folder: the value (parentFolderVar) you pass to showDocuments Page and isReturn that is setted in OnNavigatedTo Method:
App.parentFolderVar = someValue;
So, when you handle tha back operation in App.xaml.cs:
private void OnBackRequested(object sender, BackRequestedEventArgs e)
{
if (rootFrame.SourcePageType == typeof(showDocuments))
App.isReturn = true;
e.Handled = true;
Pause();
}
And in showDocuments navigation:
protected override void OnNavigatedTo(object sender, NavigationEventArgs e)
{
if(App.isReturn)
//You know the parent folder with App.parentFolderVar
//Make operations
App.parentFolderVar = updatedParentFolderValue;
App.isReturn = false;
}

Windows Phone Page Navigation

I am working on a Windows Phone application, here is the scenario that I have problem:
So I have three pages, lets call it page 1, 2, 3.
In page 1, I have a button called start downloading. Click the button and use NavigateService.Navigate(page2Uri) and navigate to page2.
Page 2 makes query and downloads images from internet, so in its OnNavigateTo handler, I check the page back stack, if it is navigated from page 1, I will do the download. In the app bar of this page, I have a button that can navigate to page3.
Page 3 is a list of options that will perform some behavior on the image that is downloaded in page2. Once I choose an option, I want to go back to page 2 and perform some behavior on the loaded image.Here the question comes: if I use NavigateService.Navigate(page2Uri) to navigate from page3 to page2, it will call the Page2 constructor and OnNavigateTo handler again, which will cause it to lose every instance variable it already got.
But if I use NavigatService.GoBack it will go back to page2, then realizes that the backstack top entry is page1 (since page1 -> page2 -> page3). So it will re-download everything again.
I dont want anything to be downloaded again when navigate back form page3 to page2. So wondering if anyone has good idea about this.
Thank you.
You can use the query parameters and NavigationEventArgs to help.
First, you can use the NavigationEventArgs to determine if the user is going forward or background by checking the NavigationMode.
Second, you can tell page 2 to download by using the query parameters.
From page1:
private void MoveToPage2FromPage1()
{
NavigationService.Navigate(new Uri("/Page2.xaml?shouldDownload=true", UriKind.Relative));
}
and page2:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (e.NavigationMode == NavigationMode.Back) return;
string shouldDownload = ""; //May not be needed if you'll only ever go to page 2 from page 1 to download...
if (NavigationContext.QueryString.TryGetValue("shouldDownload", out shouldDownload))
{
Convert.ToBoolean(shouldDownload);
}
}
There are several ways to pass data to another page:
You can use query parameters as Shawn suggested.
You can use global data stored somewhere like in app.cs
You can use a static class to hold the data.
You can use a shared viewModel to hold the parameters. (or static properties in the viewmodel)
It all depends on the particular case. I think Shawns suggestion of using query paramaters is probably the most 'correct' MVVM way, but the other methods have their place.
You need to implement the following function and the navigation service.
These code will definitely solve your problem
for two or more parameters, use this code
String download="true";
String file="image";
NavigationService.Navigate(new Uri("/Page3.xaml?download="+download+"&file="+file+"", UriKind.Relative));
OnNavigatedTo, add the following code on to your Page2
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
String download=NavigationContext.QueryString["download"];
String file=NavigationContext.QueryString["file"];
}
For the above OnNavigatedTo function outputs true and image. You can use MessageBox.Show(); to output

Serialize and Reload Dynamic Controls

I understand the "why" controls vanish on postback, and up until now I have had great success just creating what I need to do dynamically in page init. However this fell apart for me when I had to add some controls to a asp.net page based on the value of an existing dropdownlist.
So my question is simple, and I don't seem to be able to find a good working code example. I need to add some controls to the page based on the value of a dropdownlist. Then persist these added controls across other postbacks (session is fine).
Here is a snippet to work off of:
protected void Page_Init(System.Object sender, System.EventArgs e)
{
RebuildPlaceholder();
}
protected void ddlGroup_Change(System.Object sender, System.EventArgs e)
{
ExampleDataContext ctxExample = new ExampleDataContext();
var aryExample = (from rslt in ctxExample.mvExample
where rslt.label.ToLower() == ddlGroup.SelectedValue
select rslt);
foreach (var objExample in aryExample)
{
TextBox txtCreated = new TextBox();
txtCreated.ID = "ddl" + objExample.ID;
plcExample.Controls.Add(txtCreated);
}
StorePlaceholder();
}
private void StorePlaceholder()
{
//Need code to store all controls in a placeholder.
}
private void RebuildPlaceholder()
{
//Need code to rebuild all of the controls from Session.
}
I found this related article: Dynamically Adding Controls but I am struggling with the syntax for serializing all the controls, etc.
This can be limited to the child controls of a single placeholder that already exists on a page, just storing/restoring that placeholder's controls is what I am after.
Any version of ASP.NET is fine, if there is something that made this easy in 4.0 great.
Instead try caching the dropdown list selection. Then during the next page load use the cache to set the value selected. Then load the new controls based on that selection.
Session["CacheKey"] = DropDownList1.SelectedValue;
Then to access the Session Cache:
var value = Session["CacheKey"];
Take a look at this Microsoft article
on ASP.NET Caching
I've found that DropDownList.SelectedValue is unavailable during Page.Init. But you can still get access to the value with Request[ddl.UniqueID] and then create and add all your dynamic controls.
It feels kind of like a hack, but the ASP.NET page lifecycle doesn't allow many alternatives, particularly if your controls are not serializable.

Embedding User Controls a bad idea?

I am embedding usercontrols in a panel and using DevExpress Navigator control to navigate from one to the other. What I am concered about is any implications to this method?
I would give examples of what I am concerned about but then I wouldn't need to ask this question...
I have a primary form, ShellForm that has a docked Navigator Control on the left and a docked Panel Control for the rest. I then dock a User Control, say ucSearchPage, in the Panel when the link is clicked.
public partial class ShellForm : XtraForm
{
private ucSearch searchPage = new ucSearch();
private ucEnrollments enrollmentPage = new ucEnrollments();
private ucGeneral generalInfoPage = new ucGeneral();
private ucContacts contactPage = new ucContacts();
public ShellForm()
{
InitializeComponent();
}
private void ShellForm_Load(object sender, EventArgs e)
{
this.pnlShellHost.DockControl(this.searchPage);
}
private void navSearch_LinkClicked(object sender, DevExpress.XtraNavBar.NavBarLinkEventArgs e)
{
this.pnlShellHost.DockControl(this.searchPage);
}
private void navEnrollment_LinkClicked(object sender, DevExpress.XtraNavBar.NavBarLinkEventArgs e)
{
this.pnlShellHost.DockControl(this.enrollmentPage);
}
The code for DockControl() is as follows -->
public static void DockControl(this Control control, UserControl userControl)
{
userControl.Dock = DockStyle.Fill;
control.Controls.Clear();
control.Controls.Add(userControl);
}
Are there any implications to this approach? Is it just plan stupid?
I am one of those programmers that had to learn to run before walking so I have a tendency to fall flat on my face!
There will be about 30 User Controls in all.
Any insight is welcomed and appreciated!
IMO it is not a bad idea at all to embed user controls. In fact, that is exactly what they were meant for. Because every control inherits from the same base class you can build a tree structure of controls using the Composite pattern. This will allow you to create just about anything you would like.
If you think of a basic web page, this is actually what you are doing anyways: placing one element in another, or embedding them. You can have multiple divs in other divs etc. This is essentially what you are doing when you embed user controls as the user controls render to basic HTML.
Hope this helps.
EDIT: To address the concerns in your comment... I don't think you will have a problem from the data entry standpoint. The reason why is because you are using different user controls for your enrollment control and search control. I'm assuming you are overriding the OnLoad event in each of those user controls right? What happens on post back is that the Search's OnLoad will be hit if the search control was loaded, while the enrollment's OnLoad will be hit if that was loaded.
Because of the polymorphism of the user controls, you can handle the data for those controls separately.

Categories

Resources