This article explains a very simple and straightforward approach to create a multi-page navigation with WPF. If you need to use dependency injection and DI containers, check this article on WPF navigation.
When working in automation, you often use HMI devices that allow you to draw graphics pages and navigate within the application using a menu.
To realize a page-switch application with WPF, you can use the UserControls, which would be the pages, which are contained in a single main window.
In every UserControl you can place:
- All the graphical controls needed to configure the process.
- Charts in real-time, to check analog values, like temperatures, pressures and so on.
- Visualize alarms and events.
- Synoptic schemas.
Code
An example on how to implement the code to switch pages can be fond on this site.
The code is simple, after creating a new WPF project, create a static class that will be the Switcher class that contains the Navigate method.
public static class Switcher { public static MainWindow pageSwitcher; public static void Switch(UserControl newPage) { pageSwitcher.Navigate(newPage); } }
Then in the MainWindow assign the Switcher and write the public method Navigate:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Switcher.pageSwitcher = this; Switcher.Switch(new Page1()); //initial page } public void Navigate(UserControl nextPage) { this.Content = nextPage; } }
Then you can create UserControl and use the following code to change “page”:
Switcher.Navigate(new MyUserControl());
You can also create UserControls that requires parameters and pass parameters in an easy way between pages.
Sample application
I wrote a sample application to demonstrate the use of this class, you can download it from this link.
I still don’t understand how to pass data between pages.Could you tel me??
Hi Komin, i modified the example to make parameter more clear.
Check the new example here: https://www.mesta-automation.com/Downloads/HmiLike.rar
If it’s still not clear don’t hesitate to write me again.
Thanks
OK. But you use instead of pages(1,2,3) new window. I’d like to use pages and class switcher to send data between them.Thanks
Hi Komin, i added a page where you can edit the parameter and return it. It’s very similar to the popup.
Check the new example here: https://www.mesta-automation.com/Downloads/HmiLike.rar
Can I get your e-mail??
I have new thread “receive”where I get data from PLC (ModbusTCP).
In “receive” I update Textbox from MainWindow, I use delegate. My program works well.
But now I’d like to add your multipages and class switcher but I can’t update Textboxes from multipages. I mean that I’don’t have access to Textboxes from new thread.
How to do it??
Thread t = new Thread(new ThreadStart(receive));
void receive()
{
while (true)
{
System.Threading.Thread.Sleep(10);
try { netstream.Read(BuforIn, 0, BuforIn.Length);}
catch (Exception) { }
UpdateTextBox1(Convert.ToString(BuforIn[1]));
}
}
private void UpdateTextBox1(string text)
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate() { textBox1.Text = text; });
}
Hi Komin, it’s difficult to answer with a comment, so i wrote a post and an example.
Check it here: https://www.mesta-automation.com/writing-your-first-hmi-project-in-c-wpf/
In short, you should use static global variables, so you can use them both in the thread and in the user interface. Check the example.
It work nice 😉
But I saw one problem. Something is wrong with window, because if you put e.g. button in right-down corner in Page1 and run application you don’t see all button, it is cutted.
Do you now how to validate group of radiobutton?
Radiobuttons must be used in the same panel to have only one selected.
Every panek that contains radiobuttons permit to select one of them.
About the button, maybe there were problems in your code, because wpf is not “what you see is what you get”, but it’s all related to grids and margins and hooks.
If you want a wysiwyg screen, you have to place controls inside a canvas panel, instead of a grid.
Thank You very much
Thanks alot.
Thanks for this. You have solved big problem.
I am interested to know, its always creating new instance of control and making them context of main form. Here, what is happening with old instance ? Are they still holding memory or are they released ? How can we confirm it?
Thanks,
Hi Prasad, usually the old instance is released from memory, because there are no more references to MainWindow that keeps it alive and so the GC collects the old instance. I said “usually” because there are some memory leaks in WPF that you should be aware of, like a UserControl that contains a DispatcherTimer, if you don’t stop the timer before closing, the UserControl is kept in memory. Same for event subscription etc…
This article solves a problem that all WPF application that contained Pages had, because the journal was keeping pages into memory and causing huge memory leaks.
You can read about it on this post of StackOverflow: http://stackoverflow.com/questions/1925052/do-i-have-a-memory-leak-in-my-wpf-navigation/13258897#13258897
I usually use ANT memory profiler to detect memory leaks, it’s a pay product but you get 14 days trial when installing it. There are also Visual Studio memory profiler, but I never tried them.
is this an article is it