Last time, I submitted a question about using property in MVVM in my Windows Phone 7 app.
I could well done by excellent advices. Please see my previous question.
Can not bind textblock property from another class to UI class using MVVM
Through my coding, MVVM properties are increasing. So I want to divide properties class and methods.
But I couldn't divide it. Please let me know how to divide properties class and methods class in MVVM.
My code is here.
Authentication.cs
public class Authentication : ViewModelBase
{
private string _ErrorStatus;
public string ErrorStatus
{
get
{
return _ErrorStatus;
}
set
{
_ErrorStatus = value;
NotifyPropertyChanged("ErrorStatus");
}
}
void Authenticate()
{
ErrorStatus = "Access Denied";
}
}
I want to divide like this. But "ErrorStatus" is not changed.
Properties.cs
public class Properties : ViewModelBase
{
private string _ErrorStatus;
public string ErrorStatus
{
get
{
return _ErrorStatus;
}
set
{
_ErrorStatus = value;
NotifyPropertyChanged("ErrorStatus");
}
}
}
Authentication.cs
public class Authentication
{
Properties properties = new Properties();
void Authenticate()
{
//not work
properties.ErrorStatus = "Access Denied";
}
}
The following enables Authentication to have access to properties of Properties and shows how it could work.
public class Properties : ViewModelBase
{
private string _ErrorStatus;
public string ErrorStatus
{
get
{
return _ErrorStatus;
}
set
{
_ErrorStatus = value;
RaisePropertyChanged("ErrorStatus");
}
}
}
public class Authentication : Properties
{
public void Authenticate()
{
ErrorStatus = "Access Denied";
}
}
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
var test = new Authentication();
test.Authenticate();
MessageBox.Show(test.ErrorStatus); // Displays "Access Denied"
}
}
I assume you have the same old
private Authentication authentication;
public MainPage()
{
InitializeComponent();
this.authentication = new Authentication();
this.DataContext = authentication;
}
void btnAuthenticate_Click(object src, EventArgs e)
{
authentication.Authenticate();
}
and
public class Authentication
{
private string properties = new Properties();
public string Properties
{
get
{
return properties;
}
set
{
properties = value;
NotifyPropertyChanged("Properties");
}
}
void Authenticate()
{
Properties.ErrorStatus = "Access Denied";
}
}
the normal xaml should then be
<TextBlock Text="{Binding Path=Properties.ErrorStatus}" />
but sometimes, you change the Properties instance.
so if it don't work, you can try this xaml
<Border DataContext="{Binding Properties}">
<TextBlock Text="{Binding Path=ErrorStatus}" />
</Border>
Related
I want to implement a Toast message on my Android app.
So I created in my shared code the interface :
namespace TravelApp.Renderers
{
public interface IToast
{
void show(string message);
}
}
Then I created on my Android project the interface implementation
[assembly:Dependency(typeof(TravelApp.Droid.Toast))]
namespace TravelApp.Droid
{
public class Toast : IToast
{
public void show(string message)
{
Android.Widget.Toast.MakeText(Android.App.Application.Context, message, ToastLength.Short).Show();
}
}
}
In my XAML file I used a pancakeview, when I tap on this view I want to display my toast Message :
<pancake:PancakeView x:Name="MyPancakecs" HorizontalOptions="EndAndExpand"
VerticalOptions="EndAndExpand"
CornerRadius="60"
HeightRequest="50"
WidthRequest="50"
BackgroundColor="{StaticResource BackgroundColor}"
Margin="0,0,60,0"
Padding="15"
>
<Image Source="TrayPlus"></Image>
<pancake:PancakeView.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ToastMyToaster}"/>
</pancake:PancakeView.GestureRecognizers>
</pancake:PancakeView>
Then I register my container in a PlateformInitializer class in my android Project :
namespace TravelApp.Droid
{
public class PlatformInitializer : IPlatformInitializer
{
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.Register<IToast,Toast>();
}
}
}
I added it in my App constructor in MainActivity.cs :
LoadApplication(new App(new PlatformInitializer())) ;
And then in my ViewModel I add a IToast object in my constructor:
namespace TravelApp.ViewModels
{
public class TravelListViewModel : BindableBase
{
private string _messageToast;
public string MessageToast
{
get { return _messageToast; }
set { SetProperty(ref _messageToast, value); }
}
public DelegateCommand ToastMyToaster;
public TravelListViewModel(INavigationService navigationService, ITravelRepository travelRepository, IToast Toaster)
{
this._navigationService = navigationService;
this._travelRepository = travelRepository;
this._messageToast = "Test Toaster";
this._toaster = Toaster;
this.ToastMyToaster = new DelegateCommand(ToastShow);
}
private void ToastShow()
{
this._toaster.show(MessageToast);
}
}
In my research I used this documentation : https://prismlibrary.com/docs/xamarin-forms/Dependency-Service.html
However when I run the code and tap on my pancakeview, there is no message displayed, I'm not even sure that the command is triggered...
I don't know if I needed to implement the IPlateformInitializer.
Thank you for your help,
Here is how I did it.
Shared Project
public interface IToast
{
void LongAlert(string message);
void ShortAlert(string message);
}
Android Project (Renderer)
You need to install CurrentActivityPlugin
[assembly: Dependency(typeof(AndroidToast))]
namespace yournamespace
{
public class AndroidToast : IToast
{
public void LongAlert(string message)
{
Toast.MakeText(CrossCurrentActivity.Current.Activity, message, ToastLength.Long).Show();
}
public void ShortAlert(string message)
{
Toast.MakeText(CrossCurrentActivity.Current.Activity, message, ToastLength.Short).Show();
}
}
}
Calling toast in my shared project
internal static void Toast(string message, bool isShort=false)
{
var toast = DependencyService.Get<IToast>();
if (toast != null)
{
if (!isShort)
toast.LongAlert(message);
else
toast.ShortAlert(message);
}
}
Somewhere in my viewModel / any where in Shared project
Helper.Toast("message here");
I have been trying to bind my ListView to my View model. The view model successfully retrieves 5 records from the database and the Listview seems to display 5 blank rows, however it is not showing binding for each field within each row.
I have spent a couple of days searching internet but I don't seem to be doing anything different. I was using master detail pages so I thought that it may be the issue so I set my Events page as first navigation page without master/detail scenario but to no avail. Please note that I am using Portable Ninject for my dependencies/IoC.
My App.Xamal.cs is is as follows:
public App (params INinjectModule[] platformModules)
{
InitializeComponent();
var eventsPage = new NavigationPage(new EventsPage());
//Register core services
Kernel = new StandardKernel(new MyAppCoreModule(), new MyAppNavModule(eventsPage.Navigation));
//Register platform specific services
Kernel.Load(platformModules);
//Get the MainViewModel from the IoC
eventsPage.BindingContext = Kernel.Get<EventsViewModel>();
((BaseViewModel)(eventsPage.BindingContext)).Init();
MainPage = eventsPage;
}
My EventsPage.Xaml is provided below:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Views.EventsPage"
Title="Events">
<ContentPage.Content>
<ListView x:Name="Events" ItemsSource="{Binding Events}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding EventID}" BackgroundColor="Red" TextColor="White"
FontAttributes="Bold" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
My EventsPage.xaml.cs is provided below:
namespace MyApp.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class EventsPage : ContentPage, IBaseViewFor<EventsViewModel>
{
public EventsPage ()
{
InitializeComponent ();
}
EventsViewModel _vm;
public EventsViewModel ViewModel
{
get => _vm;
set
{
_vm = value;
BindingContext = _vm;
}
}
}
}
My EventsViewModel is as follows, it successfully retrieves 5 records and OnPropertyChanged is fired for Events property:
namespace MyApp.ViewModels
{
public class EventsViewModel : BaseViewModel, IBaseViewModel
{
ObservableCollection<Event> _events;
readonly IEventDataService _eventDataService;
public ObservableCollection<Event> Events
{
get { return _events; }
set
{
_events = value;
OnPropertyChanged();
}
}
public EventsViewModel(INavService navService, IEventDataService eventDataService) : base(navService)
{
_eventDataService = eventDataService;
Events = new ObservableCollection<Event>();
}
public override async Task Init()
{
LoadEntries();
}
async void LoadEntries()
{
try
{
var events = await _eventDataService.GetEventsAsync();
Events = new ObservableCollection<Event>(events);
}
finally
{
}
}
}
}
My BaseViewModel is as follows:
namespace MyApp.ViewModels
{
public abstract class BaseViewModel : INotifyPropertyChanged
{
protected INavService NavService { get; private set; }
protected BaseViewModel(INavService navService)
{
NavService = navService;
}
bool _isBusy;
public bool IsBusy
{
get
{
return _isBusy;
}
set
{
_isBusy = value;
OnPropertyChanged();
OnIsBusyChanged();
}
}
protected virtual void OnIsBusyChanged()
{
}
public abstract Task Init();
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
// Secod BaseViewModel abstract base class with a generic type that will be used to pass strongly typed parameters to the Init method
public abstract class BaseViewModel<TParameter> : BaseViewModel
{
protected BaseViewModel(INavService navService) : base(navService)
{
}
public override async Task Init()
{
await Init(default(TParameter));
}
public abstract Task Init(TParameter parameter);
}
}
IBaseViewModel is just a blank interface:
public interface IBaseViewModel
{
}
IBaseViewFor is given below:
namespace MyApp.ViewModels
{
public interface IBaseViewFor
{
}
public interface IBaseViewFor<T> : IBaseViewFor where T : IBaseViewModel
{
T ViewModel { get; set; }
}
}
My Event model is as follows:
namespace MyApp.Models
{
public class Event
{
public int EventID;
}
}
Finally, the image of the output, as you can see that 5 rows are created with red background but EventID is not binding in each row. I have checked the data and EventID is returned. I have even tried to manually add records into Events list but to no avail, see the manual code and image below:
async void LoadEntries()
{
try
{
Events.Add((new Event() { EventID = 1 }));
Events.Add((new Event() { EventID = 2 }));
Events.Add((new Event() { EventID = 3 }));
Events.Add((new Event() { EventID = 4 }));
Events.Add((new Event() { EventID = 5 }));
}
finally
{
}
}
I have spent a lot of time on it but unable to find a reason for this anomaly, can someone please cast a fresh eye and provide help!?
You can only bind to public properties - ie, you need a getter
public class Event
{
public int EventID { get; set; }
}
Hy
I would like to share my approach for a custom xamarin.forms control within a Xamarin PCL Project with MVVM-Light. What do you think about it?
Custom Control -> PersonPanel.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="xxx.PersonPanel">
<StackLayout Orientation="Vertical">
<Label x:Name="titleLabel" Text="{Binding TitleLabel}"/>
<Entry x:Name="filterText" Placeholder="{Binding FilterPlaceholderText}" Text="{Binding Filter.Lookup}" TextChanged="OnFilterTextChanged"/>
<Label x:Name="resultText" Text="{Binding ResultText}" IsVisible="{Binding ResultTextVisible}"/>
</StackLayout>
</ContentView>
Code-Behind -> PersonPanel.xaml.cs:
public partial class PersonPanel : ContentView
{
public PersonPanel()
{
InitializeComponent();
//Init ViewModel
BindingContext = ServiceLocator.Current.GetInstance<PersonPanelViewModel>();
}
private PersonPanelViewModel PersonPanelViewModel
{
get
{
return (PersonPanelViewModel)BindingContext;
}
}
public string TitleLabel
{
get
{
return PersonPanelViewModel.TitleLabel;
}
set
{
PersonPanelViewModel.TitleLabel = value;
}
}
public string FilterPlaceholderText
{
get
{
return PersonPanelViewModel.FilterPlaceholderText;
}
set
{
PersonPanelViewModel.FilterPlaceholderText = value;
}
}
private void OnFilterTextChanged(object sender, EventArgs e)
{
PersonPanelViewModel.SearchCommand.Execute(null);
}
}
ViewModel -> PersonPanelViewModel:
public class PersonPanelViewModel : ViewModelBase
{
private IPersonService _personService;
private decimal _personId = 0;
private string _titleLabel = string.Empty;
private string _filterPlaceholderText = string.Empty;
private string _resultText = string.Empty;
private bool _resultTextVisible = true;
public PersonPanelViewModel(IPersonService personService)
{
_personService = personService;
// Init Filter
Filter = new PersonFilter();
// Init Commands
SearchCommand = new RelayCommand(Search);
}
public ICommand SearchCommand { get; set; }
public PersonFilter Filter
{
get;
private set;
}
public string ResultText
{
get
{
return _resultText;
}
set
{
Set(() => ResultText, ref _resultText, value);
}
}
public bool ResultTextVisible
{
get
{
return _resultTextVisible;
}
set
{
Set(() => ResultTextVisible, ref _resultTextVisible, value);
}
}
public string FilterPlaceholderText
{
get
{
return _filterPlaceholderText;
}
set
{
Set(() => FilterPlaceholderText, ref _filterPlaceholderText, value);
}
}
public string TitleLabel
{
get
{
return _titleLabel;
}
set
{
Set(() => TitleLabel, ref _titleLabel, value);
}
}
public decimal PersonId
{
get
{
return _PersonId;
}
set
{
Set(() => PersonId, ref _PersonId, value);
}
}
private async void Search()
{
//Reset
ResultText = string.Empty;
ResultTextVisible = false;
PersonId = 0;
if (Filter.PersonLookup != null && Filter.PersonLookup.Length >= 3)
{
//Call to Person Service
List<PersonResult> Person = await _personService.FindpersonByFilter(Filter);
if (Person.Count == 1)
{
PersonId = Person[0].PersonId;
ResultText = Person[0].PersonName;
ResultTextVisible = true;
}
}
}
}
Using of Control in another View:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:components="clr-namespace:xxx.ViewElements.Components"
x:Class="xxx.MainPage">
<StackLayout Orientation="Vertical">
<components:PersonPanel x:Name="personPanel" TitleLabel="Person" FilterPlaceholderText="Type your search criteria here..."/>
</StackLayout>
</ContentPage>
I'm using Autofac as the IOC Container.
What do you think about it? I am using MVVM the right way (it's very new to me)?
Is there a better way to deal with calling the Command from the Event (TextChanged) on the view?
What's about the properties in the Code-Behind (which do a routing to the ViewModel)?
Edit:
I'll try to describe, what I want to achieve:
Creating our own control (reusable in different views, cross-platform) -> PersonPanel.xaml
Written in XAML in our PCL Project with pure Xamarin.Forms controls in it
The control should have it's own commands (Search) and properties
One of the commands is using a Service
The control should get the Service (as an Interface) injected through IOC
The Service itself is also implemented in the PCL Project and makes a REST Call to a Webservice
The Result of the Call is than set to a property of the control -> ResultText Property
The Result is visible to the User
-> With the above implementation, all of that works, but I'm not sure if this is the right way...
Thanks for your help!
Kind regards,
Peter
The approach for mapping the event to the command is exactly as I would perform.
The rest is a little bit confusing. The general pattern is to create bindable properties in your control that are exposed to the view model when instantiated within the host view. A very basic sample structure is below:
public class TestLabelControl : Label
{
public static readonly BindableProperty TestTitleProperty = BindableProperty.Create< TestLabelControl, string> (p => p.TestTitle, null);
public string TestTitle {
get {
return (object)GetValue (TestTitleProperty);
}
set {
SetValue (TestTitleProperty, value);
}
}
}
public class TestContentPage : ContentPage
{
public TestContentPage()
{
var testLabel = new TestLabel();
testLabel.SetBinding<TestContentPageViewModel>(TestLabel.TestTitleProperty, vm => vm.TestLabelTitle, BindingMode.Default);
Content = testLabel;
}
}
public class TestContentPageViewModel
{
public string TestLabelTitle{get;set;}
public TestContentPageViewModel()
{
TestLabelTitle = "Something random";
}
}
You would then create the native renderers to handle the drawing on each platform.
By following this approach you keep the code separated and concise. It does seem a slightly long winded way of getting things done but it is highly scalable and configurable.
Hi i'm new using MVVM and i'm trying to binding a listbox but it doesn't work. Here's my code
Model
public class Musicmodel : INotifyPropertyChanged
{
//variables privadas
private String _artista;
private Uri _href;
private String _informacion;
private Double _Dvalue;
public String artista
{
get
{
return this._artista;
}
set
{
this._artista= value;
this.RaisePropertyChanged("artista");
}
}
public Uri href {
get {
return this._href;
}
set
{
this._href = value;
this.RaisePropertyChanged("href");
}
}
public String informacion {
get
{
return this._informacion;
}
set
{
this._informacion = value;
this.RaisePropertyChanged("informacion");
}
}
public Double Dvalue
{
get
{
return this._Dvalue;
}
set
{
this._Dvalue = value;
this.RaisePropertyChanged("Dvalue");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
ViewModel
public class DownloadFileViewModel : INotifyPropertyChanged
{
private WebClient clienteDownload;
private ObservableCollection<Model.Music>_musicSource= new ObservableCollection<Model.Music>();
public ObservableCollection<Model.Music> musicSource
{
get
{
return this._musicSource;
}
set
{
this._musicSource = value;
RaisePropertyChanged("musicSource");
}
}
private int index = 0;
//request para descargar la canciĆ³n
public void request(Model.Musicmodel item)
{
this.clienteDownload = new WebClient();
this.clienteDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler(clienteDownload_DownloadProgressChanged);
//agregamos el item al music
this.musicSource.Add(item);
this.clienteDownload.OpenReadAsync(this.musicSource[index].href);
}
private void clienteDownload_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
this.musicSource[index].Dvalue=(double)e.ProgressPercentage;
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
View
<ListBox x:Name="list" ItemsSource="{Binding musicSource}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding artista}"/>
<ProgressBar Value="{Binding Dvalue}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code Behind
protected override void OnNavigatedTo(NavigationEventArgs e)
{
DownloadFileViewModel download = new DownloadFileViewModel();
Model.Music newMusic = new Model.Music() { href = new Uri("http://media1.li.ru/b/4/mp3/2/95366/953662_14Friday_Im_In_Love.mp3", UriKind.Absolute), artista = "the cure" };
download.request(newMusic);
this.DataContext = download;
base.OnNavigatedTo(e);
}
I've debuged this and the download works fine and my ObservableCollection fills correctly whithout any problem but when i try to binding my listbox fails.
please what do i'm doing wrong?
thanks
The problem is quite simple. You initialize your musicSource property at the begining in
private ObservableCollection<Model.Music>_musicSource= new ObservableCollection<Model.Music>();
And then just add stuff to it after the request completes. The RaiseProperyChanged("Property") will only fire when you add a new observable collection but not when you add items to it.
Add this line again to the end of the request (when you populate your musicSource)
RaisePropertyChanged("musicSource");
This will trigger another update in the view
EDIT:
Another approach is to have an additional field like
private ObservableCollection<Model.Music>_anotherMusicSource= new ObservableCollection<Model.Music>();
And do everything on it and after that just say:
musicSource = _anotherMusicSource;
This will then trigger the notification and everything should work
You have an underscore in your property name
private ObservableCollection<Model.Musicmodel> musicSource= new ObservableCollection<Model.Musicmodel>();
public ObservableCollection<Model.Musicmodel> _musicSource
{
get
{
return this.musicSource;
}
set
{
this.musicSource = value;
RaisePropertyChanged("musicSource");
}
}
You have this mixed up - the underscore should (traditionally) be on the private member, not the public - your binding is targeting musicSource which is private
The standard convention which is advocated for .NET is:
// Private member variables
private int _someInteger;
// Public ones
public int SomeInteger { get { ... } set { ... } }
Using MVVM Light, I'm trying to develop a rather simple WP7 application. I've run into a problem using the navigation service. I can navigate to a page, but after pressing the back button I can't navigate to the same page again. NavigationService throws a NullReferenceException.
I have implemented my navigation using Messaging from the GalaSoft.MvvmLight.Messaging namespace. All my views inherits from a customized PhoneApplicationPage base class that registrers a listener on "NavigationRequest":
public class PhoneApplicationPage : Microsoft.Phone.Controls.PhoneApplicationPage
{
public PhoneApplicationPage() : base()
{
Messenger.Default.Register<Uri>(this, "NavigationRequest", (uri) => NavigationService.Navigate(uri));
}
}
From my view models I post Uri's to this listener:
SendNavigationRequestMessage(new Uri("/View/AppSettingsView.xaml", UriKind.Relative));
Like i said, this works except when navigating after pressing the Back button.
Why is this and how can I solve it?
Is there a better way to implement navigation using MVVM Light?
I'm using MVVM Light as well. I have a class called PageConductor, which is based on what John Papa (Silverlight MVP) from Microsoft uses. Here's the PageConductor Service I use
public class PageConductor : IPageConductor
{
protected Frame RootFrame { get; set; }
public PageConductor()
{
Messenger.Default.Register<Messages.FrameMessage>(this, OnReceiveFrameMessage);
}
public void DisplayError(string origin, Exception e, string details)
{
string description = string.Format("Error occured in {0}. {1} {2}", origin, details, e.Message);
var error = new Model.Error() { Description = description, Title = "Error Occurred" };
Messenger.Default.Send(new Messages.ErrorMessage() { Error = error });
}
public void DisplayError(string origin, Exception e)
{
DisplayError(origin, e, string.Empty);
}
private void OnReceiveFrameMessage(Messages.FrameMessage msg)
{
RootFrame = msg.RootFrame;
}
private void Go(string path, string sender)
{
RootFrame.Navigate(new Uri(path, UriKind.Relative));
}
public void GoBack()
{
RootFrame.GoBack();
}
}
In my MainPage.xaml.cs constructor, I have this, which creates an instance of my ContentFrame in my PageConductor service.:
Messenger.Default.Send(new Messages.FrameMessage() { RootFrame = ContentFrame });
I then use dependency injection to instantiate an instance of my PageConductor Service into my MainPage ViewModel. Here is my MainViewModel class:
protected Services.IPageConductor PageConductor { get; set; }
public RelayCommand<string> NavigateCommand { get; set; }
public MainViewModel(Services.IPageConductor pageConductor)
{
PageConductor = pageConductor;
RegisterCommands();
}
private void RegisterCommands()
{
NavigateCommand = new RelayCommand<string>(
(source) => OnNavigate(source));
}
private void OnNavigate(string sender)
{
PageConductor.GoToView(sender, "main");
}
Notice the instance of my PageConductorService as a parameter in my MainViewModel constructor method. I pass this in via my ViewModelLocator:
private readonly TSMVVM.Services.ServiceProviderBase _sp;
public ViewModelLocator()
{
_sp = Services.ServiceProviderBase.Instance;
CreateMain(_sp);
}
#region MainPageViewModel
public static MainViewModel MainStatic
{
get
{
Services.ServiceProviderBase SP = Services.ServiceProviderBase.Instance;
if (_main == null)
{
CreateMain(SP);
}
return _main;
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
"CA1822:MarkMembersAsStatic",
Justification = "This non-static member is needed for data binding purposes.")]
public MainViewModel Main
{
get
{
return MainStatic;
}
}
public static void ClearMain()
{
_main.Cleanup();
_main = null;
}
public static void CreateMain(Services.ServiceProviderBase SP)
{
if (_main == null)
{
_main = new MainViewModel(SP.PageConductor);
}
}
#endregion
For further reference, my Messages.FrameMessage class is simply:
internal class FrameMessage
{
public Frame RootFrame { get; set; }
}
I've had no issues with forward/back buttons.