For my school assignment I have to make a reservationsystem for a hotel.
The thing is that I have to make the code without the UI (never done this before).
I have to add the UI later. Each UI should be able to be used with my code.
Now I have a class called Secretary
The Secretary is able to make a Reservation.
I have this method in the class Secretary :
public void CheckIn()
{
Reservation reservation = new Reservation();
reservation.ReservationDate1 = //info from a textbox
}
Now I know that I should connect everything when my UI is ready, but what is the best way to tell my code that he should get the information from the textbox when the textbox isn't there yet???
i would suggest you start by reading this
now as for what you have to do then
first you will need to model your data
public class Reservation
{
public DateTime Date{get;set;}
public string Name{get;set;}
public void Save(){/*Copy entry to DB, webservice, file, etc*/}
public void Delete(){/*delete entry from DB, webservice, file, etc*/}
//ect
}
as you can see you now have a list of what is required for a reservation, and functionality that will persist your data
next you need a ViewModel
public class ReservationViewModel:INotifyPropertyCHanged
{
public Reservation Reservation{get;set;} //Link to model
private DateTime _Date;
public DateTime Date
{
get { return _Date; }
set { SetProperty(ref _Date, value); }
}
private string _Name;
public string Name
{
get { return _Name; }
set { SetProperty(ref _Name, value); }
}
public void SetProperty<T>(ref T store, T value,[CallerMemberName] string name = null)
{
store = value;
if(PropertyChanged!=null)PropertyChanged(this,new PropertyChangedArgs(name);
}
public void Save(){/*validate, copy over model values call models save*/}
public void Cancel(){/*change VM values back to Model values*/}
public void Delete(){/*validate, call models delete*/}
//ect
}
at this point you can stop as you have defined the data and behaviour of the system, though i would suggest adding a testing project to run your code and check it works
when you get to your View
you would just bind to your ViewModel and the rest is done for you
<TextBox Text={Binding Name}/>
You can use MVVM with a ViewModel, but if you just want a method ready to accept input when you design the UI, you can make Checkin() take a string parameter so it's Checkin(string value) and assign value to ReservationDate1.
public void CheckIn(string val)
{
Reservation reservation = new Reservation();
reservation.ReservationDate1 = val;
}
This is an exercise in keeping your logic and your UI nice and separate. A little more tightly coupled, but doable, would be this:
public void CheckIn(TextBox tb)
{
Reservation reservation = new Reservation();
reservation.ReservationDate1 = tb.Text;
}
Related
I am not sure but as long i read about ddd, domain model should never leave the application layer.. if that is true then how viewmodels can reuse behavior of domain model?
Assume the following invoice model in ddd perspective
public class Invoice
{
public int Id { get; set; }
public int CustomerID { get; internal set; }
public void ChangeCustomer(Customer customer)
{
if (customer.IsActive == false)
throw new Exception("Inactive customers cannot be used");
CustomerID = customer.Id;
//other properties change also that need to be reflected to the user interface
}
}
And now lets have the invoice ViewModel attempt #1. Going with this idea i have no issues to reuse domain behavior, but the domain layer must be referenced to the UI Project in this case(WPF). But is here where my fears appear that we should not use domain layer outside of application layer
public class InvoiceVMOption1 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyUI(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
Invoice underlinesource;
public InvoiceVMOption1(Invoice underlinesource)
{
this.underlinesource = underlinesource;
}
public int InvoiceID { get => underlinesource.Id; }
public int CustomerID
{
get => underlinesource.CustomerID;
set
{
try
{
//This is a very simple example. in reality when changing customer other properties of the domain change also.
var customer = new CustomerService().Get(value);
underlinesource.ChangeCustomer(customer);
NotifyUI(nameof(CustomerID));
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
throw;
}
}
}
}
And now lets have Invoice ViewModel option #2
Going with this idea, it means application service is responsible to construct the viewmodel and give it to the UI and then UI give back viewmodel >convert to domain > update throught repository
/// <summary>
/// I like more this idea as it decouple viewmodel from domain layer
/// The problem here is how i can reuse the logic of changing the customer since domain model is not referenced
/// </summary>
public class InvoiceVMOption2 : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyUI(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
private int invoiceid;
public int InvoiceID
{
get => invoiceid;
set
{
invoiceid = value;
NotifyUI(nameof(InvoiceID));
}
}
private int customerid;
public int CustomerID
{
get => customerid;
set
{
//user select a customer from combobox binding with his id
//here we need to let the user whenever any of the validation that exists in domain model invoice will fail when changing customer.
//nothing will save yet
//after user finish this viewmodel will be sent to application layer(service) convert it to domain and update through repository
//Problem is, how i can know if customer will fail to change without writing same code validation from domain?
customerid = value;
NotifyUI(nameof(customerid));
}
}
}
The View Model is a one-way street. It is only meant to construct a data structure suited to the UI from the domain representation.
Each change at the UI is better modeled as a separate Command (if you are using CQRS) or a different API that calls a specific Application Service (if you are using core DDD).
By choosing to model each change, you represent the domain more accurately in your code. If you were to return the same view model with modifications to the data structure, you are hiding the intent of these changes. The flow pattern is also closer to CRUD because you are simply transferring data to the backend to be persisted.
Im creating a small application for managing online racing leagues.
For this i will have a database that accesses data from web and exposes data objects through interface. The database doesn't exist yet but i created a Mockup which uses local XML files as datasource.
Small example for a league interface:
public interface ISchedule
{
string Name { get; set; }
List<IRaceSession> Races { get; }
// and some more properties …
IRaceSession AddRace();
void RemoveRace(IRaceSession race);
// and some more Methods …
}
public interface IRaceSession
{
uint RaceId { get; }
DateTime Date { get; set; }
TimeSpan Duration { get; set; }
// and some more properties …
}
Now to get this into my WPF with MVVM pattern i created a Model for each object the database is exposing and implemented the INPC there.
*Note: ContainerModel<> and ObservableModelCollection<> are classes i created to handle updates from the database while still keeping the INPC intact.
public class ContainerModel<T>
{
T Source { get; set; }
public ContainerModel(T source)
{
Source = source;
}
void UpdateSource(T source)
{
// handle updates …
}
}
public class ScheduleModel : ISchedule, ContainerModel<ISchedule>
{
public string Name { get => Source.Name ; set { Source.Name = value; NotifyPropertyChanged(); } }
public ObservableModelCollection<RaceSessionModel, IRaceSession> Races { get; }
List<IRaceSession> ISchedule.Races => Source.Races
public ScheduleModel(ISchedule source) : base(source)
{
Races = new ObservableModelCollection<RaceSessionModel, IRaceSession>(Source.Races);
}
IRaceSession AddRace()
{
Races.Add(// new Race Object);
}
void RemoveRace(IRaceSession race)
{
Races.Remove(// select race object to remove);
}
}
public class RaceSessionModel : IRaceSession, ContainerModel<IRaceSession>
{
public uint RaceId => Source.RaceId;
puglic DateTime Date { get => Source.Date; set { Source.Date = value; NotifyPropertyChanged(); } }
TimeSpan Duration { get => Source.Duration; set { Source.Duration = value; NotifyPropertyChanged(); } }
//--> here come some more logic im not sure About:
TimeSpan DurationHours
{
get => Duration.Hours;
set
{
// set only Hours componennt of Duration
Duration = Duration
.Subtract(Duration.Hours)
.Add(value);
NotifyPropertyChanged();
}
TimeSpan DurationMinutes
{
get => Duration.Minutes;
set
{
// set only Minutes componennt of Duration
Duration = Duration
.Subtract(Duration.Minutes)
.Add(value);
NotifyPropertyChanged();
}
}
Then i have a viewModel and a view that binds to the Model properties directly.
public class SchedulerViewModel : ViewModelBase //<-- just a Basic implementation of INPC
{
private ScheduleModel _schedule;
public ScheduleModel Schedule { get => _schedule; set { _schedule = value; NotifyPropertyChanged(); } }
public SchedulerViewModel(ScheduleModel schedule)
{
Schedule = schedule;
}
// Commands and other properties communicating with the view
// …
}
Now with this design i have a few concerns coming up. I am still in the process of getting my head around the whole design pattern and it is the first time i am Building it up from Scratch.
My Models don't really contain data, but only expose properties from the database
Am i Right in thinking that this is actually something a viewModel should do?
As you can see my models also hold some Kind of calculation for property Input. Should this "Business logic" be put outside the model too? Or would that also be better put in a ViewModel?
After all im doubting what i present are "models" at all. Would it be Right to call them ViewModels and then act with the Object from the database as the model?
*Edit:
When i began with this i read that for each View you should supply only one ViewModel, which is why i created my classes like this. But im not sure anymore if this is correct.
It may depend largely on what you're attempting to do with the application, but generally I would approach it like this:
Model for Schedule
Model for RaceSession
ViewModel for RaceSession, containing a RaceSession Model
ViewModel for Schedule containing a Schedule Model a collection of
RaceSessionViewModels
I've always regarded models as pretty much just representing a row from a database, essentially; a basic data entity that exists on its own outside of the application. The ViewModel is then anything that is relevant only within the application.
The reason I wouldn't have a collection of RaceSession Models in the Schedule Model, would be that if you were to do any kind of application-based manipulation of the RaceSessions, that's something that belongs in a ViewModel, so you'd then sort of be looking at a Schedule Model, with a collection of RaceSessionViewModels. So I'd keep Models strictly as single data entities, without any kind of entity relationships (joins) built in - these kinds of relationships, I'd build in to the ViewModel layer. Even if you didn't need a ViewModel for RaceSession, I'd still have a collection of RaceSession Models within the Schedule ViewModel.
As an example of the above, I believe that the AddRace method really belongs in the Schedule ViewModel, rather than the Schedule Model.
With regards to the TimeSpan calculations, I'd probably have the Hours and Minutes as get only properties (on the RaceSession ViewModel), with other methods on a RaceSessionViewModel that alter the Duration property directly. The exact implementation of this would depend on whether or not you were actually changing these in the database when they update.
Some Example Pseudocode
public class RaceSession : INPC
{
INPCProperties
RaceSession(inpcProperties)
{
INPCProperties = inpcProperties;
}
}
public class RaceSessionViewModel : INPC
{
public RaceSession RaceSession { get; set (INPC); }
public int Hours => RaceSession.Duration.Hours;
public RaceSessionViewModel(raceSession)
{
RaceSession = raceSession;
}
private void SetDurationHours(int hours)
{
RaceSession.Duration =
Duration
.Subtract(Duration.Hours)
.Add(hours);
NotifyPropertyChanged("Hours");
}
}
For the transfer of Data from the Model to the ViewModel, I would create simple Objects (Dto - DataTransferObject) without (or very minimal) Logic.
A good rule of thumb is that you want unsaved Data in the ViewModel while saved Data - or data that is about to be saved - belongs in the Model.
//--> here come some more logic im not sure About:
TimeSpan DurationHours
{
get => Duration.Hours;
set
{
// set only Hours componennt of Duration
Duration = Duration
.Subtract(Duration.Hours)
.Add(value);
NotifyPropertyChanged();
}
TimeSpan DurationMinutes
{
get => Duration.Minutes;
set
{
// set only Minutes componennt of Duration
Duration = Duration
.Subtract(Duration.Minutes)
.Add(value);
NotifyPropertyChanged();
}
I would put these into the ViewModel. In the Model you want the whole Timespan Object, only the ViewModel should be aware of the restrictions that you can only set them separately in the View.
When i began with this i read that for each View you should supply
only one ViewModel, which is why i created my classes like this. But
im not sure anymore if this is correct.
Yes, it saves a lot of headache later on, when you have to maintain your code and make changes which only apply to a single View.
No. A viewmodel connects the data (the models not the database) with the view. But it neither manipulates the view nor the database.
I wouldn't leave that in the models. This kind of stuff belongs actually in the viewmodel.
In every view you can have multiple viewmodels to present, but you definitely need at least one to begin with.
I suggest, as you already started constructing your MVVM, that you now look up an example in the internet somewhere that implements this design pattern. I suppose you already read some of the theory behind it.
As a learning exercise I'm trying to build a basic WPF app that makes use of the MVVM pattern that shows a list of objects (lets just use customers for simplicity) in a main tab and then allowing the user to edit customers by opening another tab with some sort of edit view. What I'm stuck on is how to go about communicating changes between the views if I want to make use of deferred saving. I've seen some stuff about using a MessageBus but I've also seen a lot about how that's an anti-pattern in MVVM. This is the code I've come up with so far
Model
public class Customer
{
public string Name {get; set;}
}
Customer View Model
public class CustomerViewModel
{
public string Name
{
get { return _model.Name; }
set {_model.Name = value; RaisePropertyChanged(); }
}
public void Save()
{
//Save the model to a DB/whatever
}
private Customer _model;
}
Edit View Model
public class EditCustomerViewModel
{
public string Name
{
get { return _name; }
set {_name = value; RaisePropertyChanged(); }
}
public void Save()
{
_model.Name = _name;
_model.Save();
}
private string _name;
private CustomerViewModel _model;
}
List View Model
public class CustomerListViewModel
{
public ObservableCollection<CustomerViewModel> Customers
{
get { return _customers; }
}
private ObservableCollection<CustomerViewModel> _customers;
}
The benefit of this code is that to edit a customer I create an edit view model that has a reference to the same view model this list is using so when changes are saved they show up in the list. The downside is I have to repeat a lot of code in the edit view. Not a problem when there's a few properties but definitely an issue with a lot. As well I can't imagine this scales when connected to a DB with many customers as I'd have to load all the customers into the list just to edit one (though maybe there's other solutions to this).
Is this the best way to approach a problem like this or is there a practice in MVVM that handles this kind of issue?
I am creating a Xamarin Forms application. The application contains a button which creates a new list. The list's name and date is saved in one table but the list's contents must be stored in another table, which needs to be created using a query. I have been able to successfully insert records into the table that holds the names and dates of the lists using the following approach:
[Table("ToDoLists")]
public class ShoppingList : INotifyPropertyChanged
{
private int _id;
[PrimaryKey, AutoIncrement]
public int Id
{
get
{
return _id;
}
set
{
_id = value;
OnPropertyChanged(nameof(Id));
}
}
private string _name;
[NotNull]
public string Name
{
get
{
return _name;
}
set
{
_name = value;
OnPropertyChanged(nameof(Name));
}
}
private string _date;
[NotNull]
public string Date
{
get
{
return _date;
}
set
{
_date = value;
OnPropertyChanged(nameof(Date));
}
}
private string _description;
[NotNull]
public string Description
{
get
{
return _description;
}
set
{
_description = value;
OnPropertyChanged(nameof(Description));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I have tried the following things:
Pass on the list name as a table name in the [Table(tableName)] statement but the IDE tells me that only constant fields are allowed to be used, meaning that I can't dynamically specify a table name
I have tried reading about SQLiteCommand but the examples I'm given use functions that aren't available in SQLite PCL (unless I've installed SQLite PCL incorrectly).
How exactly do I create a table using a query in SQLite PCL? Is it even possible? Any suggestions?
Take a look at SQLite-net:
SQLite-net is an open source, minimal library to allow .NET and Mono applications to store data in SQLite 3 databases. It was first designed to work with Xamarin.iOS, but has since grown up to work on all the platforms (Xamarin.*, .NET, UWP, Azure, etc.).
SQLite-net was designed as a quick and convenient database layer. Its
design follows from these goals:
Very easy to integrate with existing projects and runs on all the .NET platforms.
Thin wrapper over SQLite that is fast and efficient. (This library should not be the performance bottleneck of your queries.)
Very simple methods for executing CRUD operations and queries safely (using parameters) and for retrieving the results of those
query in a strongly typed fashion.
Works with your data model without forcing you to change your classes. (Contains a small reflection-driven ORM layer.)
First, create a SQLiteAsyncConnection to your database:
private SQLiteAsyncConnection database;
database = new SQLiteAsyncConnection("YourDatabasePath");
Then you can use the method CreateTableAsync() to create your table:
await database.CreateTableAsync<ShoppingList>();
For adding data to the table, you can do something like this:
public async Task SaveShoppingObjects(List<ShoppingObjects> shoppingsObjects)
{
await database.RunInTransactionAsync(tran =>
{
foreach (ShoppingObject s in shoppingObjects)
{
tran.InsertOrReplace(SqliteEntityFactory.Create(s));
}
});
}
SqliteEntityFactory.Create is a method which helps you creating the table element. It could look something like this:
public static ShoppingList Create(ShoppingObject s)
{
ShoppingList slist = new ShoppingList();
if (s == null)
{
return slist;
}
slist.Id = s.Id;
slist.Name = s.Name;
// etc...
return slist;
}
If I understand your question right, that should make the trick!
I'm using SQLite in my application to store some Message objects. I display a list of Message items in "View 1". When I change a property in the Edit View "View 2", I want the property to also change in the list.
Classes
Message.cs
class Message : INotifyPropertyChanged
{
private uint _id;
public uint Id
{
get
{
return _id;
}
set
{
// Trigger INotifyPropertyChanged
Set("Id", ref _id, value);
}
}
private string _content;
public string Content
{
get
{
return _content;
}
set
{
// Trigger INotifyPropertyChanged
Set("Content", ref _content, value);
}
}
...
}
MessageViewModel.cs
class MessageViewModel : INotifyPropertyChanged
{
private Message message;
...
private string _content;
public string Content
{
get
{
return message.Content;
}
set
{
// Set value
message.Content = value;
// Trigger INotifyPropertyChanged
RaisePropertyChanged();
}
}
...
}
View 1
View1.xaml
The datacontext is View1ViewModel
View1ViewModel.cs
private List<MessageViewModel> _messages;
public List<MessageViewModel> Messages
{
get
{
return _messages;
}
set
{
// Trigger INotifyPropertyChanged
Set("Messages", ref _messages, value);
}
}
...
private async void loadMessages()
{
// Get the messages from SQLite database
var messages = await newMessages();
Messages = new MessageViewModelCollection(messages);
}
View 2
View2ViewModel.cs
private MessageViewModel _message;
public MessageViewModel Message
{
get
{
return _message;
}
set
{
// Trigger INotifyPropertyChanged
Set("Message", ref _message, value);
}
}
...
private async void loadMessage()
{
// Get the message from SQLite database by Id
var message = await newMessage(messageId);
Message = new MessageViewModel(message);
}
The functions newMessages and newMessage(uint messageId) return new Message objects from the database.
I normally use the INotifyPropertyChanged implementation, but this doesn't work. I query the database 2 times, once for the list (View 1), and once for the edit page (View 2). The SQLite returns two different copies of the Message object, therefore the INotifyPropertyChanged meganism will not work (Only in the current page, not the pages in the backstack).
I could fix the problem by re-using the Message item from the list, but I cannot always do this in all views.
Is there a way to make the INotifyPropertyChanged work in this scenario? Or do I need a different approach to update the values?
You need a different approach. IMHO, the best thing would be to separate the data model from the view model. So have a MessageVm that binds to the WPF view, and put the logic into it to update itself appropriately (along with firing any necessary INotifyPropertyChanged's) from the Message objects that get passed into it.
There are some automatic mapping tools like Automapper which might, to some degree, alleviate the pain that comes along with this approach.
But you really should separate the view model from the data model, the decoupling of these layers is one of the principle tenets of WPF programming.