Hierarchical viewmodels which represent UI structure. What is better approach? - c#

Sorry for long and descriptive question, but it really bugs me for a long time. I have a problem with MVVM pattern.
I wrote application which actually works, but I don't think it's in a good style. My view model strucure looks like tree: it has references to all child viewmodels which are used to render proper view in ContentPresenter.
Take a look at sample GUI:
Home tab
--------------------------------------
HOME SETTINGS ADMINPANEL
======---------------------------------
______________________________________
/////////
///////// Home content
/////////
Settings tab
--------------------------------------
HOME SETTINGS ADMINPANEL
------============---------------------
______________________________________
settings1 > settings2 > other...
/////////
///////// Settings1 content
/////////
Notice the submenu which appears only in Settings view. Every switchable view is somehow dependent on model type. settings1 is visible only if model property is Type.One, and settings2 is visible when property is Type.Two.
Take a fast look into my current code: common interface for every view that I can change by click. PageHeader is displayed on button change content view:
public interface IPageVM
{
string PageHeader { get; set; }
}
and view models:
public class WindowVM : ViewModelBase
{
public ObservableCollection<IPageVM> ViewModels { get; set; }
public IPageVM CurrentTab { get; set; }
public ICommand ChangeViewModel { get; set; }
private Model _model;
public WindowVM()
{
_model = new Model();
ViewModels = new ObservableCollection<IPageVM>();
ViewModels.Add(new HomeVM(model));
ViewModels.Add(new SettingsVM(model));
if(_model.Admin)
ViewModels.Add(new AdminVM(model));
}
}
public class HomeVM : ViewModelBase, IPageVM
{
public string PageHeader { get { return "HOME"; } }
string Property { get; set; }
public HomeVM(Model model)
{
this.Property = model.Property;
}
}
public class SettingsVM : ViewModelBase, IPageVM
{
public string PageHeader { get { return "SETTINGS"; } }
public ObservableCollection<IPageVM> Tabs { get; set; }
public IPageVM CurrentTab { get; set; }
public ICommand ChangeViewModel { get; set; }
public SettingsVM(Model model)
{
Tabs = new ObservableCollection<IPageVM>();
if(model.Type = Type.One)
Tabs.Add(new Settings1VM(model));
if(model.Type = Type.Two)
Tabs.Add(new Settings2VM(model));
Tabs.Add(new OtherSettingsVM());
CurrentTab = Tabs[0];
}
}
public class Settings1VM: ViewModelBase, IPageVM
{
public string PageHeader { get { return "settings1"; } }
public Settings1VM(Model model)
{
}
}
public class Settings2VM: ViewModelBase, IPageVM
{
public string PageHeader { get { return "settings2"; } }
public Settings1VM(Model model)
{
}
}
xaml:
display buttons in ItemsControl that will change CurrentViewModel and render appropriate view bounded to viewmodels' type by DataTemplate.
Pros:
it already works
I can easily tell how does my GUI structure looks, because root viewmodel contains its children viewmodels and so on.
it's easy to inject data model to children by constructor.
Cons:
xaml code is all a DataTemplate
UserControls are empty in preview mode, it's hard to edit GUI
terrifying future: how will look my viewmodels structure if my application will grow a bit?
So I decided to change my ViewModels to something that looks more like WPF MVVM:
public class WindowVM : ViewModelBase
{
public bool AdminMode { get; set; }
public WindowVM()
{
_model = new Model();
AdminMode = _model.Admin;
AnotherTabVisibilityDependency = _model.Dependency;
}
}
xaml:
<TabControl>
<TabItem Header="HOME">
<TabItem.DataContext>
<vm:HomeVM/>
</TabItem.DataContext>
</TabItem>
<TabItem Header="SETTINGS">
<TabItem.DataContext>
<vm:SettingsVM/>
</TabItem.DataContext>
</TabItem>
<TabItem Header="ADMINPANEL" Visibility="{Binding AdminMode, Converter BoolToVisibility}">
<TabItem.DataContext>
<vm:AdminVM/>
</TabItem.DataContext>
</TabItem>
<TabItem Header="DEPENDANT" Visibility="{Binding AnotherTabVisibilityDependency, Converter BoolToVisibility}">
</TabItem>
</TabControl>
As you probably see, everything is clean, chaning UI is easy; not too much templates to write. Everything looks fine... But there is a thing I don't understand: Now each ViewModel is a separate instance that doesn't know about its parent. I can't pass model that easy.
Questions:
how can I inject data model into each viewmodel? I can't do it via xaml. Do I need to have a global static class with program state, or IoC? Maybe another way?
any alternative approaches? Maybe my second approach also isn't good?
does it make sense to rewrite my logic which actually works? I really hope it does (I hate my viewmodels' code).

Related

Command not firing on current item

I have a CarouselView. The ItemsSource is binded to an ObservableCollection of type AlarmEvent. AlarmEvent is a base class for different types of alarm events (Generic, Fr, Vfr, Anpr). The ItemTemplate changes depending on the type of CurrentItem. This works.
Xaml:
<CarouselView x:Name="cvAlarmEvents"
ItemsSource="{Binding AlarmEvents}"
CurrentItem="{Binding SelectedAlarmEvent}"
CurrentItemChangedCommand="{Binding CmdSelectedAlarmEventChanged}"
ItemTemplate="{StaticResource AlarmEventDataTemplateSelector}"
Grid.Row="2"
Margin="0, 2, 0, 0"
BackgroundColor="#141d3d"
IsVisible="true"/>
Template Selector:
public class AlarmEventDataTemplateSelector : DataTemplateSelector
{
public DataTemplate Generic { get; set; }
public DataTemplate Fr { get; set; }
public DataTemplate Tfr { get; set; }
public DataTemplate Anpr { get; set; }
public AlarmEventDataTemplateSelector()
{
Generic = new DataTemplate(typeof(GenericView));
Fr = new DataTemplate(typeof(FrView));
Tfr = new DataTemplate(typeof(TfrView));
Anpr = new DataTemplate(typeof(AnprView));
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
var alarmEvent = item as AlarmEvent;
switch (alarmEvent.Type)
{
case Enums.AlarmEventType.None:
return null;
case Enums.AlarmEventType.Generic:
return Generic;
case Enums.AlarmEventType.FaceRecognition:
return Fr;
case Enums.AlarmEventType.TemperatureFaceRecognition:
return Tfr;
case Enums.AlarmEventType.ANPR:
return Anpr;
default:
return null;
}
}
}
GenericView, FrView etc inherit from ContentView. The actual command bindings are inside the DataTemplate (ContentView) which is returned from AlarmEventDataTemplateSelector:
<ImageButton Source="CamWhite1"
BackgroundColor="Transparent"
Scale="1"
BorderColor="White"
BorderWidth="3"
Padding="10"
Margin="10, 5"
Command="{Binding CmdAddPic}" />
I have plenty of data bindings on the model which all work, aside from the Command bindings. I've tested the buttons with OnClick events and they fire as they should, which makes me think that the Command data binding is not working.
Here is how the command code looks inside AlarmEvent
public class AlarmEvent : BaseModel
{
public Command CmdAddPic { get; set; }
public AlarmEvent()
{
CmdAddPic = new Command(AddPic);
}
public void AddPic()
{
// I dont fire and this makes me sad ;(
}
}
I cannot find a single thread online about this problem. I can find countless of threads where they are trying to bind a command from a selected item to their viewmodel. THIS IS NOT WHAT I WANT. I simply want the command binding to work on my data model (AlarmEvent), and I am stumped as to why it doesn't work. Perhaps I am missing something obvious?
I am a silly bum for not realising this sooner, the fix was:
Instead of auto property like so -
public Command CmdSubmitUserMedia{ get; set; }
I needed to use a full property like so -
private Command cmdSubmitUserMedia;
[Ignore]
public Command CmdSubmitUserMedia
{
get { return cmdSubmitUserMedia; }
set { SetProperty(ref cmdSubmitUserMedia, value); }
}

Xamarin Forms MVVM with an actual model

I'm fairly new to Xamarin and stumbled across MVVM and really like it as an architectural pattern. However, I found that most HowTo's and tutorials out there only address the VVM (i.e. View-ViewModel) side of things, probably for simplicity sake!?
I would like to know how the communication between a ModelView and its associated models takes place using the INotifyPropertyChanged paradigm and other things.
If I understand correctly, I personally would put stuff like data handling, data storage (collections), db connections and stuff like that into a model. At least this is how I would've been doing it in the good old MVC days. Following questions arouse in my mind:
Where do I create the model(s) and how do I assign them to ViewModels?
How do I properly connect Model and ViewModel such that property updates are propagated and can be handled correctly?
Would you set the model as a member of the ViewModel?
In my current example, I would like to implement a SensorModel which provides several sensory data which layers above can subscribe to. I would like to send updates whenever new sensor data is available to the layers above; i.e. a ViewModel, for instance.
I'd basically had something like this in mind:
class Sensor
{
int _id { get; set; }
string _name { get; set; }
}
class SensorModel
{
private List<Sensor> _sensors { get; set; }
public void addSensor(Sensor s) ...
public void removeSensor(Sensor s) ...
}
Does anybody have links to actual/complete MVVM examples, including the connection between Model and ViewModel?
Any help appreciated.
Use Lastest stable Xamarin Forms
MODELS
In the Project, create a Models folder
To store data, i usually use SQLite or a temp store:
class DataStore
{
public static List<SensorModel> SensorStore { get; set; }
}
Create the SensorModel model
class SensorModel
{
internal int Id { get; set; }
internal string Sensor { get; set; }
}
VIEWMODELS
In the Project, create a ViewModels folder
Create a SensorVM viewmodel
class SensorVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public System.Windows.Input.ICommand StartCommand { get; set; }
public string SensorName { get; set; }
public SensorVM()
{
DataStore.SensorStore = new List<SensorModel>();
StartCommand = new Xamarin.Forms.Command(StartSubmit);
}
private void StartSubmit(object paramter)
{
var sensor = new SensorModel()
{
Id = 1,
Sensor = SensorName
};
AddSensor(sensor);
}
public void AddSensor(SensorModel sensor)
{
//do something
DataStore.SensorStore.Add(sensor);
}
}
VIEWS
In the Project, create a Views folder
Create a Sensor.xaml view
<ContentPage.Content>
<StackLayout Spacing="10" Orientation="Vertical">
<Entry Text="{Binding SensorName}" />
<Button Command="{Binding StartCommand}" Text="Start" />
</StackLayout>
</ContentPage.Content>
In the code behind:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Sensor : ContentPage
{
SensorVM vm;
public Sensor()
{
InitializeComponent();
BindingContext = vm = new SensorVM();
}
}
Hope that helps.
I would like to know how the communication between a ModelView and its
associated models takes place using the INotifyPropertyChanged
paradigm and other things.
I think the best way to create a communication in MVVM is Messaging Center.
https://learn.microsoft.com/pt-br/xamarin/xamarin-forms/app-fundamentals/messaging-center
It's not coupled from device (sensor) code to view models ...
Your messages, in this model, active events that could acess your viewmodels as well as other structures.
A sample of this
In your view use :
public void MessegingCenterInit()
{
#region Bluetooth
MessagingCenter.Subscribe<string, string>("App", "Status_name", (sender, arg) =>
{
App.PVM.Name = $"{arg}";//using INotifyPropertyChanged and view model
viewmodelMethod();//using only a viewmodel
});
#endregion
}
in your model use:
public string Name
{
get { return name; }
set
{
name = value;
App.PVM.Add_patient.AddCanExecuteChanged();//PVM is a viewmodel
//The view model need to have INotifyPropertyChanged as a interface
}
}
In specific code you have (into a generic method or event):
string new_name = John;
MessagingCenter.Send<string,string>("App","Status_name",new_name);
There are several ways to do it, its a simple one, you can try use objects as sender with less information.
Regards
Xamarin itself gives a really good example with their default Master-Detail Solution.
Just create a new Xamarin.Forms App and select the Master-Detail Layout.
It includes several Views, ViewModels (with the BaseVIewModel) and some MockUp Data Classes.
For a start just have a look around there :)
In almost all cases there is no communication between the Model and ViewModel, and very rarely there is communication between the Model and View. If you need to communicate between Model and ViewModel it is extremely likely that you are doing something wrong.
To explain, your model usually describes some entity, like that you have the class Cat:
public class Cat
{
public string Color {get; set;}
}
It is generally used in ViewModel either as the field or as a Collection like:
public class CatsViewModel
{
public List<Cat> Cats {get; set;}
}
The cat shouldn't be able to update by itself, if it is updated it is done either by bindings with the view or somewhere from ViewModel.
So you have some architectural problems in your app, I think.

MVVM pattern for WPF: Model vs ViewModel

I can't really wrap my head around the following problem:
All I have in the application is a textboxfor the user input, a button for performing a background calculation on that input and a textblock. Imagine I have to use MVVM, so I have my view, viewmodel and model classes.
I bind the controls (textbox, button and textblock) from the view to the viewmodel on corresponding properties and commands. However, I'm not sure where the viewmodel functionality should end. For instance, would the following be a way to structure the application?
Model:
public class Model
{
public string Input { get; set; }
public string Output { get; set; }
public void FancyMethod ()
{
// Use input to calculate output
}
}
ViewModel:
public class ViewModel
{
public string Input {get; set;}
public string Output {get; set;}
public ICommand command {get; set;}
public Model model {get; set;}
public ViewModel()
{
model = new Model();
}
// When the button is pressed, model.input = Input and then execute model.FancyMethod()
}
If you want to keep a clean layer model, you should not include public Model model {get; set;} in your ViewModel.
So, for example, if you have a command, targeting some business model, your structure should be something like this:
//you don't have this one... but well, maybe other cases have
public class SomeService : ISomeService
{
//member of ISomeService
public void SomeFancyMethod(Model model)
{
//do stuff..
}
}
public class Model //might be database, or domain model.
{
public string Input { get; set; }
public string Output { get; set; }
}
As for your viewmodel, it will become something like this:
public class ViewModel
{
private ISomeService _someService;
//note: someService is passed through a IoC service like ninject, unity, autofac etc.
public ViewModel(ISomeService someService)
{
_someService = someService;
//initialize the command:
command = new RelayCommand(() =>
{
_someService .SomeFancyMethod(new Model()
{
//properties could be mapped with an automapper.
});
});
}
public ICommand command {get; private set;}
public string Input {get; set;}
public string Output {get; set;}
}
Note: there are some additional techniques involved:
using an inversion of control container, and pass the service
through the constructor.
abstracting the service by means of an
interface (ISomeService)
possibly some automapper to isolate your mapping from and towards Models/ViewModels
"So why make this so 'complicated'? You are just making a copy.", a commonly heard argument against this pattern:
Well:
it isn't complicated
doing this will separate your layers. This mean that changes in your datalayer doesn't break your View. In the long run, you'll benefit, as change will come and you'll need to maintain the code.
I guess the FancyMethod() contains your business logic and produces a value that you want to display in the view. In this case, FancyMethod() belongs to your model as it contains some business logic that is the same regardless of whether it's being executed in the context of a client application or some other component.
So your model would look something like this, i.e. it accepts an input and produces an output but it doesn't expose any properties that a view may bind to:
public class Model
{
public string FancyMethod(string input)
{
// Use input to calculate output
}
}
You could then inject your view model with the model and call the FancyMethod when the user executes the command by clicking on the Button in the view:
public class ViewModel
{
private readonly Model _model;
public ViewModel(Model model)
{
_model = model;
command = new RelayCommand(Execute, CanExecute);
}
public string Input { get; set; }
public string Output { get; set; }
public ICommand command { get; private set; }
private bool CanExecute(object _)
{
return !string.IsNullOrEmpty(Input);
}
private void Execute(object _)
{
Output = _model.FancyMethod(Input);
}
}
Obviously the view model class should also implement the INotifyPropertyChanged interface and raise change notifications to the view.
In short the business logic belongs to the model and the application logic, for example what happens when a user clicks a Button, belongs to the view model.
I think its not necessary to outsorce the Input and Output properties in another class. The reason for this is that the properties reflect the input and output of the view. So they have to be in the viewmodel.
You can outsorce the SomeFancyMethod in a service class to separate the logic from the viewmodel anlogous to mvc.

Update models at runtime using mvvm

I'm familiar with MVVM and differences between models, viewmodels and views. The only thing that I'm not able to find answer to is how to update models at runtime. Simple example to show you what I mean:
Let's say I have application which can display graphs and store them in a database.
I have models
public class Session {
public Document Doc { get; set; }
}
public class Document {
public string Name { get; set; }
public Point[] GraphPoints { get; set; }
}
I can connect those to their viewmodels by passing them as parameters, so:
public class SessionViewModel{
private readonly Session _session;
public SessionViewModel(Session session)
{
this._session = session;
}
}
public class DocumentViewModel{
private readonly Document_document;
public SessionViewModel(Document document)
{
this._document = document;
}
}
public class ShellViewModel {
public SessionViewModel SessionVm { get; set; } // <-- Bind in view
public DocumentViewModel DocumentVm { get; set; } // <-- Bind in view
private Session _session;
public ShellViewModel()
{
_session = new Session();
session.Doc = new Document();
SessionVm = new SessionViewModel(session);
DocumentVm = new DocumentViewModel(session.Doc);
}
}
Problem appears when in the middle of my application's life cycle I decide to change value of document. For example:
public void OnNewDocumentLoaded(Document newDoc)
{
_session.Doc = newDoc;
}
_session.Doc was changed but every DocumentViewModel has its own instance of document which is passed in a constructor, so even though I changed model, my viewmodel stays the same.
Also I don't want to use INotifyPropertyChanged inside my model, because models should not know about framework and from my understanding this is a bad approach. Also I keep my models in PCL project so I'm not even able to implement INotifyPropertyChanged in my models.
From my understanding of a MVVM approach, models should not have a viewmodel associated with them. Instead, your views should have a viewmodel associated to them. Inside your viewmodel you can have objects from models in your application. Inside your viewmodel is where you should implement INotifyPropertyChanged. Those methods control the objects you have changed and then binding can occur between your view and viewmodel.

PRISM: How to add a view model to a region and create the view automatically?

I´m new to PRISM and trying some things out. I´m struggeling a little bit with MVVM.
The way you "connect" a view with a viewmodel is clear:
injection through unity, or
set the data context manually (ServiceLocator)
Everything is working fine if I add a view to a region (the viewmodel is created automatically). But that´s not the use case.
Let´s take a look at the example:
public class MyViewModel : NotificationObject
{
public ObservableCollection<AnotherViewModel> OrderModel { get; private set; }
}
I have to create view models and add them to the collection. This view models have to be displayed (AnotherView) in a region (OrderRegion). My problem is, how can I achieve that now the view is created when I am adding a viewmodel to a region. This region is a TabControl, so it could happened that different views must be displayed.
I have already took a look to the PRISM Quickstarts and the StockTrader example. What I am looking for is quite similar to
virtual protected void StartOrder(string tickerSymbol, TransactionType transactionType)
{
if (String.IsNullOrEmpty(tickerSymbol))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, Resources.StringCannotBeNullOrEmpty, "tickerSymbol"));
}
this.ShowOrdersView();
IRegion ordersRegion = _regionManager.Regions[RegionNames.OrdersRegion];
var orderCompositeViewModel = ServiceLocator.Current.GetInstance<IOrderCompositeViewModel>();
orderCompositeViewModel.TransactionInfo = new TransactionInfo(tickerSymbol, transactionType);
orderCompositeViewModel.CloseViewRequested += delegate
{
OrderModels.Remove(orderCompositeViewModel);
commandProxy.SubmitAllOrdersCommand.UnregisterCommand(orderCompositeViewModel.SubmitCommand);
commandProxy.CancelAllOrdersCommand.UnregisterCommand(orderCompositeViewModel.CancelCommand);
commandProxy.SubmitOrderCommand.UnregisterCommand(orderCompositeViewModel.SubmitCommand);
commandProxy.CancelOrderCommand.UnregisterCommand(orderCompositeViewModel.CancelCommand);
ordersRegion.Remove(orderCompositeViewModel);
if (ordersRegion.Views.Count() == 0)
{
this.RemoveOrdersView();
}
};
ordersRegion.Add(orderCompositeViewModel);
OrderModels.Add(orderCompositeViewModel);
commandProxy.SubmitAllOrdersCommand.RegisterCommand(orderCompositeViewModel.SubmitCommand);
commandProxy.CancelAllOrdersCommand.RegisterCommand(orderCompositeViewModel.CancelCommand);
commandProxy.SubmitOrderCommand.RegisterCommand(orderCompositeViewModel.SubmitCommand);
commandProxy.CancelOrderCommand.RegisterCommand(orderCompositeViewModel.CancelCommand);
ordersRegion.Activate(orderCompositeViewModel);
}
The view model is created inside the code and added to the region. The whole type regestring is happend through the "ViewExportAttribute" so it makes it harder to understand the pattern behind it.
EDIT:
I have found a way to do this manually but it´s not very nice:
var view = (FrameworkElement) ServiceLocator.Current.GetInstance<AnotherView>();
var model = ServiceLocator.Current.GetInstance<AnotherViewModel>();
view.DataContext = model;
regionManager.Regions["OrderRegion"].Add(view, null, true);
regionManager.Regions["OrderRegion"].Activate(view);
Roman
EDIT2:
Hi, I´m sorry, maybe I wasn´t clear enough.
My goal was to create a view model and then to configure it like in the example from the StockTrader above: Subscribe events, commands etc. After that I want to add this view model to the region, so that´s it could be displayed. This region might be a tabcontrol where different views with different view models are displayed.
The order is:
Create a view model in the controller class
Configure the view model
Add the view model to local collection inside the controller
Add the view model to the region
The missing piece what I was looking for was how to make it happen, that the view is created “automatically” with all stuff like binding etc. I have found an approach in this article (http://www.codeproject.com/Articles/229931/Understand-MVVM-Using-PRISM-by-Hello-World-Silverl). I have to create own interfaces for the view and the view model (IAnotherViewModel, IAnotherView).
Another approach can be found here: http://paulstovell.com/blog/viewmodel-first-prism
Is there any reason not to use implicit DataTemplates for this?
They are DataTemplates that define a DataType property, but not a Key property, and they are used anytime WPF tries to draw an object of the specified DataType
For example,
<TabControl ItemsSource="{Binding MyViewModelCollection}"
SelectedItem="{Binding SelectedViewModel}">
<!-- This could also go elsewhere, like Application.Resources -->
<TabControl.Resources>
<DataTemplate DataType="{x:Type local:ViewModelA}">
<local:ViewA />
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModelB}">
<local:ViewB />
</DataTemplate>
</TabControl.Resources>
</TabControl>
If the TabControl is displaying an object of type ViewModelA, it will draw it using ViewA, and if it's displaying ViewModelB, it will draw it using ViewB
yI you are using MEF then you can automate your view registration using Attributes:
/*YOUR VIEW*/
[ExportViewToRegion("MyView", "MyRegion")]
[Export(typeof(MyView))]
public partial class MyView : UserControl
{
....
}
/*IMPLEMENTATION*/
public interface IExportViewToRegionMetadata
{
string ViewName { get; }
string TargetRegion { get; }
}
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property, AllowMultiple = false)]
public class ExportViewToRegionAttribute : ExportAttribute
{
public ExportViewToRegionAttribute(string viewName, string targetRegion)
: base(typeof(UserControl))
{
ViewName = viewName;
TargetRegion = targetRegion;
}
public string ViewName { get; private set; }
public string TargetRegion { get; private set; }
}
[Export(typeof(IFluentRegionManager))]
public class FluentRegionManager : IFluentRegionManager, IPartImportsSatisfiedNotification
{
public IRegionManager RegionManager { get; set; }
[ImportingConstructor]
public FluentRegionManager(IRegionManager regionManager)
{
RegionManager = regionManager;
}
/*This Import will find all views in the assembly with attribute [ExportViewToRegion("ViewName", "RegionName")]*/
[ImportMany(AllowRecomposition = true)]
public Lazy<UserControl, IExportViewToRegionMetadata>[] Views { get; set; }
private readonly List<string> _processedViews = new List<string>();
private Lazy<UserControl, IExportViewToRegionMetadata> _GetViewInfo(string viewName)
{
return (from v in Views where v.Metadata.ViewTypeForRegion.Equals(viewName) select v).FirstOrDefault();
}
public IExportViewToRegionMetadata this[string viewName]
{
get
{
return (from v in Views
where v.Metadata.ViewName.Equals(viewName, StringComparison.InvariantCultureIgnoreCase)
select v.Metadata).FirstOrDefault();
}
}
public void ExportViewToRegion(string viewName)
{
if (viewName==null)
{
throw new ArgumentNullException("viewName");
}
var viewInfo = _GetViewInfo(viewName);
string targetRegion;
UserControl _view;
if (viewInfo != null)
{
targetRegion = viewInfo.Metadata.TargetRegion;
_view = viewInfo.Value;
}
if (string.IsNullOrEmpty(targetRegion) || _processedViews.Contains(viewName)) return;
RegionManager.RegisterViewWithRegion(targetRegion, _view.GetType());
_processedViews.Add(viewName);
}
/*All required views has been discovered and imported */
/*Loop true collection and register view with the region */
public void OnImportsSatisfied()
{
foreach (var viewName in from view in Views where !_processedViews.Contains(view.Metadata.ViewName)
select view.Metadata.ViewName)
{
ExportViewToRegion(viewName);
}
}
}
/* finally call IFluentRegionManager import in the bootstrapper to kick off registration*/

Categories