MVVM simple question - mvvm

Problem - user clicks "do something" button (view), view model receives command and passes it to model (function call). Some time passes and model is done processing data (async). How does model notifies viewmodel about "need update"/"done"?
What is the best aproach? How can i seperate Model from ViewModel in this scenario?

You could implement a plain old event in your Model which can be subscribed to from the ViewModel.
Update
In response to your comment.
If you are using multiple threads, then you will need to know about the "Dispatcher" framework to ensure that calls from non-UI threads are properly synchronized onto the UI thread. This is a requirement of WPF. Please see:
http://msdn.microsoft.com/en-us/magazine/cc163328.aspx

I think the normal approach for doing this is to use the INotifyPropertyChanged interface. I'm not 100% certain how it works as I'm still fairly new to WPF, but normally you fire an event whenever a property changed, passing in the name of the property and that updates the binding for that property.
Below's some sample code. You'd then be binding to the IsSelected property (as I believe this should be your ViewModel).
public class TestProperty : INotifyPropertyChanged
{
public Boolean IsSelected
{
get { return isSelected; }
set
{
isSelected = value;
this.NotifyPropertyChanged("IsSelected");
}
}
private bool isSelected;
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Notifies the property changed.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
private void NotifyPropertyChanged(String propertyName)
{
this.VerifyPropertyName(propertyName);
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}

You might find the sample applications of the WPF Application Framework (WAF) helpful. They show how the model can communicate with the ViewModel or the View via events.

Related

Best Practice for handling collection updates in .net-maui (MVVM)

I have been working with MVVM and ObservableCollections for some time now, but it is still not clear to me what is the best practice for handling an update of a collection. When I add an item to the collection the UI gets notified and shows the new item in e.g. a ListView.
But I cannot see how this process works for the update of an item in the Collection. What I do now is to completely re-assign the collection and raise an OnPropertyChanged event but this updates the whole collection which seems like overkill and not really efficient.
Example use-case: The user edits an item and I want the change to be presented in the List or the Collection receives an update from a different service like a SignalR message.
I tried to assign new Values to an item of the ObservableCollection but it seems not to update the View even if I raise the OnPropertyChanged Event
From document From Data Bindings to MVVM,we could know that:
ViewModels generally implement the INotifyPropertyChanged interface,
which means that the class fires a PropertyChanged event whenever one
of its properties changes. The data binding mechanism in Xamarin.Forms
attaches a handler to this PropertyChanged event so it can be notified
when a property changes and keep the target updated with the new
value.
So if you want the UI updates automatically once changing the value of the property of the Item model in your List, you can implement interface INotifyPropertyChanged for your item model.
You can refer to the following code:
public class Item: INotifyPropertyChanged
{
private string _numType;
public string NumType
{
get => _numType;
set
{
SetProperty(ref _numType, value);
}
}
public string Name { get; set; }
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;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Note:
1.Suppose you want to update UI automatically while modifying the value of NumType,you can add following code:
private string _numType;
public string NumType
{
get => _numType;
set
{
SetProperty(ref _numType, value);
}
}
2.If you want UI update automatically after adding or remove item from your datalist, you just define your list as follows:
public ObservableCollection<ItemModel> Items { get; set; }
For more information, check ObservableCollection Class.

How to implement a State Pattern for Blazor pages using multiple components to build a page?

I have a Blazor page that utilizes multiple components within it - how can I implement a State pattern (ideally per-page) that would be able to handle the current state of a page?
Currently I have all of the state and state-manipulation being done on the page (and via injected Services), but I imagine it would be cleaner to implement a state pattern where each page has some kind of State object which then allows you to manipulate the page and its components in a strict manner.
Ideally the State object would implement INotifyPropertyChanged and be able to dynamically have its State updated, but I also don't hate the idea of having the State object relegate State-manipulation to methods on the object to make sure state isn't just 1-off updated on the Blazor page.
I've already tried to implement some kind of MVVM pattern, but that turned into more questions than answers.
I started to create a State object for the current page being worked on, but I'm not sure if I should basically just be putting most of the logic that was on the Blazor page in the State object, or if I should still have some data, but delegating the heavy lifting to the State.
eg: I have some code that used to be in the "OnAfterRenderAsync" function on the Blazor page, but I'm in the process of moving basically everything in there to a "LoadMatterDetails()" function in the State object that is handling that. Does this make sense, or should I only really have object State in the state object, and writing to & reading from the State object when particular pieces of information are available?
public class MatterDetailsState : IMatterDetailsState
{
private readonly IMatterDetailsService matterDetailsService;
private readonly NavigationManager navigationManager;
public bool EditMode { get; private set; } = false;
public int EditMatterId { get; private set; } = 0;
public Matter Matter { get; set; } = new();
public MatterPaymentOptionDetails PaymentDetails { get; set; } = new();
public List<MatterStatus> MatterStatuses { get; private set; } = new();
public MatterDetailsState(
IAppState appState,
IMatterDetailsService matterDetailsService,
NavigationManager navigationManager)
{
this.matterDetailsService = matterDetailsService;
this.navigationManager = navigationManager;
}
public async Task LoadMatterDetails()
{
// Query Params handling
var uri = navigationManager.ToAbsoluteUri(navigationManager.Uri);
var decryptedUri = HelperFunctions.Decrypt(uri.Query);
var queryParamFound = QueryHelpers.ParseQuery(decryptedUri).TryGetValue("MatterID", out StringValues uriMatterID);
if (queryParamFound)
{
EditMatterId = Convert.ToInt32(uriMatterID);
EditMode = !String.IsNullOrEmpty(uriMatterID) && EditMatterId > 0;
}
await LoadMatterStatuses();
if (EditMode)
{
Matter = await matterDetailsService.GetMatterByIdAsync(EditMatterId);
PaymentDetails = await matterDetailsService.GetMatterPaymentInfoByMatterId(EditMatterId);
}
}
private async Task LoadMatterStatuses()
{
MatterStatuses = await matterDetailsService.GetAvailableMatterStatusesAsync();
}
}
Basically, should I instead of having more or less the entire function in the State object, or only make the calls like setting Matter & PaymentDetails go through functions in the State object? Not sure what the standard for this is.
I've used Fluxor, which is a Flux/Redux library for Blazor, and have liked it. It holds all your state in an object which you can inject into your component for read access. You then manage state by dispatching actions from your components which are processed by effects or reducers which are essentially methods that process the action and make changes to state. It keeps everything neat, separated and very testable in my experience.
https://github.com/mrpmorris/Fluxor
There isn't a "standard", but applying good coding practices such as the "Single Responsivity Principle" and Clean Design principles drives you in a certain direction.
I divide the presentation and UI code into three:
UI - components and UI logic
State - data that you want to track state on.
Data Management - getting, saving,....
Each represented by one or more objects (Data Management is the ViewModel in MVVM).
You can see an example of this in this answer - https://stackoverflow.com/a/75157903/13065781
The problem is then how do you create a ViewModel instance that is scoped the same as the Form component. You either:
Scope the VM as transient - you can cascade it in the form if sub components need direct access to it. This is the approach in the referenced example.
Create an instance from the IServiceProvider using ActivatorUtilities and deal with the disposal in the form component.
If the VM implements IDisposable/IAsycDisposable the you have to do the second.
The following extension class adds two methods to the IServiceProvider that wrap up this functionality.
public static class ServiceUtilities
{
public static bool TryGetComponentService<TService>(this IServiceProvider serviceProvider,[NotNullWhen(true)] out TService? service) where TService : class
{
service = serviceProvider.GetComponentService<TService>();
return service != null;
}
public static TService? GetComponentService<TService>(this IServiceProvider serviceProvider) where TService : class
{
var serviceType = serviceProvider.GetService<TService>()?.GetType();
if (serviceType is null)
return ActivatorUtilities.CreateInstance<TService>(serviceProvider);
return ActivatorUtilities.CreateInstance(serviceProvider, serviceType) as TService;
}
}
Your form then can look something like this:
public partial class UIForm: UIWrapperBase, IAsyncDisposable
{
[Inject] protected IServiceProvider ServiceProvider { get; set; } = default!;
public MyEditorPresenter Presenter { get; set; } = default!;
private IDisposable? _disposable;
public override Task SetParametersAsync(ParameterView parameters)
{
// overries the base as we need to make sure we set up the Presenter Service before any rendering takes place
parameters.SetParameterProperties(this);
if (!initialized)
{
// Gets an instance of the Presenter from the Service Provider
this.Presenter = ServiceProvider.GetComponentService<MyEditorPresenter>() ?? default!;
if (this.Presenter is null)
throw new NullReferenceException($"No Presenter could be created.");
_disposable = this.Presenter as IDisposable;
}
return base.SetParametersAsync(ParameterView.Empty);
}
//....
public async ValueTask DisposeAsync()
{
_disposable?.Dispose();
if (this.Presenter is IAsyncDisposable asyncDisposable)
await asyncDisposable.DisposeAsync();
}
}

Is it ever appropriate to add an ICommand to your domain model objects?

I'm working on applying the MVVM pattern (and learning it in the process) for a Windows Store application.
Right now I am leaning towards having a 1:1 correspondence between View and ViewModel, where multiple ViewModels have a dependency on the same underlying Model.
For example, suppose I have an entity "Student". I have two ways to view the student: in a full-screen details page or as a list of students in a classroom. That results in the following View/ViewModel pairs:
StudentDetailsView/StudentDetailsViewModel
StudentListItemView/StudentListItemViewModel
At the moment I'm assuming my ViewModel will directly expose the Model, and my Xaml will bind to ViewModel.Model.property-name (I realize that's debatable).
Suppose I can perform some action on the Student from either View (e.g., "Graduate"). I want to have the Graduate behavior in my Model (to avoid an Anemic Domain Model), and I want to avoid duplicating behavior between ViewModels that depend on the same Model.
My intent is to have an ICommand (e.g., a RelayCommand) that I can bind a Graduate button to in the View. Here's my question:
Is there any reason not to make the ICommand a property of the Model class?
Basically that would mean something like the following (ignoring the need for a Repository):
public class Student {
public ICommand GraduateCommand { get { ... } }
void Graduate() { ... }
}
That way both StudentDetailsView and StudentListItemsView could have Xaml that binds to that command (where DataContext is StudentViewModel and Model is the public property):
<Button Command="{Binding Model.GraduateCommand}" />
Obviously I could just make Student::Graduate() public, create duplicate GraduateCommands on the two ViewModels, and have the execution delegate call Model.Graduate(). But what would be the disadvantage of exposing the behavior of the class via an ICommand rather than a method?
First of all, in many cases, it is perfectly fine to bind directly from the View to the Model, if you can implement INotifyPropertyChanged on the Model. It would still be MVVM. This prevents the ViewModel to be cluttered with a lot of "relay-directly-to-Model" code. You only include in the VM what can't be directly used by the View (need to wrap/denormalize/transform data, or Model properties don't implement INPC, or you need another validation layer...).
That said, Commands are a primary mean of communication between the View and the ViewModel.
There may be many receivers for the command (possibly on different ViewModels).
The Execute/CanExecute pattern often doesn't fit outside of the context of the VM.
Even if the real stuff is done in a method of the Model, Commands may have some logic other than just delegating to the model (validation, interaction with other VM properties/methods...).
When it comes to test your VMs, you can't stub the commands' behavior if they're outside of the VM.
For these reasons, Commands do not belong to the Model.
If you're concerned by code duplication across VMs, you can create a StudentViewModel from which both StudentDetailsViewModel and StudentListItemViewModel will inherit. StudentViewModel will define the Command and its common behavior.
If you use a model's property in your view, then you should stop calling that MVVM. You can move graduate command implementation into another class (let's say a Helper class) an share it between your ViewModels (during the initialisation).
GraduateCommand=new RelayCommand (GraduateHelper.Graduate, CanGraduate);
Wrong: put Graduate() into your entity.
EDIT
Extension methods for INotifyPropertyChanged
public static class NotifyExtension
{
public static void OnPropertyChanged(this INotifyPropertyChanged source, PropertyChangedEventHandler h, string propertyName)
{
PropertyChangedEventHandler handler = h;
if (handler != null) handler(source, new PropertyChangedEventArgs(propertyName));
}
public static bool SetProperty<T>(this INotifyPropertyChanged source,PropertyChangedEventHandler handler, ref T field, T value, string propertyName)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
source.OnPropertyChanged(handler, propertyName);
return true;
}
}
And then :
public class Student:INotifyPropertyChanged
{
private string _name = "Name";
public string Name
{
get { return _name; }
set {
this.SetProperty<string>(PropertyChanged, ref _name, value, "Name"); }
}
public event PropertyChangedEventHandler PropertyChanged;
}
public partial class MyViewModel :INotifyPropertyChanged
{
private Student _student=new Student();
public Student Student
{
get { return _student; }
set
{
this.SetProperty<Student>(PropertyChanged, ref _student, value, "Student");
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Finally Xaml:
<TextBlock Text="{Binding Path=Student.Name}"></TextBlock>

How are Views injected into the UI using PRISM and MEF?

I have already searched some tutorials and even looked pluralsite Introduction to PRISM. However, most examples based on using unity containers and the some lack of information on how to implement this feature with Mef container.
My simple helloworld module is based on web tutorial. My code is the same except I’m stuck only on HelloModule and using Mef, not Unity as tutorial shows:
The main my problem how to initialize my view with my view model. The only working way I have found via experimenting is to initialize view-model in View constructor:
HelloView.xaml.cs
namespace Hello.View
{
[Export]
public partial class HelloView : UserControl, IHelloView
{
public HelloView()
{
InitializeComponent();
Model = new HelloViewModel(this);
}
public IHelloViewModel Model
{
//get { return DataContext as IHelloViewModel; }
get { return (IHelloViewModel)DataContext; }
set { DataContext = value; }
}
}
}
And standard module initialization code:
[ModuleExport(typeof(HelloModule), InitializationMode=InitializationMode.WhenAvailable)]
public class HelloModule : IModule
{
IRegionManager _regionManager;
[ImportingConstructor]
public HelloModule(IRegionManager regionManager)
{
_regionManager = regionManager;
}
public void Initialize()
{
_regionManager.Regions[RegionNames.ContentRegion].Add(ServiceLocator.Current.GetInstance<HelloView>());
}
}
However, can someone tell the correct way how to this things, I this it must be done in Module initialization section.
MatthiasG shows the way to define modules in MEF. Note that the view itself does not implement IModule. However, the interesting part of using MEF with PRISM is how to import the modules into your UI at startup.
I can only explain the system in principle here, but it might point you in the right direction. There are always numerous approaches to everything, but this is what I understood to be best practice and what I have made very good experiences with:
Bootstrapping
As with Prism and Unity, it all starts with the Bootstrapper, which is derived from MefBootstrapper in Microsoft.Practices.Prism.MefExtensions. The bootstrapper sets up the MEF container and thus imports all types, including services, views, ViewModels and models.
Exporting Views (modules)
This is the part MatthiasG is referring to. My practice is the following structure for the GUI modules:
The model exports itself as its concrete type (can be an interface too, see MatthiasG), using [Export(typeof(MyModel)] attribute. Mark with [PartCreationPolicy(CreationPolicy.Shared)] to indicate, that only one instance is created (singleton behavior).
The ViewModel exports itself as its concrete type just like the model and imports the Model via constructor injection:
[ImportingConstructor]
public class MyViewModel(MyModel model)
{
_model = model;
}
The View imports the ViewModel via constructor injection, the same way the ViewModel imports the Model
And now, this is important: The View exports itself with a specific attribute, which is derived from the 'standard' [Export] attribute. Here is an example:
[ViewExport(RegionName = RegionNames.DataStorageRegion)]
public partial class DataStorageView
{
[ImportingConstructor]
public DataStorageView(DataStorageViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
}
The [ViewExport] attribute
The [ViewExport] attribute does two things: Because it derives from [Export] attribute, it tells the MEF container to import the View. As what? This is hidden in it's defintion: The constructor signature looks like this:
public ViewExportAttribute() : base(typeof(UserControl)) {}
By calling the constructor of [Export] with type of UserControl, every view gets registered as UserControl in the MEF container.
Secondly, it defines a property RegionName which will later be used to decide in which Region of your Shell UI the view should be plugged. The RegionName property is the only member of the interface IViewRegionRegistration. The attribute class:
/// <summary>
/// Marks a UserControl for exporting it to a region with a specified name
/// </summary>
[Export(typeof(IViewRegionRegistration))]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
[MetadataAttribute]
public sealed class ViewExportAttribute : ExportAttribute, IViewRegionRegistration
{
public ViewExportAttribute() : base(typeof(UserControl)) {}
/// <summary>
/// Name of the region to export the View to
/// </summary>
public string RegionName { get; set; }
}
Importing the Views
Now, the last crucial part of the system is a behavior, which you attach to the regions of your shell: AutoPopulateExportedViews behavior. This imports all of your module from the MEF container with this line:
[ImportMany]
private Lazy<UserControl, IViewRegionRegistration>[] _registeredViews;
This imports all types registered as UserControl from the container, if they have a metadata attribute, which implements IViewRegionRegistration. Because your [ViewExport] attribute does, this means that you import every type marked with [ViewExport(...)].
The last step is to plug the Views into the regions, which the bahvior does in it's OnAttach() property:
/// <summary>
/// A behavior to add Views to specified regions, if the View has been exported (MEF) and provides metadata
/// of the type IViewRegionRegistration.
/// </summary>
[Export(typeof(AutoPopulateExportedViewsBehavior))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class AutoPopulateExportedViewsBehavior : RegionBehavior, IPartImportsSatisfiedNotification
{
protected override void OnAttach()
{
AddRegisteredViews();
}
public void OnImportsSatisfied()
{
AddRegisteredViews();
}
/// <summary>
/// Add View to region if requirements are met
/// </summary>
private void AddRegisteredViews()
{
if (Region == null) return;
foreach (var view in _registeredViews
.Where(v => v.Metadata.RegionName == Region.Name)
.Select(v => v.Value)
.Where(v => !Region.Views.Contains(v)))
Region.Add(view);
}
[ImportMany()]
private Lazy<UserControl, IViewRegionRegistration>[] _registeredViews;
}
Notice .Where(v => v.Metadata.RegionName == Region.Name). This uses the RegionName property of the attribute to get only those Views that are exported for the specific region, you are attaching the behavior to.
The behavior gets attached to the regions of your shell in the bootstrapper:
protected override IRegionBehaviorFactory ConfigureDefaultRegionBehaviors()
{
ViewModelInjectionBehavior.RegionsToAttachTo.Add(RegionNames.ElementViewRegion);
var behaviorFactory = base.ConfigureDefaultRegionBehaviors();
behaviorFactory.AddIfMissing("AutoPopulateExportedViewsBehavior", typeof(AutoPopulateExportedViewsBehavior));
}
We've come full circle, I hope, this gets you an idea of how the things fall into place with MEF and PRISM.
And, if you're still not bored: This is perfect:
Mike Taulty's screencast
The way you implemented HelloView means that the View has to know the exact implementation of IHelloViewModel which is in some scenarios fine, but means that you wouldn't need this interface.
For the examples I provide I'm using property injection, but constructor injection would also be fine.
If you want to use the interface you can implement it like this:
[Export(typeof(IHelloView)]
public partial class HelloView : UserControl, IHelloView
{
public HelloView()
{
InitializeComponent();
}
[Import]
public IHelloViewModel Model
{
get { return DataContext as IHelloViewModel; }
set { DataContext = value; }
}
}
[Export(typeof(IHelloViewModel))]
public class HelloViewModel : IHelloViewModel
{
}
Otherwise it would look like this:
[Export(typeof(IHelloView)]
public partial class HelloView : UserControl, IHelloView
{
public HelloView()
{
InitializeComponent();
}
[Import]
public HelloViewModel Model
{
get { return DataContext as HelloViewModel; }
set { DataContext = value; }
}
}
[Export]
public class HelloViewModel
{
}
One more thing: If you don't want to change your Views or provide several implementations of them, you don't need an interface for them.

MVVM EventToCommand

Hi Friends,
I am developing MVVM WPF application, I need to execute the event for TelerikRadTab Control SelectionChanged event, I am aware using MVVM light it is simple using EventToCommand behavior, but as I am using MVVM framework(Link)
I have to do using Interaction triggers suggested # Link.
For the below I added the interactivity dll reference from
C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\Silverlight\v4.0
and in XAML I included
xmlns:I="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<Command:ChangePropertyOnTarget
Target="{Binding}" PropertyName="SelectedItems"
Value="{Binding SelectedItems, ElementName=ItemsToChoose}" />
</i:EventTrigger>
</i:Interaction.Triggers>
When I build the app I get the below error.
The property 'EventName' does not exist in XML namespace 'Link'.
Any suggestion or help on this would be of great help.
I'm using mvvm light but haven't needed to use the event to command feature often. I've managed the same functionality you are after a slightly different way:
<telerik:RadTabControl Template="{StaticResource TabControlTemplate}"
ItemsSource="{Binding TabbedViewModels }" SelectedItem="{Binding ActiveTabbedViewModel, Mode=TwoWay}"
ItemTemplate="{StaticResource TabItemTemplate}" Style="{StaticResource RadTabControlStyleBorderless}" />
so on the main windows viewmodel I have a collection of viewmodels, one per tabbed item which I bind to as the item source of the control.
Then I bind the selecteditem to a property on the main view model. Then in the setter of that property I am able to do anything specific that I would have required to do in the SelectionChangedEvent.
In my case the viewmodels for the tabs are dynamically loaded based upon what the user has initiated and each one is potentially quite different so they all inherit from a common base class, although you could also use an interface.
the collection is thus an ObservableCollection of that bas class and the ActiveTabbedViewModel property that selectedItem binds to is also of that type.
May or may not be suitable to your scenario, but by using this approach I've not needed any Interaction Triggers
EDIT: going into a bit more detail - afraid I don't know of a blog to point you to, so will explain a bit more about how I've approached this
So MainPage.xaml with the TabControl and a content frame.
MainPageViewModel is the view model for the mainpage. It has a property called TabbedViewModels which is an ObservableCollection of a TabbedWindowViewModelBase (a class I've created for this purpose)
/// <summary>
/// Gets or sets a collection of TabbedViewModels - each one will be represented by a tab on the top bar of the main window
/// </summary>
public ObservableItemCollection<CastleTabbedWindowViewModelBase> TabbedViewModels
{
get
{
return this.tabbedViewModels;
}
set
{
this.tabbedViewModels = value;
this.RaisePropertyChanged(() => this.TabbedViewModels);
}
}
/// <summary>
/// Gets or sets the Active Tab - is bound to the Tab bars SelectedItem - when changing to
/// another tab / view model it sets the page menu item to the correct one for that view model
/// </summary>
public CastleTabbedWindowViewModelBase ActiveTabbedViewModel
{
get
{
return this.activeTabbedViewModel;
}
set
{
this.activeTabbedViewModel = value;
this.RaisePropertyChanged(() => this.ActiveTabbedViewModel);
if (value != null)
{
// when the active tab has changed want to ensure we open the previously opened page that the new tab was on
value.DoSomething();
}
}
}
At this point it kind of depends on how complex your scenario is. If you have the same view but are just changing data then your view can bind to ActiveTabbedViewModel, because that raises the propertychanged event it will automatically refresh the bindings and show the data relating to the new tab. You could use the DoSomething on the child viewmodel to load it's data initially - you'd only need to do this once, unless you wantd to refresh it.
From what you've described, one way around this would be to create the TabbedWindowViewModel Class below:`
public class TabbedWindowViewModel :ViewModelBase
{
private RelayCommand<NavigationEventArgs> navigationCommand;
/// <summary>
/// Gets or sets the position /order that this tab item is relative to the other tab items
/// </summary>
public int MenuOrder { get; set; }
/// <summary>
/// Gets or sets the Navigation Id
/// </summary>
public int NavigationId { get; set; }
/// <summary>
/// Gets or sets the Title that will be displayed for this tab item
/// </summary>
public string Title { get; set; }
/// <summary>
/// Gets or sets the navigation target that will be navigated to when the tab item is clicked
/// </summary>
public string NavigationTarget { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the tab item is enabled
/// </summary>
public bool IsEnabled { get; set; }
/// <summary>
/// Gets the command for regular navigation.
/// </summary>
public virtual ICommand NavigationCommand
{
get
{
return this.navigationCommand
??
(this.navigationCommand =
new RelayCommand<NavigationEventArgs>(
this.ExecuteNavigationCommand, x => this.IsEnabled));
}
}
public void DoSomething()
{
//do whatever you need to
//then navigate to the correct page
this.NavigationCommand.Execute(null);
}
private void ExecuteNavigationCommand(NavigationEventArgs e)
{
NavigationManager.NavigateToView(this.NavigationTarget);
}
}
Note that NavigationManager is a static helper class to aid navigation.
Then each of the views that you potentially navigate to would inherit the datacontext from the MainPage - so then you have two choices - you could have a DataViewModel property on the TabbedWindoViewModel one and bind everything to that via ActiveTabbedWindow.DataViewModel. Or, as we do, have a property for each child view model on the Main View Model and bind directly to that property:
public SummaryViewModel SummaryViewModel
{
get
{
return this.summaryViewModel
?? (this.summaryViewModel = (SummaryViewModel)ViewModelFactory.GetPageViewModel<SummaryViewModel>());
}
}
Hope this helps...