How to Pass Values (Parameters) Between Xaml Pages

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



Leave a reply



Submit