Loading Multiple ViewModel in a single View Xamarin Forms - c#

I’m working on a Xamarin Forms project, where I have a screen divided into 2 parts, inside a single View (say DashBoardView.Xaml). One part is having some menu options and on the other part I want to load different views on menu option clicked.
The dynamically views having different ViewModels registered (using XLABS MVVM) ViewFactory.
DashBoardView.Xaml
<Grid>
<Grid ColumnSpacing="0" RowSpacing="0" BackgroundColor="#404040">
// menu options having Command binded in DashboardViewModel
</Grid>
<ContentView Grid.Row="0" Grid.Column="1" BackgroundColor="White"
Content="{Binding DashboardDetailView}">
// views are binded with DashboardDetailView
// views are loaded dynamically to DashboardDetailView
(bindable property) using new Keyword when menu option
command is executed.
</ ContentView>
</Grid>
DashBoardViewModel.CS
private Command _dashboardMenuOptionCommand;
public Command DashboardMenuOptionCommand
{
get
{
return _ dashboardMenuOptionCommand?? (_dashboardMenuOptionCommand = new Command(() => {
DashboardDetailView = new ABCView();
}));
}
}
Note: ABCView is a Xaml view registered with ABCViewModel using xLab’s ViewFactory
Problem: The issue is the ABCView is getting loaded but no user interaction is happening, as in no commands binded to a label in ABCViewModel is getting called. Is there something I’m doing wrong or is there any better or optimize way to achieve the same?
Please find the attached screenshot for the reference.
DashboardView.xaml

Instantiating a view won't automatically instantiate a viewmodel and set it as it's binding context.
Most (if not all) MVVM Frameworks will provide you with a method to instantiate or resolve a page, which will automatically look up and hook up the appropriate viewmodel as well. Not too sure about automatically resolving a view with a viewmodel.
If not supported by your framework, you can do it yourself by instantiating your viewmodel, then assigning it to the view's binding context, before adding the view to the page.
Please note that XLabs is a dead project, I'm not too sure it's a smart idea to use it going forward, I suggest you look into current MVVM frameworks (there's a bunch) and pick one that suits your needs and looks good to you.

Related

MVVM and WPF structure

I've been recently trying to re-write a WinForm application to WPF. I've been trying to implement an MVVM structure into my application because it's starting to look a lot like Winforms where I need to name my controls x:Name and referencing them all the time. Essentially, I'm not using the power of what MVVM provides.
One thing I'm having trouble wrapping my head around, is the Window. Every time I create a Window, it generates a partial class. My question is, how does that tie in to MVVM? The confusion starts as to what content this class should contain. Does it have a single DataContext binding? What about button events?
From my understanding (at the moment), is that this "partial" class should have very minimal code, perhaps only to bind your ViewModel in your constructor:
this.DataContext = new ViewModel();
and the rest of the functionality should come from your ViewModel with the help of binding things on XAML. However, each ViewModel should be tied to a single Model. But what happens when this particular Window calls for many Models, such as a Client, Products, etc? Do you make a single ViewModel class that somehow does everything?
The essence of my question lies within the contents of this particual "partial" class and its relation to the ViewModel.
Looks like you've got two questions:
How the heck does this partial class thing fit in with MVVM?
How do I structure all the view models and models and stuff?
1) What you are referring to as a "partial class" is often called "code-behind" when discussing WPF. This is because in that in non MVVM patterns it usually has all the actual C# code that sits behind the xaml layout - i.e. "code-behind".
You're correct that a good indication of a good MVVM implementation is minimal/no code-behind. As you mentioned, usually all it will have is binding the DataContext to the ViewModel - and in lots of frameworks this is all handled for you and you don't even need that. In my MVVM projects every partial class looks like this:
namespace MyApp.Views
{
public partial class GeneratorView : CreatableView
{
public GeneratorView()
{
InitializeComponent();
}
}
}
Part of the nice thing with MVVM is that all the spaghetti event updating/connection code that you had to have in WinForms is all bypassed by using bindings. But as you noted, you can still do this with WPF but it's generally considered bad practice, and definitely with MVVM.
With all content and commands being bound directly to the ViewModel through data binding, the partial class need not have any content at all. There's lots of interpretations, but on a basic level:
The View lays things out and shows things on the screen.
The View Model contains UI specific data and logic. It deals with commands from the view, and may utilize business services.
The Model represents your data. Think of the stuff that's going in a database or file system.
2) MVVM is not strict in how you structure it. Generally the convention is you have ViewModel for every View. However, I believe it's fine to have a ViewModel without a View. Especially simple ones.
But what happens when this particular Window calls for many Models, such as a Client, Products, etc? Do you make a single ViewModel class that somehow does everything?
Not at all, it seems like you've got this all-or-nothing monolithic ViewModel in your head. If these were really simple structures, I'd do it like this:
However, you might want a dedicated ClientView or ProductView, and instead embed them in the main view:
The key thing is your ViewModels may contains other ViewModels, arrays of ViewModels. Similarly, your View can embed other View's to display it's ViewModels - or not. If they're simple, or you're just, say, listing a few properties (Maybe when you click an 'info' button a dialog shows up and that has the full View for said ViewModel, but in the list you just want the Name and Cost.
It's flexible. On thing is, often the Window isn't even part of the MVVM pattern. It's so "dumb" that it doesn't even have a ViewModel (also, what if you want to embed your app into another app or something?).
It's more flexible to have a high-level "AppViewModel" and all your Window does is contain that (often not even bothering with a WindowViewModel, it's not really a concern).
You can use more than one model in a view model. The aim of the view model is to abstract from the business layer (models, services).
For creating and keeping the instances you may use IoC (Inversion of Control) containers. There are many IoC containers available to use in .NET applications such as Castle Windsor, Autofac and so on (see List of .NET Dependency Injection Containers (IOC)). You just need to instantiate a view model object by necessary model objects, for example like this:
public class ViewModel
{
private readonly IClientModel _clientModel;
private readonly IProductModel _productModel;
public ViewModel(IClientModel clientModel, IProductModel productModel)
{
_clientModel = clientModel;
_productModel = productModel;
}
// Logic of your view model
}
Also you need to configure object dependencies and scopes (your model will be a singleton or a new instance of the type). The container injects dependencies when it creates the objects.
Also I recommend to read the article MVVM - IOC Containers and MVVM.
Yes, the way I approach it anyway, is to keep my Window dumb. How dumb? I guess it depends on the application. If I am just trying to throw a proof of concept or something with low importance together then I will cut a few corners. If I am working an a large application that will need to be maintained then I am going to be more strict, I may even frown on setting the ViewModel from the constructor in that case.
However, each ViewModel should be tied to a single Model
I don't know that I agree with that. That is not how I have approached MVVM, anyway. I would say that every View should be tied to a ViewModel. Within the ViewModel it may be the case that you are only dealing with one model but I have also had great success using a single ViewModel to expose multiple models to a View in a coherent way as well.
Here is an example of a template I use as a jumping off point in some of my smaller projects. I like to use explicit ViewModel properties in my Window and Views but you don't have to; you could modify this to use the DataContext property instead.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public object ViewModel
{
get { return (object)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(
"ViewModel",
typeof(object),
typeof(MainWindow));
}
In the code behind the ViewModel propoerty is just a dependency property of the Window. I will bind the Window content to this property. In this case it is an object but it could be some base ViewModel class or an interface if you want.
In my Window's markup I add a DataTemplate for each ViewModel to the Window's resources. If everything is wired together correctly WPF's implicit data templating will take over and make sure the correct view is rendered whenever the ViewModel property is changed.
<Window x:Class="Example.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModels="clr-namespace:Example.ViewModels;assembly=Example"
xmlns:views="clr-namespace:Example.Views;assembly=Example">
<Window.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type viewModels:FirstViewModel}">
<views:FirstView ViewModel="{Binding }" />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:SecondViewModel}">
<views:SecondView ViewModel="{Binding }" />
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid>
<ContentControl HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Content="{Binding ViewModel, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
</Grid>
</Window>

Modal Popup and views communication under MVVM pattern on C#

I have a large project coded with VB6 which I've been trying to upgrade to new technologies for a few months. My project consist on 6 administrative modules reunited under a client-server application. Coming from VB, my logical choice was to upgrade to .NET. After a lot of research I decide to use C#, WPF and the MVVM pattern (with Caliburn Micro).
At the beggining I had some problems, but I managed to resolve them. But now I've come to a point where I need (like every complex application) to communicate with different views and their corresponding viewModel through modal popups (or some other technique). And in this matter the MVVM pattern seems to be very restrictive or complex. A simple "Are you sure you want to delete this record (yes/no)" is a very complex task. So I'm looking for advice as how communicate views without complex artifacts as EventAgregators.
So far the only possible alternative I've found is to use the ModalContentPresenter class from this blog. The problems with this solution are:
I need to write the father view XAML and modal XAML on the same view.
I cannot have multiple popus from same view.
Some examples of where I'd like to use modal popups is:
Put a button on a view to select a Client. It should open a popup with all posible clients and let the user chose one.
Add a product popup to a customer order.
Any ideas or suggestions? Some sample code would be appreciated? Thanks!
I am the author of the linked ModalContentPresenter control so I will attempt to address some of your questions and concerns.
I need to write the father view XAML and modal XAML on the same view.
You can actually write both views in separate files. The views can then be loaded dynamically using DataTemplates which will depend on the ViewModel that is bound to either the Content or ModalContent properties.
See this which describes the general way in which this view switching can be achieved.
You could have a MainViewModel which has two properties, PrimaryViewModel and SecondaryViewModel which return appropriate view models which provide the properties and commands for the main and modal content.
You could have the following setup in XAML:
<DataTemplate DataType="{x:Type FooViewModel}">
<Controls:FooView />
</DataTemplate>
<DataTemplate DataType="{x:Type BarViewModel}">
<Controls:BarView />
</DataTemplate>
<controls:ModalContentPresenter
Name="modalPresenter"
Content={Binding DataContext.PrimaryViewModel}
ModalContent={Binding DataContext.SecondaryViewModel} />
When the IsModalproperty is false, only your PrimaryView will be displayed. As soon as you set the IsModal property to true the ModalContentPresenter will display your SecondaryView.
I cannot have multiple popus from same view.
I take it you mean you want to be able to display different modal content at different times from the same main view.
Using the above technique this is as simple as switching the ViewModel that is bound to the ModalContent property (before displaying it by setting IsModal to true). As long as you have a DataTemplate for the ViewModel that is bound (and your MainViewModel implements INotifyPropertyChanged correctly), the correct content will be displayed.
Some example on where i'd like to use modal popups is:
Put a button on a view to select a Client. It should open a popup with
all possible clients and let the user chose one.
Add a product popup to a customer order.
Once you understand the technique described above you should be able to see that the as long as you have a View and ViewModel pair you can cover any scenario you can think of.
As an example, consider viewModels that have the following interfaces:
public interface SelectCustomerViewModel : INotifyPropertyChanged {
event EventHandler CustomerSelected;
public ObservableCollection<Customer> Customers { get; }
public Customer Customer { get; set; }
public Command CustomerSelectedCommand { get; }
}
public interface MainViewModel : INotifyPropertyChanged {
public SelectCustomerViewModel ModalContent { get; }
public Command SelectCustomerCommand { get; }
public bool IsSelectingCustomer { get; }
}
You could have XAML that looks something like this:
<Window x:Class="ModalContentTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Select a customer">
<DataContext>
<vm:MainViewModel />
</DataContext>
<DataTemplate DataType="{x:Type SelectCustomerViewModel}">
<Controls:SelectCustomerView />
</DataTemplate>
<c:ModalContentPresenter Name="modalPresenter"
ModalContent={Binding ModalContent}
IsModal={Binding IsSelectingCustomer}>
<!-- This is the primary content! -->
<Grid>
<Button Content="Select a customer"
Command={Binding SelectCustomerCommand} />
</Grid>
</c:ModalContentPresenter>
</Window>
Here's how it works:
The IsSelectingCustomer property of the MainViewModel would start off as false.
Clicking the button in the main view would invoke the SelectCustomerCommand object. The command would then tell the MainViewModel to change the IsSelectingCustomer property to true.
The ModalContentPresenter would display the view specified by the data template. The user can now only interact with the 'select customer view'.
Once a customer has been selected, a button can be clicked (which is bound to the CustomerSelectedCommand of the SelectCustomerViewModel) which in turn would raise the CustomerSelected event.
The MainViewModel would have an event handler that would respond to the CustomerSelected event. The handler would then read the SelectedCustomer property from the SelectCustomerViewModel and finally, it would set the IsSelectingCustomer property back to false, causing the modal content to be closed.

create textblock programmatically

I want to create textblock programmatically
But it seems the code behind file don't build it.
EDIT
Inside Main.cs
public Main()
{
InitializeComponent();
}
public void generateUI(TypeOne item)
{
// Create first element
TextBlock authorText = new TextBlock();
authorText.Text = "Saturday Morning";
authorText.FontSize = 12;
authorText.FontWeight = FontWeights.Bold;
gridUI.Children.Add(authorText);
}
Inside Main.xml
<Page.DataContext>
<ViewModels:MainWindowViewModel/>
</Page.DataContext>
<Grid Width="Auto" Background="WhiteSmoke" x:Name="grid">
<Grid x:Name="gridUI" Margin="0,68,0,-37">
</Grid>
</Grid>
Inside MainWindowViewModel.cs
Main genUI = new Main();
IEnumerable<TypeOne> generateUI = //query variable
from x in _txnType
where x.Description == selectedTypeOne
select x;
foreach (TypeOne ui in generateUI)
{
genUI.generateUI(ui);
}
But the public void generateUI(TypeOne item) not creating the textblock.
I supposed, the Main.xml cannot read it since the DataContext is set to MainViewModel.cs
Please help.
The fact that you want to follow the MVVM pattern doesn't exclude dynamic view creation. However I always recommend that you use "logic-only" in the view model. That means that the VM still only contains logic for the view to interact with, but has absolutely no knowledge about the view and how it behaves.
Your view is the one using the view model and should adapt the view dynamically. This means that in the code-behind of your view, you have access to your view model and can customize the view according to your current view model. You can respond to changes in the view model as well since the view model will implement INotifyPropertyChanged (which you can intercept in your code-behind just as normal bindings would).
The question you should ask yourself is whether MVVM is the right patter for you here. If the UI always comes from a database, then where are the bindings defined? Also in the database? If so, what actual logic are you implementing in the view model? In other words: what is the point of a VM if there is no custom logic. In that case I recommend to use the view-only approach. If you need custom logic, use the approach with the code-behind I described above.

Navigating through multiple child views contained in Main Window

I am working on a an WPF MVVM application where I need to have a Main Window with just a logo and it has to show child views inside it. I don't have any controls in Main Window all the controls reside in child view for example Buttons like Next, Back, Cancel and some text blocks etc. Now If users select Next button on the child view I have to draw or load the next child view inside the Main Window. If Back button is clicked I have to go back to the previous child view. So basically I am changing the child views depending on which button is clicked. Also I am maintaining different view models for every child view. Now the problem is I am not able to figure how should I link the child views to there respective view models. This application is similar to some Installation applications where different dialogs are shown depending on the selection and the button clicked by the user.I am new to this wpf and don't want to use MVVM Light , Prism etc. Any detailed help will be greatly appreciated. Thanks in advance.
One of the easiest ways to associate any data type with XAML controls is to use a DataTemplate. Therefore, you can simply add something like this into your Application.Resources and as long as you do not set the x:Key properties on the DataTemplates, then they will be explicitly applied by the Framework whenever it comes across instances of your view models:
<DataTemplate DataType="{x:Type ViewModels:HomeViewModel}">
<Views:HomeView />
</DataTemplate>
...
<DataTemplate DataType="{x:Type ViewModels:MainViewModel}">
<Views:MainView />
</DataTemplate>
Then displaying the view is as simple as this:
<ContentControl Content="{Binding YourViewModelProperty"} />
In code behind, or your view model:
YourViewModelProperty = new MainViewModel();
It's often handy to create a base class for your view models and then the YourViewModelProperty can of that type and you will be able to interchange them using the same property and ContentControl.
UPDATE >>>
The general idea is that you have one MainViewModel class with one BaseViewModel property data bound to one ContentControl in MainWindow.xaml... the navigation controls should also be in MainWindow.xaml and not in the views themselves. In this way, the MainViewModel class is responsible for changing the property to the relevant view model instances when it receives navigation Commands from the MainWindow.xaml.

ViewModels that talk to each other without a Framework

Introduction
I have an application that imports lab instrument data while it is running. This data is imported and then displayed in a ListView at an interval set by the end-user as per his or her testing requirements. When a value of interest appears in this ListView that they watch, they then press a Start button and the application begins performing calculations on that datum and subsequent data until a Stop button is pressed. So on the left side of the screen is a View for displaying the imported data and on the right side is another View for watching the values and statistics as they are calculated and displayed.
The Current Code
The View that displays the ListView where data is imported to is the ImportProcessView.xaml and it sets its DataContext to the ImportProcessViewModel.cs. The VM I've just introduced has a property ObservableCollection<IrData> that the ListView, I've also just described, binds to. Now to the interesting part...
The ImportProcessView has a ContentControl that sets it's content dynamically a UserControl representing the controls and fields specific to the type of Phase that is chosen by the end-user.
<StackPanel Background="White" Margin="5">
<ContentControl Content="{Binding CurrentPhaseView}"/>
</StackPanel>
There are three PhaseViews, each in its own User Control and each sets it's DataContext to the ImportProcessViewModel. As a result I am getting some severe VM bloat to the tune of 2000 lines. Ridiculous. I know. The reason for the bloat is because the ImporProcessViewModel is maintaining state through properties for each of the three PhaseViews and not only that but contains methods for performing calculations whose data is stored and displayed in these "PhaseViews".
What I am trying to achieve
Obviously before the ImportProcessViewModel becomes more unwieldy, I need to break it up so that each PhaseView has its own ViewModel, but also such that each ViewModel maintains a relationship back to the ImportProcessViewModel for sake of the dependency imposed by the ObservableCollection of IrData.
R&D
I've done my research on ViewModels communicating with each other, but most of the results involve applications that were written with a specific MVVM framework. I am not using a framework, and at this point in the project it would be too late to refactor it to start using one.
I did, however, find this article and the answer offered by 'hbarck' suggests something simple like composition to achieve the result I want, but since I don't have much experience with DataTemplates I don't understand what is meant when he/she suggests exposing "the UserControl's ViewModel as a property on the main ViewModel, and bind a ContentControl to this property, which would then instantiate the View (i.e. the UserControl) through a DataTemplate"
Specifically, I don't understand what is meant by "bind a ContentControl to this property which would then instantiate the View through a DataTemplate".
Can someone clarify by way of an code example what is meant by instantiating a view through a DataTemplate in the context of this example?
Additionally, is this a good approach (as suggested by 'hbarck')?
As one can see, I am already setting the Content property of a ContentControl to the Phase View that is to be instantiated. I just don't know know what involving a DataTemplate would look like.
I don't understand what is meant when he/she suggests exposing "the
UserControl's ViewModel as a property on the main ViewModel, and bind
a ContentControl to this property, which would then instantiate the
View (i.e. the UserControl) through a DataTemplate"
A DataTemplate allows you to specify a relationship between a view (such as a user control) and a view model.
<DataTemplate DataType="{x:Type myApp:MyViewModel}">
<myApp:MyUserControl />
</DataTemplate>
This tells a ContentPresenter to display MyUserControl whenever its content property is set to an instance of MyViewModel. The view model will be used as the user controls DataContext. Typically, the DataTemplate is added to your application resources.
What the author of that answer is saying is that you could have a viewModel that has a property of another viewModel type which is bound to the Content property of the ContentPresenter.
<ContentPresenter Content="{Binding ParentViewModel.ChildViewModelProperty}"/>
Providing you have a DataTemplate that specifies a relationship between your ChildViewModel and your user control, WPF will automatically load the user control into your view.
This answer I provided to another question might also provide you with some help.
I need to break it up so that each PhaseView has its own ViewModel,
but also such that each ViewModel maintains a relationship back to the
ImportProcessViewModel.
This will allow you to break your viewModels into smaller, more manageable viewModels that look after themselves. This will leave you with the problem of communicating between the viewModels.
If you nest your viewModels as suggested, then your child viewModels could expose events that the parent viewModel can bind to so it is notified when something changes. Something like this:
public class ParentViewModel // Derive from some viewModel base that implements INPC
{
public ParentViewModel()
{
childViewModel = new ChildViewModel();
childViewModel.SomeEvent += someEventHandler;
// Don't forget to un-subscribe from the event at some point...
}
private void SomeEventHandler(object sender, MyArgs args)
{
// Update your calculations from here...
}
}
This is simple and doesn't require any additional frameworks. Some might argue against this method but it is a valid solution that works. The downside is that the viewModels have to know about each others existence in order to subscribe to the events so can end up being tightly-coupled. You can use standard object-oriented design principles to get around this though (I.E. derive your child viewModel from an interface so that the parent only knows about the interface and not the implementation).
If you really want to go for loosely-coupled communication then you need to use some sort of event aggregation or message bus system. This is similar to the above method except there is an object that sits between the view models and acts as a mediator so that the viewModels do not have to know of each others existence. My answer here provides some more information.
There are pre-existing solutions available but this would involve taking on an additional framework. I would advise using Josh Smiths MVVM foundation as it is very simple and you would only need to use a single class anyway.
While Benjamin's answer is really elaborate and very helpful, I'd like to clarify how what I wrote in the other post would apply to your problem:
You'd have three different PhaseViewModel-Classes for your different phases, probably derived from one common base class, let's say PhaseVMBase.
Instead of a CurrentPhaseView property, you'd probably have a CurrentPhaseVM property. This would be of type Object or PhaseVMBase, and return one of the three PhaseViewModel classes, depending on what the user chose in the main ViewModel.
PhaseVMBase would have an UpdateData method, which would be called by the main ViewModel whenever it received new data that should be processed by the phase view. The main ViewModel would call this method on whatever happened to be the CurrentPhaseVM at the moment. The PhaseViewModels would implement INotifyPropertyChanged, so that changes as a result of UpdateData would be visible to bound controls.
Your DataTemplates would be declared in the resources of the main view, e.g. the main window,
like this:
<DataTemplate DataType="{x:Type my:Phase1VM}">
<my:Phase1View/>
</DataTemplate>
<DataTemplate DataType="{x:Type my:Phase2VM}">
<my:Phase2View/>
</DataTemplate>
<DataTemplate DataType="{x:Type my:Phase3VM}">
<my:Phase3View/>
</DataTemplate>
Notice that there is no x:Key, only the DataType value. If declared like this, WPF would choose the appropriate DataTemplate when asked to display an object of type Phase1VM, Phase2VM or Phase3VM, respectively. Phase1View, Phase2View and Phase3View would be UserControls which would know how to display the different ViewModels. They wouldn't instantiate their ViewModels themselves, but expect that their DataContext is set to an instance of their respective ViewModel from outside.
Under the assumption that the ContentControl which should show the phase view is declared in the main view, and that the DataContext there would be the main ViewModel, you'd declare the ContentControl like this:
<ContentControl Content="{Binding CurrentPhaseVM}"/>
Depending on the actual type of CurrentPhaseVM, this will choose one of the three DataTemplates, and display the appropriate UserControl. The UserControl's DataContext would automatically be the ContentControl's Content, since that would the object which caused the DataTemplate to be chosen.
EDIT: Lists and code formatting don't go together, it seems...

Categories

Resources