Basically I have a page in my app where there's an async function that receives data via bluetooth. I want to execute functions on my main page based on the data I receive via bluetooth on the other page. I searched around a bit and mostly people suggest creating a base class and inheriting both pages from the same class, but that isn't what I'm trying to do: I don't want to execute a generic instance of the main page's function, I want to execute the specific main page function that belongs to the main page that my app is displaying.
I thought of two possible solutions to this:
Update a static variable in the main page class based on the received data, and use a property to execute the required functions every time the variable changes value, but the problem is that the functions I want to execute are non-static.
If I could know the object name of the main page class which my app instantiates, I could simply make the functions public and access them using syntax like MainPageObjectName.myFunction(), but I don't know the name of the object instantiated from the MainPage class by my app.
Any advice? Thanks in advance.
Ali, I assume here that you need to update the contents of the MainPage.xaml while some background (async) task has finished.
The best way to do that is have a DataModel (MVVM) in your application. More info here
and here.
By doing this when the async task finishes a function will be called to update the DataStructure that holds your data. Since that Model implements the INotifyPropertyChanged class the control on your UI (even though they are on another page) will be updated automatically.
Related
I have a function in my MainPage.xaml.cs, and when it is called I would like to change the text on a label in another page called Dashboard.xaml.cs
How do I change variables and call functions between files in Xamarin Forms?
Pages are just classes, and you can communicate between them like any class: using public methods, public properties, public events, etc
However, using Form's built in MessagingCenter might be the best method:
// send a message TO an instance of MyPage
MessagingCenter.Send<MyPage, string> (this, "MessageName", some_string_arg);
// in MyPage, listen for the Message
MessagingCenter.Subscribe<MyPage> (this, "MessageName", (sender, args) => {
// args will contain the value passed in Send
});
Provided that you have a reference to the instance of the Page, you can invoke methods or set properties on that instance.
In 2.3.6, you'll even be able to set a x:FieldModifier and modify the field values directly.
But don't do any of that. Use a Mvvm pattern, Bind your Pages, and let the ViewModels communicate between each other. And your Pages will be modified accordingly.
Every view in Xamarin is a class, you can instantiate a variable of the type View, where View is the page you want to access. For example:
I have a view called Works. To access (public) functions and variables contained within the view, I write code like this:
Works MyTestVariable;
var SomeResult = MyTestVariable.FunctionInWorksClass(aParameter);
The function contained in the Works view is executed and the value is returned to the var in the calling view.
I've been giving this some thought lately and I was hoping someone who has better knowledge of MvvmCross than myself can shed some light on this. Given the nuances between each mobile platform there are probably a few different factors that can affect this problem. But for this scenario let's assume we want the best approach for a cross platform solution.
So let's say we have a basic View and a ViewModel class setup. Here's an iOS example.
View
public partial class FirstView : MvxViewController<FirstViewModel>
{
public FirstView(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
Request = new MvxViewModelInstanceRequest(FirstViewModel.NewInstance());
base.ViewDidLoad();
}
}
View Model
public class FirstViewModel : MvxViewModel
{
public static FirstViewModel NewInstance()
{
return Mvx.IocConstruct<FirstViewModel>();
}
public FirstViewModel()
{
}
}
Now at the loading of this View or at some point just before the view is created we want to fetch some data from the web using a service that we inject using dependency injection; because the displaying of the view depends on that data. Here lies the problem.. at which point from a platform perspective and in the MvvmCross lifecycle would be the most appropriate place to call the web fetch function in the service.
With regards to platform I would assume that we should do it once the view loads. Because if the fetched data is anything other than simple data types it will be inconvenient to work with on Android, as one would have to persist the data to disk and retrieve it after the navigation, due to serialization between activities.
So assuming we called the web fetch during the view loading process. Where is the best place in the MvvmCross architecture to fire it off, that most closely follows the design paradigms. e.g. The View Model. Is there any lifecycle methods that someone could recommend to call it inside as well. Something like the Start method, called after the view model has been created.
First of all, I don't understand why you won't let the platform itself instantiate and do it's ViewModel lifecycle instead of creating a new instance of the ViewModel using Mvx.IocConstruct. That method does not invoke the ViewModel lifecycle and will not call neither Init or Start on the ViewModel.
If you let the platform do this for you, first the Init method will be called with the arguments that you set when using ShowViewModel<T>(args).
When ViewDidLoad invokes the Start method will subsequently be called.
This gives you two places to invoke the Service that you inject in the ctor of the ViewModel.
If you want more control over when to download the data, you could create some ICommand's, which you invoke on your ViewModel in any of the ViewController lifecycle methods. This could be in the ViewWillDisappear/ViewDidDisappear method, or you could fetch the data.
There are so many ways you can do this. In the end it is entirely up to you, and you can't possibly know when a user decides to change to another View. However, you can make qualified guesses and try fetch data before the user actually wants it.
There is a nice article for you to read here, by Rob Gibbens on how you could do Resilient network services. It describes how you could speculatively fetch resources based on what the user is doing, and this way have something ready for the user to see when he enters the View. This could be cached data or fresh data that you are fetching after showing the cached version.
In any case, I would suggest you stop loading your ViewModel's with Mvx.IocConstruct and let MvvmCross handle this for you in order to get lifecycle methods invoked.
My project is build on MVVM. Currently I have a list where i can select an object and add them to another list. What I want to make is a new window where this list is shown (the list with objects that are added) and edit that list in the new window (delte an item from that list).
How should I pass the data (selected object) to another window and be able to update them there?
I currently have it working in one view. In some related questions they advice MVVM light so I tried looking for that, from what I red mvvm light is mostly used to replace the notify property change. Should I use mvvm light or are there some specific patterns I could use?
Both windows will be open at the same time.
If you want to share your ViewModel between windows, you can use a ViewModelLocator. It is not specific to MvvmLight, it just creates one for you with its project template. You can implement it yourself, it is basically a container for your ViewModels. You can look here for the implementation details.
I've got to say that I'm not sure that these are the best approaches and if they are common, it's just what me and my colleagues were using in a WinRT application, so I'll be really glad if someone comes up with something better (both of these are not that clean).
I can think of two ways to pass data (without persisting it)
Pass parameters on page navigation
Have common shared class (Static or singleton class with some common data accessible from all ViewModels)
For passing on navigation:
I have this method in my Navigation service class:
public virtual void NavigateTo(Type sourcePageType, object parameter)
{
((Frame)Window.Current.Content).Navigate(sourcePageType, parameter);
}
and I use it like this in navigation commands:
Navigation.NavigateTo(typeof(PageType), someParameters);
Then you could get the values in the code behind of the navigated page
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var receivedParameter = e.Parameter as TheTypeOfThePassedParameter;
}
And from there to pass them to the ViewModel, maybe there is an option to pass this without code in the code behind but I've not tried this.
Having shared class:
This is pretty much straightforward just have static class or a singleton with the desired fields.
I have a method in an aspx web page which is accessed from another non webpage .cs class. This method contains a ClientScript to create a popup.
I get this error below when trying to make it a static.
An object reference is required for the non-static field, method, or property 'System.Web.UI.Page.ClientScript.get'
So I am wondering if there is a way to access this method from another .cs class or a solution.
Basically when an error trips on the .cs class I want to display a popup that says the error.
public static void message(string popupinformation)
{
ClientScript.RegisterStartupScript(this.GetType(), "", "popupinformation", true);
}
In .cs
AddUI.message("alert('Error can not add information');");
tl;dr - You need to add "System.web" reference in that library.
I understand that, you have a separated cs file in some another library that invokes a function sitting in asp.net webform. If that is true, then how you are calling that function because it will be inside a page class which inherits from system.web.ui.page.
Lets assume you have make it work by placing that in App_Code. Then used that class say Web_work.cs in some other library say lib.cs.
To use ClientScript... in the library with lib.cs you need to add "System.web" reference in that library.
Best practice is to do all validation in library, but use such kind of display method in webform only. Take an example, lets say you want to use windows form now, which uses MessageBox.Show, in that case your library needs change with current approach.
I'm am new to the .NET/c# realm and I am trying to develop a Windows Phone 8 application.
I have several pages showing lists of Objects(ListPage). All of these pages will have a filter capability, using a commom FilterPage.
What I need is to pass an object from the ListPage to the FilterPage.
I want to use MVVM (MVVM light templates). I've managed to implement almost everything using the Messaging framework. I'm using a FilterMessage that takes the object to be passed in its constructor.
The ListPage and the FilterViewModel listen to this message. The ListPage will navigate to the FilterPage and The FilterViewModel will take the Object from the message.
The ListPage is notified correctly but the FilterViewModel is not notified because the FilterViewModel is created only after the FilterPage is first shown.
Is it possible to initialize the FilterViewModel by App start?
If you think that this is not the way to go please tell me why:)
Thanks in advance.
What I do in this scenario is I'm adding the instance you want to pass around to the other page into the Session object you have under PhoneApplicationService.Current.State.
On the other side after you complete navigation you can extract the instance, and you should remove it from the State.
Pay attention that if your application goes into the background when you have instances inside the State, WP will try to serialize them.
I managed to make it work by creating the FilterViewModel instance in the ViewModelLocator constructor.I'm not sure that this is the best way to do it. Hopefully someone with more experience will share with us his thoughts.
public ViewModelLocator()
{
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<FilterViewModel>();
ServiceLocator.Current.GetInstance<FilterViewModel>();
}