When using .NET RIA Services and MVVM in Silverlight 3.0 is there a difference between the Metadata type from RIA Services and the ViewModel from the MVVM pattern? Are these the same thing or should they be keep separate?
The metadata type is a sealed internal class to the partial Entity class. There doesn't seem to be a proper separation there but the metadata type can also be decorated with attributes for Validation which makes it look like a ViewModel.
I've searched around but I didn't see anything that talks about this in any detail.
Agree with ChuckJ - generally the DomainContext forms part of a view model. For example, say I had a search page that allowed searching against a product catalog. Here is how I'd structure things:
On the server:
class Catalog : DomainService {
IQueryable<Product> GetProducts(string keyword) { ... }
}
The generated DomainContext:
class Catalog : DomainContext {
EntityList<Product> Products { get; }
void LoadProducts(string keyword);
}
The view model I would write:
class SearchViewModel {
Catalog _catalog = new Catalog();
public IEnumerable<Product> Results {
get { return _catalog.Products; }
}
public void Search(string keyword) {
_catalog.Products.Clear();
_catalog.LoadProducts(keyword);
}
}
And then finally in my xaml, I'd set my UserControl's DataContext to be an instance of SearchViewModel, and bind an ItemsControl to the Results property. I'd use the ViewModel pattern of your choice to bind a button click to Search (which is effectively a command that SearchViewModel exposes). I personally like something that I have working with Silverlight.FX as in:
<Button Content="Search"
fxui:Interaction.ClickAction="$model.Search(keywordTextBox.Text)" />
and as initially shown here.
As Chuck mentions I might indeed have other state in my view model, for example, the SelectedProduct that might be two-way bound to the SelectedItem of a ListBox in my xaml, and then bind the same SelectedProduct as the DataContext of a DataForm to show details of a selected product.
Hope that helps! I'll be blogging about this some more on my blog soon.
The RIA services data context was designed to play the role of a ViewModel in the MVVM pattern since they natively support data binding, but they don't use that term in their documentation. However, it really depends. You will probably need state in your view model than the RIA data context provides such as commands and other view related state. I think what you want to do is use the data contexts from the RIA services as a part of the view model.
Related
I need to send notification from ViewModel to View in MVVM WPF application. In most cases it will be simple MessageBox on View side. Is it unacceptable violation of MVVM pattern to use types like System.Windows.MessageBoxResult or System.Windows.MessageBoxImage in ViewModel (in this case VM must reference UI-specific libraries)?
I need to pass title, message and notification type from VM and by creating custom enumerations I am in fact copying existing functionality from .NET Framework.
You don't need notification mechanism. That's one option. Another is using simple service class:
public class ViewModel
{
IDialogService _dialogService; //ctor injection or use service locator
public void CommandExecute()
{
_dialogService.ShowMessageBox(...);
}
}
public interface IDialogService
{
bool? ShowMessageBox(params....);
}
public class DialogService : IDialogService
{
public bool? ShowDialog(params...)
{
MessageBox.Show(params...);
}
}
I find this approach more straightforward, easier to understand and easier to debug. Messaging may easily turn into memory leak and in this case I don't see any benefit over my approach.
EDIT:
Will you use custom enum in ShowMessageBox parameters, or will you use
System.Windows.MessageBoxImage?
First of all, ViewModels belong to presentation layer. It is OK to use enums like System.Windows.MessageBoxImage in ViewModel.
In MVVM, ViewModels are separated from Views because of following reasons:
ViewModels expose data and logic from Model in such way that is easily consumable from Views (e.g DataBinding)
ViewModels are easier testable
ViewModels provides better design time support (Blendability, test data)
ViewModels separates application logic from the actual presentation markup which makes it easier to understand (readbility)
Does using enum like System.Windows.MessageBoxImage breaks any of the points above? The answer is no.
If you wanted to reuse IDialogService and your ViewModels on multiple platforms, for example WPF, UWP and Xamarin, then you need to create your own enum, because it may not exist on all platforms. The golden rule is: don't add another layer of abstraction if you don't need it.
You could have the view implement an interface, say INotificationService and then pass the view to the view model constructor. That won't violate MVVM, and you will still be able to bind the view model to the view using the DataContext property on the view.
I decided to keep ViewModel as clean of UI (View) stuff as possible, so I will create custom enumeration inspired by MessageBox and tailored exactly to my needs.
If you know the MVVM pattern for WPF then you know Josh smith msdn article where a CustomerViewModel does not hold a simple property like:
public string FirstName {get;set;}
Rather a ViewModel wraps a Model and delegates the property access like this:
public string FirstName
{
get { return _customer.FirstName; }
set
{
if (value == _customer.FirstName)
return;
_customer.FirstName = value;
base.OnPropertyChanged("FirstName");
}
}
I have not seen this in asp.net mvc. Is this due to the missing INotifyPropertyChanged interface?
I have not seen this in asp.net mvc
That's normal. You shouldn't see it. MVC is a different pattern than MVVM. In MVC the view has nobody to notify of any changes. The MVVM pattern is not adapted to the stateless nature of the web.
The ViewModel and Model pieces from MVVM have a different definition than when used in MVC
In MVVM, the ViewModel is your application, while the View just provides a user-friendly interface for it. In MVC, the View is your application, the ViewModel provides data for it, and the Controller handles application flow and logic.
The Models are also different between the two patterns. In MVC, the M represents both data models and view models, while in MVVM the M only represents data models.
To summarize, MVC's M+C is equal to MVVM's VM, and MVC's M contains a mix of both MVVM's M and VM pieces
As a side note, the INotifyPropertyChanged interface is used by WPF to automatically update the UI when a property changes. This sort of thing is not used in MVC, so not needed.
I have a list of items representing packages in an MVVM control.
When you hover over the tooltip it needs to go to the database for additional information, lets just call it 'PackageDetails' for simplicity. I know how to handle the database loading with a ViewModel class but I'm having trouble figuring out when to instantiate it.
Approach 1) Have a 'lazy-load' property in the 'Package' object so when the tooltip is triggered the viewmodel will be created and immediately access the database.
This approach isn't ideal because each 'Package' object isn't a true viewmodel and came from WCF objects originally.
Approach 2) Use a converter as explained in this Josh Smith blog entry. His example seems to fit a converter well, but I don't think it really suits my situation well.
Approach 3) Somehow create a viewmodel in the XAML, but this seems like a bad idea.
What's a good approach to dynamically generate a viewmodel for a tooltip using MVVM
?
Binding models ( in your case the packages ) to the view only works for very simple situations where there is no more "processing" or business logic to implement.
I have experimented with a few options and in the ended up creating a VM wrapper for just about all my models. Going down this path makes having a tooltip property straight forward.
The other option that i have experimented with is to use partial classes to extend the wcf models. This works unless you are using dataannotations for validation ( wcf and dataannotations dont work together properly )
if you decide to wrap your models with a vm, then instantiating your list of VM wrappers is just one line of code using linq and lambdas
assuming you have a constructor on your VM that accepts your model as a parameter.
var listPackageVMs = new ObservableCollection<PackageVM> ( listPackageModels.Select(model=> new PackageVM(model)));
You could create a partial class to Package. I would avoid placing data access logic in an entity class, but this is the cheap and easy way.
namespace WCFServiceNamespace
{
// Since WCF generated entities are partial classes, we can inject features
public partial class Package
{
private readonly IDataAccessor _DataAccessor;
public Package()
: this(DataAccessor.Instance) // how you choose to inject a data accessor is up to you
{
}
public Package(IDataAccessor dataAccessor)
{
_DataAccessor = dataAccessor;
_ToolTip = new Lazy<string>(GetToolTip);
}
private readonly Lazy<string> _ToolTip;
public string ToolTip
{
get
{
// executes GetToolTip when the Value property of Lazy<T> is accessed
return _ToolTip.Value;
}
}
private string GetToolTip()
{
// we're assuming we can retreive the tooltip by ID, and that PackageId is defined in the generated WCF entity
return _DataAccessor.GetToolTipByPackageId(PackageId);
}
}
}
Good evening,
I am looking for someone to help me with my understanding of how to incorporate the Silverlight DataForm with my ViewModel that using WCF Ria Services. What I am trying to accomplish is using the DataForm manage my collection of entity and utilize its built in navigation, Add, Edit and Delete functionality. Howerver, I am having trouble tying it all together with my ViewModel and Ria Services.
From my understanding, the DataForm needs to be bound to an ObservableCollection<T>. However when I query from the WCF Ria Service context. ie.
_context.Load(_context.GetAllCustomersQuery(), loadCustomersQueryCallback, true);
I will receive back an IQueryable in the callback method, which i would have to cast as an ObservableCollection<T> like so?
Customers = new ObservableCollection<Customer>(_context.Customers);
Customers is a property in my ViewModel like so...
public ObservableCollection<Customer> Customers
{
get { return _customers; }
set
{
if (_customers != value)
{
_customers = value;
OnPropertyChanged("Customers");
}
}
}
The DataForm is bound to the Customers Property of the ViewModel and I am able to see the data from my datasource, I can navigate between entities, I can edit an existing entity and persist the changes back to the database however I cannot add or delete entites.
Is what I'm doing with the Customers property correct? have I "disconnected" from the context by casting into a new ObservableCollection and therefore have not actually added or removed the entities from the context?
Any help is greatly appreciated.
Regards,
I think you hit on the issue in your last question. When you create a new ObservableCollection, you've disconnected from collection change tracking (adds and deletes). Instead of using OC, there are a number of other options worth considering. In your case, it looks like EntitySet or EntityList may be the best options. For a full rundown of these types, take a look at my post on collection binding in RIA Services SP1.
You could use :
Customers.Clear(); // Or dispose every customer if it is Disposable
Customers = new ObservableCollection(result.ToList());
In a three-tier model (presentation-business-data access layers), I can consistently keep my lower layers agnostic of the upper layers. For example my data access layer never knows how it is presented or what busines rules are operated on it. My business rules are agnostic of how they're presented.
But I must pray to Demeter for forgiveness or at least ask fellow Stackoverflow members for advice on one thing: How do you present a "Table" to the user without referencing the Data Access object in the Presentation Layer? Time and again, I find myself referencing a ADO.NET DataTable in a GridView object. Currently I'm using third-party tools in both layers. The Table is from OpenLink's OpenComponents Table object; the grid is an Infragistics UltraGrid (Windows platform). Yet I'm guilty of the same infraction.
edit:
I am most especially interested in how this may be done with WinForm 3.5 .NET. Note my comments below: I believe the link in the comment is what I should have done, but I was hoping that I wouldn't have to get too fancy with domain objects. I don't want to be accused of over-designing. Is this a good balance?
Instead of using a datatype that represents a table, I'd use a Data Transfer Object. This would be an object that represents the logical structure of the data. It would contain nothing but data.
In this case, I'd define a DTO for my "data row" type, and then use a List<RowDTO> as the type I'd pass to the grid.
I'm not sure how other stackoverflow members would do it, but WPF, ASP MVC, Silverlight, what you would do is use the MVVM design pattern. I'm afraid I don't have any good links for you at the moment.
In MVVM, the key idea is that your View accesses data in the ViewModel. The ViewModel presents data to the View by exposing properties. In WPF and Silverlight, you use binding to access the data and use data templates to express the exact details of how to express it. Usually you will expose a collection with an ObservableCollection. In ASP MVC, you would context switch and access the model that way.
<body> <h1><% Model.MyHeaderMessage %></h1>
I would say that what you should do is in your ViewModel (similar to a controller) hit the server / service for data, and return the recordset. Repackage the data in simple data classes, and put them in a ObservableCollection expose this to the view via a property that returns ObservableCollection. If you are doing ASP MVC, expose the data via a property that returns an IEnumerable.
A very common pattern for this is the Model View Presenter pattern (MVP).
The key here is to define an interface which will represent your View. For instance, your view could have a property.
And a presenter that should be responsible for communication between the view and model.
So a view would be something like this:
internal interface IListClientsView
{
public string Title { set; }
public IList<Client> Clients { set; }
}
And the implementation in a web form would be this:
public partial class WebForm1 : System.Web.UI.Page, IListClientsView
{
ListClientsPresenter presenter;
protected void Page_Load(object sender, EventArgs e)
{
presenter = new ListClientsPresenter(this);
if (!Page.IsPostBack)
presenter.LoadView();
}
public IList<Client> Clients
{
set { GrvClients.DataSource = value;
GrvClients.DataBind();
}
}
}
Of course, this could also be a WinForm. The key is just make the WinForm inplement the IxxxView interface and call the related presenter. The presenter would look like this:
public class ListClientsPresenter
{
IListClientsView View;
public ListClientsPresenter(IListClientsView view)
{
this.View = view;
}
public void LoadView()
{
View.Title = "List of Clients";
View.Clients = new List<Client> {
new Client {Name = "Client 1"},
new Client {Name = "Client 2"}
};
}
}
This is a very simple example, you should check this article: http://msdn.microsoft.com/en-us/magazine/cc188690.aspx