C
C#•4mo ago
ZASLON

[SOLVED] (WPF) Textblock inputs not saving on Navigation to new page?

(SOLVED - Solution Below) I'm currently having trouble with page navigation in WPF, I currently have a MainWindow with a sidebar, and a Frame in the middle of the window to display new pages. The sidebar navigation seems to work fine, but the issue is whenever I navigate to a new page and back, it doesn't save any of the information that was filled out in any of the textblocks. C#
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); MainFrame.Navigate(new Uri("P1Home.xaml", UriKind.RelativeOrAbsolute)); } private void BtnHomePage_Click(object sender, RoutedEventArgs e) { MainFrame.Navigate(new Uri("P1Home.xaml", UriKind.RelativeOrAbsolute)); } private void BtnDependencies_Click(object sender, RoutedEventArgs e) { MainFrame.Navigate(new Uri("P4Dependencies.xaml", UriKind.RelativeOrAbsolute)); }
I have tried using KeepAlive=true for each page with no luck, I was thinking the issue was that when each button is pressed I am "recreating" the page instead of moving back to it, so it is erasing the inputs(?) (If it helps, I am using .NET 6.0) Thanks in advance, (Sorry if the question is a bit basic, I am still learning a lot)
7 Replies
SpReeD
SpReeD•4mo ago
Afaik, you need to somehow save the instance, since WPF creates a new instance everytime you navigate to a different page. This can be achieved by a so called NaivgationManager class or just something that looks up if there's already an instance of that page and loads it. I usually used a static (global-runtime) List<MyPage> and made a simple Manager-class by using a method NavigateToPage(string pagename) that made the lookup. In addition I suggest to use the MVVM pattern with WPF or, at least, the Binding part of it. Bind the Source of your <frame/> to an Observable Property which is a Page and only change this property. Which sits in the DataContext / ViewModel of your MainWindow. So that your Manager only changes the ViewModel layer, not directly an object of your View.
ZASLON
ZASLON•4mo ago
Ohh okay, yes I was looking into MVVM but wasn't sure if it was what I needed. As far as I understand, by using MVVM I will basically be loading the page into the frame and any other page "on top" of it so it won't erase the data thats already entered(?) For some background on the program, its just supposed to be a simple interface that will take the user inputs to generate and structure a .xml file to be opened, so I was also guessing I would need to store the entries as strings anyways for that purpose? Sorry for the long response, just making sure I'm understanding right
SpReeD
SpReeD•4mo ago
Everything depends on the context of the application imho. By referring to the KISS principle don't overcomplicate your structure and patterns, but still use basic OOP principles. A simple eventdriven WinForms app would be suitable as well. MVVM is yet another pattern which comes with a lot of rules and best practices, which might be an overkill for a simple one window application, plus, it produces some overhead which isn't always beneficial. All in my humble opinion. For storing the information, would like to store it only in runtime or on disk, so it'll be loaded the next time the application starts? In both scenarios you would need the mentioned NavigationManager, which can be one simple method.
ZASLON
ZASLON•4mo ago
For storing the information, would like to store it only in runtime or on disk, so it'll be loaded the next time the application starts?
I just need to store it for the duration of the runtime, no need to save it for when the application reopens To my knowledge, if I wanted to store it for when it reopens, I could use .settings, but I don't need that functionality Sorry, but a new discovery: If I leave the navigationUI visible, and I click the back or forth button, it seems to keep the information in the textboxes. But when I navigate by clicking on the buttons I have in my sidebar (shown in the code above) it clears all the values.. It seems the way I have the buttons set up, it keeps creating a new instance of each page everytime I click it, instead of navigating back to it. I suppose I could add a check in each button to check if the window is already open or not? (Not sure of that process, but just an idea)
SpReeD
SpReeD•4mo ago
As I mentioned before, one way to ensure that only one instance is created during runtime and always refer to it is to use some simple manager; usually peeps have disabled the navigationbar on the frame element tho. You could do something like this: Having a runtimestorage or globals:
internal static class Globals
{
internal static List<Page> Pages { get; } = [];
}
internal static class Globals
{
internal static List<Page> Pages { get; } = [];
}
Preload the pages on app start
private static void LoadPages()
{
foreach (Type typePage in MyAssembly.GetTypes().Where(x => x.Namespace.Contains("Pages") && x.IsSubclassOf(typeof(Page))))
{
Globals.Pages.Add((Page)Activator.CreateInstance(typePage));
}
}
private static void LoadPages()
{
foreach (Type typePage in MyAssembly.GetTypes().Where(x => x.Namespace.Contains("Pages") && x.IsSubclassOf(typeof(Page))))
{
Globals.Pages.Add((Page)Activator.CreateInstance(typePage));
}
}
And navigate with a simple method:
public static void Navigate(string pagename)
{
Page p = RuntimeStorage.Pages.Find(x => x.GetType().Name.ToLower().Contains(pagename, StringComparison.InvariantCulture));
if (p == null)
{
return;
}
((MainWindowViewModel)Application.Current.MainWindow.DataContext).CurrentFramePage = p;
}
public static void Navigate(string pagename)
{
Page p = RuntimeStorage.Pages.Find(x => x.GetType().Name.ToLower().Contains(pagename, StringComparison.InvariantCulture));
if (p == null)
{
return;
}
((MainWindowViewModel)Application.Current.MainWindow.DataContext).CurrentFramePage = p;
}
ZASLON
ZASLON•4mo ago
Ah okay, that makes sense. I'll try and implement that. Thanks so much for the help, I appreciate it 🙂 Sorry again, just thought I would post here as I've been able to fix the issue for anyone having a similar problem: Essentially I went and created a static instance of each page at runtime, so instead of the NavigationService creating a new instance of each window when navigating with my sidebar, it would simply load the static instance of each page that would save each time I navigated. Example below: App.xaml.cs
// Defining static instances of each page
public static class PageInstances
{
public static PageOne PageOneInstance { get; } = new PageOne();
public static PageTwo PageTwoInstance { get; } = new PageTwo();
// Any other Pages here
}
// Defining static instances of each page
public static class PageInstances
{
public static PageOne PageOneInstance { get; } = new PageOne();
public static PageTwo PageTwoInstance { get; } = new PageTwo();
// Any other Pages here
}
MainWindow.xaml.cs
// Navigation logic via buttons (sidebar)
private void BtnPageOne_Click(object sender, RoutedEventArgs e)
{
MyFrame.NavigationService.Navigate(PageInstances.PageOneInstance);
}

private void BtnPageTwo_Click(object sender, RoutedEventArgs e)
{
MyFrame.NavigationService.Navigate(PageInstances.PageTwoInstance);
}
// Navigation logic via buttons (sidebar)
private void BtnPageOne_Click(object sender, RoutedEventArgs e)
{
MyFrame.NavigationService.Navigate(PageInstances.PageOneInstance);
}

private void BtnPageTwo_Click(object sender, RoutedEventArgs e)
{
MyFrame.NavigationService.Navigate(PageInstances.PageTwoInstance);
}
Similar to the solution that @SpReeD had provided above, thank you again for your help.(and sorry again for the ping lol)
SpReeD
SpReeD•4mo ago
No problem, I'm glad I could help