I am trying to implement MVVM for one of my Windows Phone app that i am developing and its growing to be big.
I have tried below code in Model class.I want to know how can i handle the scenario where user clicks on a button "Latest Entry" and it will connect to a service and executes a method asynchronously.Once the data is returned i have to display the latest record in UI which has 3 text fields EmpName,EmpID,Address.
Code in Model Class:
public class EmpDetailsModel:INotifyPropertyChanged
{
private string _EmpName;
public string EmpName
{
get { return _EmpName; }
set {
if (value != _EmpName)
{
_EmpName = value;
RaisePropertyChanged("EmpName");
}
}
}
private string _EmpId;
public string EmpId
{
get { return _EmpId; }
set {
if (value != _EmpId)
{
_EmpId = value;
RaisePropertyChanged("EmpId");
}
}
}
private string _Address;
public string Address
{
get { return _Address; }
set {
if (value != _EmpId)
{
_EmpId = value;
RaisePropertyChanged("Address");
}
}
}
#region myfirstmodel inotify members
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
The code to connect to service is below:
EmpAzureSer empAzureSer = new EmpAzureSer();
empAzueSer.GetLatestEntry += new GetLatestEntryCompletedEventHandler(LatestEntryCompleted);
private void LatestEntryCompleted(object sender, GetLatestEntryCompletedEventArgs e
{
//get the data from e as e.Name,e.Id and e.Address and bind them to UI.
}
view xaml code:
<Button Name="FetachLAtest" Click="FetachLatest_Click"></Button>
<TextBlock Name="EmployeeName"></TextBlock>
<TextBlock Name="EmployeeID"></TextBlock>
<TextBlock Name="EmployeeAddress"></TextBlock>
I was following the link http://msdn.microsoft.com/en-us/library/windowsphone/develop/gg521153(v=vs.105).aspx.
It was very helpful but I want to know where do i put the code to connect to service (model ? or Viewmodel ? How does the viewmodel should look like ?
There are various ways to implement MVVM into an application, it varies depending on developpers and application requirements.
But for started, let's try to keep things simple and to focus on ViewModels (because this seems to be where is your interest).
MVVM means Model View ViewModel, Model is your business/domain code, View is basically your XAML and its associated code behind, and ViewModel is the link/glue between Views and Models.
An important thing to note is that ViewModels mustn't know Views (meaning don't reference them). This ensures a better separation of concerns, and thus try to build an application easier to test and to maintain.
So to make a long story short, ViewModels don't know Views but they have to communicate with them... And this magic is made possible thanks to Bindings!
XAML/UI components display data, these data comes from the ViewModel which is bound to the View through Bindings mechanisms (provided on WP by the Silverlight framework).
This means the ViewModel contains all the data required by the View, actually a ViewModel represents all the data or behaviors of a View.
Being not the best person to describe the whole MVVM pattern and all its subtilities, i'll leave this sensitive task to most knowledgeable people in the field ;). Here are some really great links that should help you :
From Josh Smith
Wikipedia with code samples for ViewModel
If you already know MVC or MVP patterns, this one will help you to spot differences
All this being told, you must be a little bored with theory, so let's try to write some code. The problem is that there are many ways to organize your code, so all that follow is just a kind of pseudo code, it cannot be used directly into your application!
In your case, you could create just a ViewModel like this one
public class WhateverYouWantViewModel : INotifyPropertyChanged
{
private EmpDetailsModel _model;
public EmpDetailsModel Model
{
get { return _model; }
set
{
if (value != _model)
{
_model = value;
RaisePropertyChanged("Model");
}
}
}
public void GetLastestEntries()
{
// put in here the code calling your service
}
}
About assignements from data service to your this.Model, we are dealing with an asynchronous callback, so maybe it would be wiser to use the Dispatcher in case the callback is not called from the UI Thread :
EmpAzureSer empAzureSer = new EmpAzureSer();
empAzueSer.GetLatestEntry += new GetLatestEntryCompletedEventHandler(LatestEntryCompleted);
private void LatestEntryCompleted(object sender, GetLatestEntryCompletedEventArgs e
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
this.Model = new EmpDetailsModel()
{
//get the data from e as e.Name,e.Id and e.Address and bind them to UI.
};
});
}
Creating a new EmpDetailsModels before assigning it to this.Model will trigger RaisePropertyChanged and notify the View this property has changed. More specifically, the UI component bound to this property will be notified for being updated.
To bind your UI components to the ViewModel, you can do something like that :
<Button Name="FetachLAtest" Click="FetachLatest_Click"></Button>
<TextBlock Name="EmployeeName" Text="{Binding Model.EmpName}"></TextBlock>
<TextBlock Name="EmployeeID" Text="{Binding Model.EmpId}"></TextBlock>
<TextBlock Name="EmployeeAddress" Text="{Binding Model.Address}"></TextBlock>
Do not forget to set the DataContext of your View with your ViewModel instance.
Last but not least, you have to bind your "Latest Entry" Button to the ViewModel.GetLastestEntries method by calling it from your *View.FetachLatest_Click* event handler. All this can be achieved this way :
public partial class YourView : BasePage
{
private WhateverYouWantViewModel _viewModel;
public YourView()
{
InitializeComponent();
_viewModel = new WhateverYouWantViewModel();
this.DataContext = _viewModel;
}
private void FetachLatest_Click(object sender, RoutedEventArgs e)
{
_viewModel.GetLastestEntries();
}
}
And that's (almost) it! Why almost? Because the link between the View and the ViewModel is quite strong and defined into the code behind (which is something we are usually trying to avoid in MVVM).
Fortunately, there are some solutions to solve this issue :
What we call a ViewModelLocator could be used to store and to locate
ViewModels
A Command could be created in WhateverYouWantViewModel and bound to the "Lastest
Entry" Button, instead of calling directly the GetLastestEntries method in code behind
The downside of all this is that you would have to write more code and that's where MVVM framweworks come up! These frameworks will help you to write clean MVVM applications with minimum effort.
As a beginner, i would warmely advice you to visit MVVM Light Toolkit website. It contains lots of useful articles about the MVVM pattern, to learn how to design an MVVM application and to handle common scenarii using this framework. MVVM Light is not the only MVVM framework running on Windows Phone but i'm quoting it because it is widely used, it has a big community and it strives to keep things as simple as possible.
I'm aware this answer is only a starting point to achieve what you want. I only give you some ideas that need further study, but i hope it will help you move in the right direction.
Related
I'm trying to learn on MVVM. I've understand the concept, however, i'm confused about the binding. I'm not sure where to bind my Fill property. Please help. Tqvm in advanced.
View - name: MainScreen.xaml
<Path Fill="{Binding mainScreenClass, Converter={StaticResource colorConverter}}"/>
inCodeBehind
DataContext = new vmMainScreen();
ViewModel - name:vmMainScreen
public ICommand cmdMouseEnterNav { get; private set; }
public mMainScreen mainScreenClass { get; set; }
public vmMainScreen()
{
mainScreenClass = new mMainScreen();
mainScreenClass.propNaviconFill = new SolidColorBrush(Colors.White);
naviconMouseEventChecker();
}
private void naviconMouseEventChecker()
{
cmdMouseEnterNav = new SimpleCommand
{
ExecuteDelegate = x => mainScreenClass.propNaviconFill = (SolidColorBrush)(new BrushConverter().ConvertFrom("#c5a02b"))
};
}
Model - name:mMainScreen
public class mMainScreen : INotifyPropertyChanged
{
private Brush _NaviconFill = new SolidColorBrush(Colors.White);
public Brush propNaviconFill
{
get
{
return this._NaviconFill;
}
set
{
this._NaviconFill = value;
NotifyPropertyChanged("propNaviconFill");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
I understand that when i breakpoint on my colorConverter, I'm getting the class. Not the property of propNaviconFill. If i create another property with the Brush class on my ViewModel and bind it to Fill, there is no problem. But that means I'm not following the correct structure of MVVM. Thanks again.
You should bind to the property of your view model.
<Path Fill="{Binding propNaviconFill, Converter={StaticResource colorConverter}}"/>
Use the view model implementing the INotifyPropertyChanged as the data context of your view.
DataContext = new mMainScreen();
If you really want to use vmMainScreen as your data context, then vmMainScreen should implement INotifyPropertyChanged there and you should study how NotifyPropertyChanged was used to notify the view that the view model property has changed.
Keep in mind there are two basic types of MVVM:
1. View First
2. View Model First
Based on your example you are trying to do View First. This is easier to implement but comes with drawbacks on larger projects since the view controls the creation of the ViewModel it's harder to inject data or state into the ViewModel.
For all MVVM patterns you have the three parts:
Model - Basically a state bag. This thing is just like a customer class which most of the time implements INotifyProperty changed.
ViewModel - This is like the controller class in MVC. It has all the real logic and does the work.
View - This is your XAML and it only holds presentation logic. The code-behind class ie: MyWindow.xaml.cs should not be used except to setup the ViewModel if your going View First. (there are exceptions of course but generally it should basically be empty)
For View First
Your Window (or control) should create the ViewModel in the constructor and assign it to the DataContext.
Your ViewModel will have ICommand's, ObservableCollections and such that can be bound to controls in the View. So when your constructor fires you fill up your data and put it into the necessary structures; because of databinding this gets related to the View and shown.
Your Model (you usually have more than one, can have Customer, Order, StockTicker or whatever.) These are created by the ViewModel and put into things such as ObservableCollections for the View to databind to.
I have a Silverlight/WPF application I'm enhancing. I have a UserControl and it needs to disable or enable some controls when a property on the model changes. It has to do some other logic, so I can't just bind them to the property.
In the control's code behind, I have a reference to the model. I know there is a way to bind to certain properties, and I know how to do it in XAML, but not in the code-behind.
I've seen a lot of instances say to use the INotifyPropertyChanged interface, but it doesn't seem to apply in this case.
An example of what I'm trying to do:
public partial class MyControl : UserControl
{
private readonly MyModel _model;
public MyControl(MyModel model)
{
_model = model;
// bind to model's ImportantThing property here
}
...
// Some method gets called when property changes
...
}
public class MyModel
{
...
public bool ImportantThing
{
get { return _importantThing; }
set
{
_importantThing = value;
// This is existing code and notifies some controls, but not the ones
// I'm interested in. It should notify MyControl as well. I know in
// most applications, this is OnPropertyChanged();
RaisePropertyChanged("ImportantThing");
}
}
}
Any pointers?
Some Pointers....
Your issue\solution sounds like a task for a ValueConverter. But first, I can see code in the UserControl code-behind file, you really should adopt and apply the MVVM pattern... OK there is a [steep] learning curve and sometimes you wonder if it's worth the effort (know I did when I started with XAML)... But take my word for it.... MVVM, there simply in no other way to develop using WPF. If you try to apply the WinForms UI Logic to WPF it will become an unmaintainable, unmanageable monolithic pile of spaghetti code....
you might find this link to Rachel Lim's Blog useful....
https://rachel53461.wordpress.com/category/mvvm/
and for ValueConverter take a look at this.....
http://www.wpftutorial.net/ValueConverters.html
I apologize, my original question wasn't all that clear, but I've found a solution. It turns out the UserControl (MyControl in my original example) was already watching the Model for changes:
_myModel.PropertyChanged += Model_PropertyChanged;
In the existing callback (Model_PropertyChanged()), I just looked for the property I was interested in and added everything else I needed:
void Model_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "StatusEnabled")
{
// do stuff
}
else if (e.PropertyName == "ImportantThing")
{
// my stuff
}
}
Thanks for everyone's input!
I am trying to learn to use the MVVM Light Toolkit but i did not find a concrete definition of what is
"Messaging"
and the
"Messenger Class"
mvvm light - messaging
Someone asked this question but before reading the articles that are given in the answers can anyone give a concrete definition of what Messaging means in MVVM ?
Thank you !
There are some cases wich is not easy to make a property in the viewmodel and link it to the view. You need a class to bind any property from the code behind the WPF to the viewmodel.
In the following example, every time the user selects several rows from the grid (the view), the number of selected rows is passed to the viewmodel using the Messenger class:
//in the view
public MainWindow(){
InitializeComponent();
this.MyGrid.SelectionChanged += MyGrid_SelectionChanged;
}
void MyGrid_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
Messenger.Default.Send<IList>(this.MyGrid.SelectedItems);
}
//in the viewmodel
private IList _numFilasSeleccionadas;
public IList NumFilasSeleccionadas
{
get { return _numFilasSeleccionadas; }
set
{
_numFilasSeleccionadas = value;
RaisePropertyChanged("NumFilasSeleccionadas");
}
}
private void RegisterCommands()
{
Messenger.Default.Register<IList>(this, d => this.NumFilasSeleccionadas = d);
}
I am trying to come up with a good way of implementing the MVVM pattern using Entity-Framework where my entities are my models. My DataContext is my viewmodel. This is a small reproduction of the problem.
View
<TextBox Text="{Binding MyText}" />
ViewModel:
I have the requirement of needing to navigate record by record from my DB. When a button is clicked in the View a command is sent to the Viewmodel that executes nextRecord(). EF does its magic and _myObject is the next row/record from the database
public class myViewModel: INotifyPropertyChanged
{
private MyEntityObject _myObject;
public string MyText
{
get { return _myObject.MyText; }
set
{
if (_myObject.MyText != value)
{
_myObject.MyText = value;
OnPropertyChanged("MyText");
}
}
}
private void _nextRecord()
{
_myObject = myEntitiesContext.NextRecord() //pseudocode
}
}
Autogenerated Entity Model
public partial class MyEntityObject
{
public string MyText { get; set; }
}
Since the View has no knowledge of _myObject changing, it doesn't update when _myObject changes. A few approaches I have thought of.
I haven't tested wrapping my entities in a INotifyPropertyChanged wrapper class but am wary to do this as I have a lot of entity objects.
I could call OnPropertyChanged("...") for all properties, but some of my entities have a lot of properties to them, which would be ugly. Possible to use reflection to make it cleaner, but I may have properties that aren't databound.
I might be able to defer this to the UI, somehow refreshing the bindings when I click "Next Record", but this breaks MVVM and looks dirty
How can I get the UI to recognize changes from _myObject?
As I've mentioned in the comments, calling OnPropertyChanged("") or OnPropertyChanged(null) invalidates all properties and is equivalent to calling OnPropertyChanged for each and every property. This behavior is also documented here:
The PropertyChanged event can indicate all properties on the object
have changed by using either null or String.Empty as the property name
in the PropertyChangedEventArgs.
This means that you can simply add a call to OnPropertyChanged("") when you update your object to force WPF to reevaluate all bindings to your view model:
private void _nextRecord()
{
_myObject = myEntitiesContext.NextRecord();
OnPropertyChanged("");
}
That being said, I'd still go with #Anand's solution (+1). There's an ongoing debate on whether it's OK or not for the viewmodel to expose the model as a property, and I tend to go with exposing it until you need to introduce some view model specific logic. Most of the time you won't have to and it's not worth the trouble of wrapping model properties.
The problem with your code is that when _myObject changes the MyText property changed event is not fired. A work around would be to create a new property to hold you entity
and make this property as your Grids DataContext in your view as shown below. Now when this line is executed MyObject = myEntitiesObject.NextRecord() your view will be notified about the change.
public class myViewModel : INotifyPropertyChanged
{
private MyEntityObject _myObject;
public MyEntityObject MyObject
{
get { return _myObject; }
set {
if (_myObject != value)
{
_myObject = value;
OnPropertyChanged("MyObject");
}
}
}
private void _nextRecord()
{
MyObject = myEntitiesObject.NextRecord() //pseudocode
}
}
View:
<Grid DataContext="{Binding MyObject}">
<TextBlock Text="{Binding MyText}"/>
</Grid>
An extremely simple but not very elegant solution that I believe would meet needs: upon switching records, set the DataContext to null, then back to the ViewModel.
However, there are arguably more elegant alternatives that require more work to meet all requirements. See Anand's answer for an improvement upon this.
The tag in View should have the mode and UpdateSourceTrigger attribute set with values.
The following code is a refactoring of my previous MVVM approach (Fat Models, skinny ViewModels and dumb Views, the best MVVM approach?) in which I moved the logic and INotifyPropertyChanged implementation from the model back up into the ViewModel. This makes more sense, since as was pointed out, you often you have to use models that you either can't change or don't want to change and so your MVVM approach should be able to work with any model class as it happens to exist.
This example still allows you to view the live data from your model in design mode in Visual Studio and Expression Blend which I think is significant since you could have a mock data store that the designer connects to which has e.g. the smallest and largest strings that the UI can possibly encounter so that he can adjust the design based on those extremes.
Questions:
I'm a bit surprised that I even have to "put a timer" in my ViewModel since it seems like that is a function of INotifyPropertyChanged, it seems redundant, but it was the only way I could get the XAML UI to constantly (once per second) reflect the state of my model. So it would be interesting to hear anyone who may have taken this approach if you encountered any disadvantages down the road, e.g. with threading or performance.
The following code will work if you just copy the XAML and code behind into a new WPF project.
XAML:
<Window x:Class="TestMvvm73892.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestMvvm73892"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<ObjectDataProvider
x:Key="DataSourceCustomer"
ObjectType="{x:Type local:CustomerViewModel}"
MethodName="GetCustomerViewModel"/>
</Window.Resources>
<DockPanel DataContext="{StaticResource DataSourceCustomer}">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock Text="{Binding Path=FirstName}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding Path=LastName}"/>
</StackPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock Text="{Binding Path=TimeOfMostRecentActivity}"/>
</StackPanel>
</DockPanel>
</Window>
Code Behind:
using System;
using System.Windows;
using System.ComponentModel;
using System.Threading;
namespace TestMvvm73892
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
//view model
public class CustomerViewModel : INotifyPropertyChanged
{
private string _firstName;
private string _lastName;
private DateTime _timeOfMostRecentActivity;
private Timer _timer;
public string FirstName
{
get
{
return _firstName;
}
set
{
_firstName = value;
this.RaisePropertyChanged("FirstName");
}
}
public string LastName
{
get
{
return _lastName;
}
set
{
_lastName = value;
this.RaisePropertyChanged("LastName");
}
}
public DateTime TimeOfMostRecentActivity
{
get
{
return _timeOfMostRecentActivity;
}
set
{
_timeOfMostRecentActivity = value;
this.RaisePropertyChanged("TimeOfMostRecentActivity");
}
}
public CustomerViewModel()
{
_timer = new Timer(CheckForChangesInModel, null, 0, 1000);
}
private void CheckForChangesInModel(object state)
{
Customer currentCustomer = CustomerViewModel.GetCurrentCustomer();
MapFieldsFromModeltoViewModel(currentCustomer, this);
}
public static CustomerViewModel GetCustomerViewModel()
{
CustomerViewModel customerViewModel = new CustomerViewModel();
Customer currentCustomer = CustomerViewModel.GetCurrentCustomer();
MapFieldsFromModeltoViewModel(currentCustomer, customerViewModel);
return customerViewModel;
}
public static void MapFieldsFromModeltoViewModel
(Customer model, CustomerViewModel viewModel)
{
viewModel.FirstName = model.FirstName;
viewModel.LastName = model.LastName;
viewModel.TimeOfMostRecentActivity = model.TimeOfMostRecentActivity;
}
public static Customer GetCurrentCustomer()
{
return Customer.GetCurrentCustomer();
}
//INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
//model
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime TimeOfMostRecentActivity { get; set; }
public static Customer GetCurrentCustomer()
{
return new Customer
{ FirstName = "Jim"
, LastName = "Smith"
, TimeOfMostRecentActivity = DateTime.Now
};
}
}
}
I like your sample above, I think it implements the spirit of MVVM. Just for clarification, though, the ViewModel code and the Model code should not be in the same source file as the actual Code Behind. In fact, I would argue that they should not be in the same project.
Here is MVVM as I understand it:
M - the Model is the data returned from the Business Layer (BL). This should be lightweight, containing read-only data. The Model classes are dumb and do not contain Update, Write, or Delete logic, and are generated by the BL as the result of requests, commands, actions, etc. The Model classes have no knowledge of the presentation needs of the consuming application, so they can be used by any manner of application. To really take advantage of this reusability, we want the Model classes to be independent of the UI project.
VM - the ViewModel contains the communications layer: it issues the requests to the BL and processes the results in a manner fit for presentation. Like the example above, it also receives the Model and reformats it for the particular presentation needs. Think of this as a "Binding Class". In the example above, the data is simply being moved from one object to the next, but the ViewModel would be responsible for such things as exposing a "FullName" type property or adding leading zeroes to a ZipCode. It is correct that the Binding Class is the one to implement INotifyPropertyChanged. And again, for reusability I would probably extract this layer into its own project as well. This would allow you to experiment with various UI options with no plumbing changes.
V - the View is bound to the Binding class object created in the VM. The View is super dumb: it knows nothing of the BL or the VM. Data can be bound in both directions, but the VM handles errors, validation, etc. Any data synchronization operations are handled by passing requests back the the BL, and again processing the results.
It would depend on the type of application, but it seems heavy handed to constantly check the Model to see if it has changed. Pretend you were connecting to a BL that built the Business Object(BO) from a DAL, which is connecting to a DB. In this scenario, you would be constantly recreating the BO, which I'm sure would be a performance killer. You could implement a checkout system on the BL that listened for notifications, or have a method for comparing last known time of change to actual, or you could cache the BO on the BL. Just some ideas.
Also, I said above that the Model should be Lightweight. There are heavyweight options, like CSLA, but I'm not sure how well they fit into the MVVM idea.
I don't mean to pass myself off as an expert, I have only been studying these ideas so far while designing our new software's architecture. I'd love to read some discussion about this topic.
My personal opinion is that while Model should be used to load and store data, ViewModel's responsibility is to know when this data is needed, thus using timer in a ViewModel makes sense. This way you can use your Model with different ViewModel (for which it may be sufficient to retrieve data only once, not every second).
Few things to consider:
Implement your model to support
Asynchronous data retrieval (very
important if you want to target Silverlight)
Be careful about updating collection from background thread (not a problem in your example, but if you ever need to use ObservableCollection than remember that it cannot be updated from non UI thread, read more here )