Catel Mapping properties to Model - c#

I have problem with AutoMapping Catel ViewModel -> Model properties.
I'm using Catel with Fody.Catel
I have a situation when my model changes during runtime.
My Model declaration looks like this:
[Model]
public MyModel SelectedMyModel { get; set; }
And I change this model during runtime like this:
private void TabChangedHandler(TabChangedMessage tabChangedMessage)
{
SelectedMyModel = (MyModel) tabChangedMessage.Data;
}
Then, I'm delegating some properties from Model to ViewModel like this:
[ViewModelToModel("SelectedMyModel")]
public string Name { get; set; }
[ViewModelToModel("SelectedMyModel")]
public string LastName { get; set; }
And the problem is:
When I'm setting this property for the first time, it works nice, but If I change SelectedMyModel to another object, it stops working.
Looks like delegation ViewModel -> Model is no longer working.
Should I call something to let Catel know, that my Model is changing? Or maybe it's a Catel issue?
Can you please help me?

Related

Binding properties between viewmodels

Lets say I have two views: FileList and Editor.
They both have their own view models, bound using a DependencyProperty.
The view models look somewhat like this:
public class FileVM : INotifyPropertyChanged
{
public string FileName { get; set; }
}
public class FileListVM : INotifyPropertyChanged
{
public ObservableCollection<FileVM> Files { get; set; }
public FileVM SelectedFile { get; set; }
}
public public class EditorVM : INotifyPropertyChanged
{
string FileName { get; set; }
}
Imagine that they properly implement INotifyPropertyChanged.
Now I don't want FileListVM and EditorVM to know about each other. They could just as easily exist independently. But in one use case I would like to bind FileListVM.SelectedFile.FileName to EditorVM.FileName. Whenever the selected file or the filename changes, so should the filename in the editor. And whenever the editor changes the filename in the editor, so should the name of the selected file.
Now here is my question: how can I do this cleanly? I'm guessing the solution lies somewhere in their parent view model (e.g. MainVM), since that view model is aware of the connection between the two child view models. But I'm not sure if I can connect the two through xaml, and I'd like to avoid writing property changed event handlers if possible.
Please look at:
Communicate between View Models in MVVM
I advise to use MVVM frameworks like Galasoft because they have useful functionality and often do life with MVVM easier ;)
If you do not like using them, you can add event SelectedFileChanged in one VM and subscribe it from the other one.

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.

Using property name and values from main view model in nested view model

I have a view model like below.
I would like to use the property name/values - AllowOrgs and IsOrgOnly in the nested view model - EditAddressViewModel too.
How to accomplish this objective?
My main view looks like this -
#Html.EditorFor(m=> m.AddressEditor,"AddAddress")
My main view model is like this -
public class AddressViewModel
{
public EditAddressViewModel AddressEditor {get; set;}
public bool AllowOrgs { get;set; }
public bool IsOrgOnly { get; set; }
}
Are you asking how you can bind to the AllowOrgs property in AddressEditor?
If so then all you have to do is:
#Html.EditorFor(m=> m.AddressEditor.AllowOrgs,"AddAddress")
And Razor will take care of the rest.
If this not what you meant to ask please provide a little bit more information about what you are looking for.

Passing DTO to my ViewModels constructor to map properties

In my solution I have two projects.
Project 1 (Core)
Mapping SQL to DTO using Dapper
Project 2 (WebUI - ASP.NET MVC 4)
Here I use a ViewModel per View.
Examples of a Controller
[HttpGet]
public ActionResult Edit(int id)
{
// Get my ProductDto in Core
var product = Using<ProductService>().Single(id);
var vm = new ProductFormModel(product);
return View(vm);
}
Examples of a ViewModel
public class ProductFormModel : BaseViewModel, ICreateProductCommand
{
public int ProductId { get; set; }
public int ProductGroupId { get; set; }
public string ArtNo { get; set; }
public bool IsDefault { get; set; }
public string Description { get; set; }
public string Specification { get; set; }
public string Unit { get; set; }
public string Account { get; set; }
public decimal NetPrice { get; set; }
public ProductFormModel(int productGroupId)
{
this.ProductGroupId = productGroupId;
}
public ProductFormModel(ProductDto dto)
{
this.ProductId = dto.ProductId;
this.ProductGroupId = dto.ProductGroupId;
this.ArtNo = dto.ArtNo;
this.IsDefault = dto.IsDefault;
this.Description = dto.Description;
this.Specification = dto.Specification;
this.Unit = dto.Unit;
this.Account = dto.Account;
this.NetPrice = dto.NetPrice;
}
public ProductFormModel()
{
}
}
Explanation:
I'll get my DTOs in my controller using a service class in the project (Core).
Then i create my ViewModel and pass the DTO to the constructor in ViewModel.
I can also use this view to add a new Product because my ViewModel can take a empty constructor.
Does anyone have experience of this. I wonder if I am in this way will have problems in the future as the project gets bigger?
I know this has nothing to do with Dapper. But I would still like a good way to explain my solution.
I think you will be fine using your current approach. More importantly, start out like this and refactor if you start to encounter problems related to your object mapping code (instead of thinking too much about it beforehand).
Another way to organize mapping logic that I use sometimes is to employ extension methods. That way, the mapping code is kept separate from the view model itself. Something like:
public static class ProductMappingExtensions
{
public static ProductFormModel ToViewModel(this ProductDto dto)
{
// Mapping code goes here
}
}
// Usage:
var viewModel = dto.ToViewModel();
Yet another approach would be to use a mapping framework like AutoMapper - this is a good fit in particular if your mapping logic is simple (lots of 1:1 mappings between properties).
But again, start simple and refactor when you need to.
I realize that this is a little bit late answer, but maybe it will help someone in the future.
This way of doing mapping between objects breaks the 'S' of the SOLID principles, because the responsibility of the ViewModel is to prepare data in its properties to be ready to use by the view and nothing else, therefore, mapping objects should not be on it's responsibilities.
Another drawback of this way is that it also breaks the 'Loose Coupling' OO principle as you ViewModel is strongly coupled with your DTO.
I think, even when we are in the very first step of the project, there are some importants OO principles that we should never break, so using mapper classes, either auto (AutoMapper, ValueInjecter ...) or manual, is definitely better.

ScaffoldColumn(false) is not detected when generating MVC 2 View in VS2010

If I understand the [ScaffoldColumn(false)] attribute correctly, I should be able to decorate a variable with this and then, when I create a strongly-typed Edit view, that field will show up as hidden text and NOT a Label/Textbox pair.
I am using entity framework and then adding a partial class with an inner metadata class like so:
[MetadataType(typeof(AlumniInterest_Metadata))]
public partial class AlumniInterest
{
private class AlumniInterest_Metadata
{
[ScaffoldColumn(false)]
[DisplayName("Person Id")]
[StringLength(8)]
public object person_id { get; set; }
[DisplayName("Interest")]
[StringLength(35)]
public string interest_desc { get; set; }
}
}
This partial is in the same namespace as the EF generated class and the DisplayName attribute IS being picked up so I think things are wired correctly. I tried changing the type from string to object (based on some google search results) but that did nothing.
Anyone else run into this problem? Have I made a newb error?
The MVC tooling does not reason about ScaffoldColumnAttribute. This attribute is only used when you invoke the Html.DisplayForModel or Html.EditorForModel methods.
If you wanted the Add View dialog to honor ScaffoldColumnAttribute you could edit the T4 template file that's used to generate a View.
The [ScaffoldColumn(false)] does not seem to work as you would expected. You will need to set
Html.HiddenFor(model => model.person_id)
in your view manually.

Categories