How to pass values (parameters) between XAML pages?
Methods to pass parameters
1. Using the query string
You can pass parameters through the query string, using this method means have to convert your data to strings and url encode them. You should only use this to pass simple data.
Navigating page:
page.NavigationService.Navigate(new Uri("/Views/Page.xaml?parameter=test", UriKind.Relative));
Destination page:
string parameter = string.Empty;
if (NavigationContext.QueryString.TryGetValue("parameter", out parameter)) {
this.label.Text = parameter;
}
2. Using NavigationEventArgs
Navigating page:
page.NavigationService.Navigate(new Uri("/Views/Page.xaml?parameter=test", UriKind.Relative));
// and ..
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
// NavigationEventArgs returns destination page
Page destinationPage = e.Content as Page;
if (destinationPage != null) {
// Change property of destination page
destinationPage.PublicProperty = "String or object..";
}
}
Destination page:
// Just use the value of "PublicProperty"..
3. Using Manual navigation
Navigating page:
page.NavigationService.Navigate(new Page("passing a string to the constructor"));
Destination page:
public Page(string value) {
// Use the value in the constructor...
}
Difference between Uri and manual navigation
I think the main difference here is the application life cycle. Pages created manually are kept in memory for navigation reasons. Read more about it here.
Passing complex objects
You can use method one or two to pass complex objects (recommended). You can also add custom properties to the Application
class or store data in Application.Current.Properties
.
How to pass values between two pages in WPF
Your fixed point of reference is the Application object. You can store stuff in the Properties collection:
string myText = (string)Application.Current.Properties["test"];
Or you can add any kind of data to your derived App class.
Passing parameters between UWP pages
You can use the Windows.Storage.ApplicationData.Current.LocalSettings class to save/restore the settings. You have not to create your own settings class.
Following url may helps you.
https://msdn.microsoft.com/en-us/windows/uwp/app-settings/store-and-retrieve-app-data
And,
Frame.Navigate(typeof(BasicPage), parameters);
Basically, the parameter of navigation methods is suitable for the 'navigation' purpose - like as browsing url, etc.
Because, the navigation methods have feature of save/restore navigation stack. It's useless to save/restore the application settings value. It's not related to 'Navigation' :)
Passing values between XAML pages
You can pass parameter object in Frame
's Navigate(...)
method. So you should write like this.
MainPage.xaml.cs
Player p = new Player();
this.Frame.Navigate(typeof(MainGame), p);
Now that object of Player
can be get in MainGame.xaml.cs
's OnNavigatedTo(...)
method.
MainGame.xaml.cs
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var objPlayer = e.Parameter as Player;
}
How to pass arguments between pages in XAML without causing loading issues
MVVM can help you.
this is a simple view model:
public class MyVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string propAOfPage1;
public string PropAOfPage1
{
get => propAOfPage1;
set
{
if (value != this.propAOfPage1)
{
propAOfPage1= value;
NotifyPropertyChanged();
}
}
}
private string propBOfPage1;
public string PropBOfPage1
{
get => propBOfPage1;
set
{
if (value != this.propBOfPage1)
{
propBOfPage1= value;
NotifyPropertyChanged();
}
}
}
private string propCOfPage2;
public string PropCOfPage2
{
get => propCOfPage2;
set
{
if (value != this.propCOfPage2)
{
propCOfPage2= value;
NotifyPropertyChanged();
}
}
}
private string propDOfPage2;
public string PropDOfPage2
{
get => propDOfPage2;
set
{
if (value != this.propDOfPage2)
{
propDOfPage2= value;
NotifyPropertyChanged();
}
}
}
}
and here is a simple view:
<!-- Page1 -->
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Prop A:" />
<TextBox Text="{Binding PropAOfPage1}" Width="100" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Prop B:" />
<TextBox Text="{Binding PropBOfPage1}" Width="100" />
</StackPanel>
</StackPanel>
<!-- Page2 -->
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Prop C:" />
<TextBox Text="{Binding PropCOfPage2}" Width="100" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Prop D:" />
<TextBox Text="{Binding PropDOfPage2}" Width="100" />
</StackPanel>
</StackPanel>
just set Frame.DataContext
as a MyVM
object, them this MyVM
object will share between your pages. you can navigate freely and need not consider to get or set the control property in each page.
Extended reading: https://www.google.com/search?q=wpf+frame+page+mvvm
best practice to pass parameters between open pages
Naah… the best way is to use a standard pattern that consist of an app ViewModel class, which contains all the common app data that you want to use in the logic layer.
I always do it like this:
1) I use the MainPage automatically created as the "shell" of the app, with a property that is the AppViewModel
.
The MainPage (and thus the AppViewModel
) can be accessed from everywhere in the app, by setting itself as a static field in its own class.
This is the code, simpler than you think:
public sealed partial class MainPage : Page
{
public AppViewModel ViewModel { get; set; } = new AppViewModel();
public static MainPage Current { get; set; }
public MainPage()
{
this.InitializeComponent();
Current = this;
}
}
2) The AppViewModel
itself is a class that must implement the INotifyPropertyChanged
interface, in order to enable bindable properties and functions.
It is common, among developers, to create a base class that implements it and then derive all the classes that needs bindable properties from it.
Here it is:
public class BaseBind : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
protected bool SetProperty<T>(ref T storage, T value,
[CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
}
Then you derive AppViewModel
class (and all the other model and viewmodel classes) from it… populating it with all the common properties that you need to share across pages.
I have even added a derived property, in order to show how you can share even multiple data types at once, and a function:
public class AppViewModel : BaseBind
{
public AppViewModel()
{
// ...
}
// All common app data
private string sampleCommonString;
public String SampleCommonString
{
get { return sampleCommonString; }
set { SetProperty(ref sampleCommonString, value); OnPropertyChanged(nameof(SampleDerivedProperty1)); OnPropertyChanged(nameof(SampleDerivedProperty2)); }
}
public String SampleDerivedProperty1 => "return something based on SampleCommonString";
public String SampleDerivedProperty2
{
get
{
<<evaluate SampleCommonString>>
return "Same thing as SampleDerivedProperty1, but more explicit";
}
}
// This is a property that you can use for functions and internal logic… but it CAN'T be binded
public String SampleNOTBindableProperty { get; set; }
public void SampleFunction()
{
// Insert code here.
// The function has to be with NO parameters, in order to work with simple {x:Bind} markup.
// If your function has to access some specific data, you can create a new bindable (or non) property, just as the ones above, and memorize the data there.
}
}
3) Then, in order to access all this from another Page
, just create an AppViewModel
field in that page, as seen below:
public sealed partial class SecondPage : Page
{
public AppViewModel ViewModel => MainPage.Current.ViewModel;
public SecondPage()
{
this.InitializeComponent();
}
}
...and you can easily bind XAML controls properties to the AppViewModel
itself:
<TextBlock Text="{x:Bind ViewModel.SampleCommonString, Mode=OneWay}"/>
<Button Content="Sample content" Click="{x:Bind ViewModel.SampleFunction}"/>
(Mode=OneWay
is for real-time binding, in order that the property is immediately updated even in the UI, while Mode=TwoWay
is used for those properties that can be edited from the control itself, by the user, in order to interact with app logic).
Hope this helped.
Best regards and happy new year.
Related Topics
Excel Interop - Efficiency and Performance
How to Create a Custom Membership Provider for ASP.NET MVC 2
Coercing Floating-Point to Be Deterministic in .Net
Using Linq to Get the Last N Elements of a Collection
How to Decode a Url Parameter Using C#
Do You Have to Put Task.Run in a Method to Make It Async
Servicestack Request Dto Design
Unrecognized Escape Sequence for Path String Containing Backslashes
How to Add an Item to a Ienumerable<T> Collection
Is It Better to Create a Singleton to Access Unity Container or Pass It Through the Application
Read Xml Attribute Using Xmldocument
How to Select Distinct Rows in a Datatable and Store into an Array
How to Send Emails Through Ssl Smtp with the .Net Framework
How to Read a Pem Rsa Private Key from .Net
How to Move and Resize a Form Without a Border