MVVM Light 5 - Navigation Service passing wrong parameter - mvvm-light

I have upgraded to MVVM Light 5 and I changed my navigation methods from:
Messenger.Default.Send(new NavigateToPageMessage() { PageName = "UserDetailsPage", Parameter = id });
To the following:
_navigationService.NavigateTo(ViewModelLocator.UserDetailsPageKey, id);
The parameter I am passing does not seem to make it's way to the OnNavigatedTo event of the view anymore, the parameter is completely different, am I missing something?
EDIT:
This new method seems to give me the parameter I need:
GlobalNavigation.GetAndRemoveParameter(NavigationContext)
Although now, when the app is tombstoned, I lose that parameter entirely. Before, when the app was restored I would still have that parameter in the NavigatedTo args, this allowed me to re-hit the server with that ID and get fresh data. Why have I lost this capability

use this
protected override void OnNavigatedTo(NavigationEventArgs e)
{
GalaSoft.MvvmLight.Views.NavigationService navigationService = new GalaSoft.MvvmLight.Views.NavigationService();
var param = navigationService.GetAndRemoveParameter(this.NavigationContext);
base.OnNavigatedTo(e);
}

Related

Xamarin Forms and IEventAggregator

Making my APP for my job I'm getting stuck on a problem:
I have a base page to fill with information for an order
1 Client
2 Destination
3 Article
When I tap on a button I get a new page (different for what I'm serching Client, Destination, Article) with a listview of the item. On a tap of the item I would like to pass the parameter to the main page to compile the order.
I think that the better solution is to implement the IEventAggregator of PRISM, I have made also some test and it work with button, but if I try to put it on the itemtapped, it give me error.
I have created the class for the event to pass the payload.
This is the xaml.cs of the page that (in theory) must pass the selected client to the mainpage:
IEventAggregator _ea;
private Cliente cliente_selezionato = new Cliente();
...
public void TapCliente(object sender, ItemTappedEventArgs e, IEventAggregator ea )
{
cliente_selezionato = (Cliente)
((ListView)sender).SelectedItem;
_ea.GetEvent<CambioClienteEvent>().Publish(cliente_selezionato);
Navigation.PushModalAsync(new DatiTestataOC());
}
On the mainpage viewmodel I have:
public DatiTestataOCViewModel(IEventAggregator ea)
{
ea.GetEvent<CambioClienteEvent>().Subscribe(NuovoCliente);
}
private void NuovoCliente(Cliente Parameter)
{
Cliente = Parameter;
}
The error that I get are:
Errore XFC0002 EventHandler "TapCliente" with correct signature not found in type "Mokadroid.Views.SceltaClientePage".
Errore XFC0004 Missing default constructor for "Mokadroid.ViewModels.DatiTestataOCViewModel".
If you have Other solution more easy to implement I'm Open...
Thanks
I've understand that I can't simply use that part of the package, I need to start a new template using the prism template and use all the package.

How to keep the page state of previous page when going back from Navigation service?

I have a question about Prism Navigation related on Xamarin.Forms.
Let's say that I have 3 pages, the Navigation stack looks like Navigation/ViewA/ViewB/ViewC. When navigate from ViewA to ViewB, I have a List to pass as parameter, so basically in ViewB I will use OnNavigatedTo method to get the parameters and set the data to some bindable properties.
Then, from ViewB to ViewC, I also need to pass that same parameter, so this parameter is kind of going though the 3 views.
Then problem happened, when I go back from ViewC to ViewB, ViewB will still call OnNavigatedTo to get the parameters, but this time, since it's navigated from ViewC, so ViewC did not have the code to pass that parameter to ViewB.
Then, ViewB cannot get the parameter, then if by that time when to go to ViewC again, ViewC will not have the data that it needs to bind to the bindable properties.
So, my question is: Do I have to pass the same parameter again from ViewC to ViewB? If that's the resolution, then wouldn't it be a little bit stupid to do so? Any solution that we can keep the state of the previous page and when we go back from ViewC, everything is just there?
Thanks and look forward to the solution or any insights on this.
I only reproduce the issue and I know I can pass back the parameter again, but that will definitely not be an ideal solution for this problem.
Let's see. In ViewA:
private async void Navigate()
{
var parameter = new NavigationParameter();
parameter.Add("SomeData", list);
await _navigationService.NavigateAsync("ViewB", parameter);
}
In View B:
public void OnNavigatedTo(NavigationParameter paramters)
{
// This code will be null when going back from ViewC
var list = parameters["SomeData"] as List<string>();
this.SomeBindableData = list;
}
ViewB used the same method as ViewA's navigate, and the problem occured when coming back from ViewC.
I would like an ideal solution for this problem. And please do help to check this by some guy from Prism team, I believe this is something needs to be handled.
While the View is in the Stack it won't be disposed or anything, so its state will be kept. Here you just have to know if your View is initialized or not:
In ViewB:
private bool _isInitialized;
public void OnNavigatedTo(NavigationParameter paramters)
{
if (_isInitialized)
return;
// This code will be null when going back from ViewC
var list = parameters["SomeData"] as List<string>();
this.SomeBindableData = list;
_isInitialized = true;
}

ASP.NET MVC Registering custom culture and internationalization

I have an ASP.NET MVC 4 project and I've registered the custom culture in it because I want to have a client-specific translation.
I call the following helper method with parameters like RegisterCulture("en-GB-CustA", "English (Customer A)", "en-GB"); This call is done in Application_Start event handler of the MvcApplication : HttpApplication class.
private static void RegisterCulture(string cultureCode, string cultureName, string baseCultureCode)
{
var ci = new CultureInfo(baseCultureCode);
var ri = new RegionInfo(ci.Name);
var builder = new CultureAndRegionInfoBuilder(cultureCode, CultureAndRegionModifiers.None);
builder.LoadDataFromCultureInfo(ci);
builder.LoadDataFromRegionInfo(ri);
builder.CultureEnglishName = cultureName;
builder.CultureNativeName = cultureName;
try
{
builder.Register();
}
catch (InvalidOperationException)
{
}
}
The method is fairy simple, it basically creates new culture based on existing one and replaces it's name.
Now in my Global.asax just for the testing purposes I've put the following code to MvcApplication class to switch current thread for the custom one.
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
var ci = new CultureInfo("en-GB-CustA");
Thread.CurrentThread.CurrentUICulture = ci;
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(ci.Name);
}
I've also included two resources files. One is called Test.resx which is for the default texts, the second one is Test.en-GB-CustA.resx. I've added a simple string resource there called Title with two different values.
Test.resx => "Hello World!"
Test.en-GB-CustA => "Hello from custom culture!"
I've also put on one of my view the code to display this title (I've added ViewRes as s CustomToolNamespace for both resource files for simplification).
#ViewRes.Test.Title
Unfortunatelly even though I've set the custom culture as descibed before I'm getting the detault "Hello world" value all the time. What am I missing here?
I know it sounds really simple, and this is an old-ish thread but have you tried rebooting?
Your code looks fine.
I had exactly the same problem, the new custom culture (locale) was being created correctly, but not being applied against the resource file of the correct name. Restarting was the only thing that applied the setting changes.
The only other thing to check, is that you are running with administrator privileges - as you need these to create a new locale.
See here:
http://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.aspx
I ended up renaming the code form my custom culture so something like en-XX. I've also have to define both TwoLetterISOLanguageName and ThreeLetterISOLanguageName and it registered properly.

Notifying that all properties have changed on a ViewModel

I am working on a Silverlight application using V3 SP1 of MVVM Light Toolkit.
My application is fully French/English. All UI elements (buttons, labels, etc.) and all the data (models). I need dynamic language switching and this is fully implemented and works with anything coming from a resource file. What I am struggling with is the ViewModels.
The Models have language specific prperties (DescriptionEn, DescriptionFr) and an additional property call LocalizedDescription which uses the current culture to return call the language specific property.
When the language changes (via a button click) I raise and broadcast (via the Messenger) a property changed event.
In each of my ViewModels, I register to receive the property changed message for the language swap.
I want to notify all the properties of the ViewModel that something has changed.
From: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.propertychanged.aspx
The PropertyChanged event can indicate all properties on the object have changed by using either null or String.Empty as the property name in the PropertyChangedEventArgs.
However, since the toolkit abstracts the raising of the changed event with RaisePropertyChanged(...) I cannot get this to work. I have also examined the source of the tookit and discovered that RaisePropertyChanged calls VerifyPropertyName(..) which in turn returns an error is the property does not belong to the ViewModel. I also noticed that the VerifyPropertyName method is attributed with Conditional("DEBUG"), but even if I choose the Release configuration, the ArgumentException("Property not found") is still raised.
Does anyone know of a way to get this to work using the toolkit aside from manually calling RaisePropertyChanged for every property of the ViewModel?
Follow-up:
Based on the comment from Simon, I attempted to create my own class that extends ViewModelBase. I looked at the source on CodePlex and decided to create a single method called RaiseAllPropertyChanged(). It would simply be a copy of the RaisePropertyChanged(string propertyName) but without the parameter and without the call to VerifyPropertyName(...). I cannot get it to work. Here is what I have.
public class ViewModelBaseExtended : ViewModelBase
{
protected void RaiseAllPropertyChanged()
{
var handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(String.Empty));
}
}
}
But I get a compiler error: The event 'GalaSoft.MvvmLight.ViewModelBase.PropertyChanged' can only appear on the left hand side of += or -=. This is a copy of the code that is used in the ViewModelBase.
Can someone offer some advice as to how to get this to work?
Solution:
I copied all the code from ViewModelBase into a new class. I then added the method RaisePropertyChanged() mentioned above which instantiates the PropertyChangedEventArgs class with String.Empty. This is now the new subclass for my ViewModels.
Thanks again to Simon for leading the way!
In case you're reading this in 2016, you can use ObservableObject and notify that all of the properties have changed by doing:
RaisePropertyChanged(string.Empty);
Unfortunately this is not possible with the current code-base of MVVMLight
In the short term your have 2 options:
User your own custom base class. And by custom base class I mean "Do not inherit from the MVVMLight class".
Download and compile MVVMLight in Release mode. This will force the "VerifyPropertyName" method to be excluded. Of course then you don't get the value of property name checks.
I am sure Laurent Bugnion will have this fixed soon.
A lighter solution to this problem would have been to override RaisePropertyChanged(string propertyName) in your class :
protected override void RaisePropertyChanged(string propertyName)
{
if (propertyName != null)
{
base.RaisePropertyChanged(propertyName);
}
else
{
var handler = PropertyChangedHandler;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(null));
}
}
}

Problem with dotnetopenauth client.ProcessUserAuthorization()

I downloaded DotNetOpenAuth-3.5.0.10259 and tried to run the samples, specifically the OAuthClient sample and I managed to get it to work with facebook (VS2010). I can see "Welcome, [my name]" after allowing access in facebook.
The problem comes in when I try to use it in another project. I get a "No overload for method 'ProcessUserAuthorization' takes '0' arguments" and "No overload for method 'RequestUserAuthorization' takes '0' arguments".
Its basically the same code, which I find very weird since it works on the included sample but won't compile in the other project.
What did I miss?
protected void Page_Load(object sender, EventArgs e)
{
IAuthorizationState authorization = client.ProcessUserAuthorization();
if (authorization == null)
{
// Kick off authorization request
client.RequestUserAuthorization();
}
private static readonly FacebookClient client = new FacebookClient
{
ClientIdentifier = ConfigurationManager.AppSettings["facebookAppID"],
ClientSecret = ConfigurationManager.AppSettings["facebookAppSecret"],
};
The FacebookClient class came from the DotNetOpenAuth.ApplicationBlock project in the samples included in the 3.5.0.10259 download.
The only thing I can guess is that there is missing overload definitions within the libraries. I experienced the same issue you are describing, but in my case I couldn't get the samples to compile at all.
The trick though, is to simply pass in a NULL for the request parameter, which seems to work:
IAuthorizationState authorization = client.ProcessUserAuthorization(null);
Also note that you may run into the same missing overload issue with the "RequestUserAuthorization" method. Likewise, you can also pass in null values for each of the three parameters if you don't want to send them along:
client.RequestUserAuthorization(null, null, null);
Good luck!

Resources