I am building a view (web form) that will display various messages based on the state of a persons License. There are approximately 10 messages that the user will see. I don't really want to create multiple panels and show/hide and populate form fields based on the state...I would rather set a single property on the page...lets just call it:
public String Message
{
get;
set;
}
The message will include html formatting and some of the messages are much longer than other messages...I guess I am looking for a decent pattern to follow so this will be easily manageable...so my presenter will just return the formatted message based on the state of the license.
I am thinking I will create a abstract MessageTemplateBaseClass and classes for each message that build the message...The presenter will return the correct instance of the template based on the license state...
Does this sound like a decent approach?
Yes that would work, or potentially define an IKeyMessage interface that has this definition, and each presenter checks if its view defines this interface, casts it, and sets it appropriately.
HTH.
Related
I know there's a lot of questions on the topic and I understand how to do it but I need some help on the design of my architecture. I'm using the Simple MVVM Toolkit.
Architecture
I have a ShellVM which is the main VM for my app. It dishes out navigation and props that my main view binds to.
Then I have a ManageVM that does all the grit work for managing the client, stores, imports, exports etc. It also handles navigation of all my management views.
Then I have an ImportVM that fleshes out the importing of data.
I also have a static PageValues dictionary that stores pages and specific properties and values that should be retained when switching views. It also stores any 'global' properties that is used throughout certain VMs.
I'm using Messaging to pass data between the VMs. The validation and prompts (using dialogs) of the PageValues data is controlled in my ManageVM. I placed it here as I feel my ManageVM should handle all 'management' like setting the client and store. Setting the actual values is done by sending a message to the ShellVM that handles this.
The ShellVM handles the CRUD of the PageValues. So in other words, if any VM gets or sets a global/shell-wide property, it does so by means of messaging to the ShellVM. The ShellVM then sends the message/result back to whichever VM requested it.
Question
This feels very spaghetti-like. I've got a ManageVM that does the loading and validations on PageValues that are actually CRUD'ed in the ShellVM.
Am I on the right track or is there any other suggestion I can try to make this feel a bit cleaner?
Thanks for reading.
Edit
What I'm trying to achieve is to have a container that holds values (ie client and store) that could be accessible from multiple VMs. A bonus is to have each page's/view's values in this container too. Then on showing of the view, it will grab its values from the container and populate the view.
You said
if any VM gets or sets a global/shell-wide property, it does so by
means of messaging to the ShellVM
I propose an interface based approach instead of message passing for this purpose. ViewModels passing messages is for view models to communicate,not for setting a global state. If there is a global state of the application,it is better handled through a dedicated service, IMO.
public interface IApplicationService
{
//your applcation methods here
}
public class ApplicationService:IApplicationService
{
}
public class ManageVM
{
public ManageVM(IApplicationService){}
}
public class ShellVM
{
public ShellVM(IApplicationService){}
}
public class SomeOtherVM
{
public SomeOtherVM(IApplicationService){}
}
Yes, this does sound rather messy. You need to try and isolate areas of functionality into their own VMs so they are not dependent on one another.
One of the tricks I use to do this is to try and imagine that I suddenly need to copy a blob of functionality (say one of your pageviews) into another application. How easy would it be? Would it be a case of just copying one VM and injecting a few dependencies? Or is the VM impossibly coupled to the rest of the app?
It's a bit difficult to give advice without knowing exactly what your app is doing, but really you want each PageVM to be in charge of it's own validation, and CRUD. Or, if the data is shared between many pages, then you need to pass in some kind of repository than the PageVMs can query for data. If validation logic is specific to some data, then put it on the model itself and just leave the presentation of that validation to the VM.
For global settings, I tend to pass around a settings object rather than using messaging.
Have a read up on inversion of control, and dependency injection. These can help you to keep objects loosely coupled because you can see exactly what other things your object is depending upon by looking at the constructor. If you are passing in half the application then it can serve as a warning alarm to try and reduce the coupling.
I am creating a simple WPF Application. I've a function OpenFile:
private void OpenFile(string fileName)
{
if(!File.Exists(Helper.GetPath(fileName)))
{
MessageBox.Show("Error opening file");
}
else
{
//Code to handle file opening
}
}
Ideally where should this function be present? I feel it should be in .xaml.cs because it accesses a MessageBox which comes in the View part. But it also calls my Helper, which is in the model. So I also think it can be in the ViewModel. What is the advantage of having this in the View or in the ViewModel? Can someone help me with some pointers?
Thanks.
One of the advantages of placing it in the view model would be testability. You could write a unit test that checks that the message box is only displayed if the file exists for example (more accurately it would be an integration test if you are hitting the file system).
However, because you are using a message box directly, your test would never complete on a build server because the machine would be waiting for input from the user whilst the message box is displayed.
Therefore, I would work against an abstraction in your view model, so that you can mock the message box during tests.
This function must be in the ViewModel. You need to create an operation in your view for showing the error message and call this method instead of MessageBox.Show. Showing the message box needs to be done in the View.
Generally you should avoid implementing any business logic inside the View such as validating or handling a file.
If you're using Microsoft Prism you can use the IInteractionRequest interface to have the view create the MessageBox, but actually pass back the necessary response to the view-model.
If you are not using Microsoft Prism, then look at how this part works and either simulate it or use a framework that does something similar.
Basically, that code should go on your view-model for testability, but replace the line where you explicitly call the MessageBox and use the IInteractionRequest mentioned instead.
Here is the documentation pertinent to the scenario you're looking to implement: Chapter 6: Advanced MVVM Scenarios. Look at the section stated User Interaction Patterns.
I am working on a BI application in WPF. I am in the process of designing its architecture and am in search of a way to directly bind controls in the view to a xml which contains the metadata of the view. Do you think this is going to be possible? then how? or is it advisable to read off from the xml and generate the views accordingly?
Edited
Properties such as colors of charts, who created the chart, the next chart upon drilling down a chart, the user names and their passwords, user group names etc. are stored in XML files. When a user starts the application the dashboards he has created should be displayed; this happens with the retrieval of data from the back end and by assigning the correct chart colors. So if these data are available in the XML, my question is the best way to generate the charts and dashboards upon user request.
Edited
As I explained earlier as well, the problem is to store the metadata related to this application in the most efficient and structured way to call back upon a user loging in.
Thanks in advance.
I'm not sure I quite understand what you are looking to do. If you just want to bind some UI control properties to data in an XML document, that's entirely possible. I blogged about it years ago here.
I will suggest use of XAML instead of XML.
XAML will not only let you define the UI but XAML also can contain your other metadata or config information that you can read/write in the form of XAML to directly your CLR class.
Benefits are,
Xaml serialization is exactly same as that of Xml's serialization
Xaml will give you powerful intellisense while editing in Visual Studio (xml also can give but you will have to create and update schema everytime you make changes to your configuration schema)
In case of intellisense, Xaml is better because it will automatically give validation errors
It will also allow you to use Enums
It will also hide/show members or classes based on inheritance hierarchy
You can load XAML from string coming from database as well
It will let you specify bindings as well if your object is derived from DependencyObject and you will be able to transfer or reuse the bindings in your UI
For example,
public class ScreenElement{
public string Author {get;set;}
public DateTime DateCreated {get;set;}
}
// XAML can not directly deal with generics so this step is
// necessary
public class ScreenElements : ObservableCollection<ScreenElement>
{
}
[ContentProperty("Elements")]
public class Screen
{
public Screen(){
this.Elements = new ScreenElements();
}
public string Title{get;set;}
public bool ToolbarPresent {get;set;}
// this attribute is necessary if
// you want to save Screen to xaml
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ScreenElements Elements {get; private set;}
}
And your Screen xaml can look like
<Screen xmlns="clr-namespace:MyNamespace"
Title="Home Screen"
ToolbarPresent="false"
>
<ScreenElement Author="Myself" DateCreated="..."/>
<ScreenElement Author="Yourself" DateCreated="..."/>
</Screen>
You can create XAML resource and load it like...
Screen s = XamlReader.Load(.. resource uri to your XAML)
// and now you can use your "s" loaded with elements to
// populate your UI
foreach(ScreenElement e in s.Elements){
// use attributes of e to populate things..
}
I think the best in your case would be to devide all possible data in the system by data classes - metatypes. after that, in xml, specify data metatype so your data would be always have metatype. And when, before view creation, you should read all metatypes for data you are intend to display and create screen controls according to that metatypes. After that you could load and display data. Such approach works well in my small programm and I thinks it would yield good results in your system too.
[EDIT]
OK, your application includes business domain (your business data, business logic and rules for data displaying). All this things you have spread among three parts: Model, View and ViewModel. As I understand correctly your question is stright about ViewModel.
For example your hypothetical application containы employee information and suppose every employee may have three types of information about he or she:
Personal information (Name, date of birth, photo, home address, mobile phone number)
Education information (information about education, list of completed training cources)
Proffesional experience information (list of succesfully completed commercial projects)
So we have domain - employee. This domain may be devided into three metatype:
Personal metatype
Education metatype
Proffesional experience metatype
For each metatype we should create subscreen which would display metatype information according to business rules. I'll recomend you to make metatype subscreens with MVC pattern because of in case of editing of data some special editing rule or data validation may be applyed. When we have each subscreen created we can be free to display each type of meta information in the system.
For example you application have loaded employee information. After that you can determine which metatype presented in loaded data and can force creation of appropriate subscreens. The last part of work is to pass appropriate data to each sub screen.
It was very vague explanation sorry for my english, if you have any question about I have explained feel free and ask question again
I'm writing an application (Silverlight and WPF) using the MVVM pattern and the Prism framework. In my application I have a grid that contains a list of customers. Under that, I various views that present customer details. All of the information is fed from a WCF service that provides data from queries as well as callbacks which fire events when the data has been received. The detail information is updated when the selected item in the grid is changed. There is also a filtering view that controls the date range for the detailed information.
I also need to implement a similar set of views, but for a specific customer. The information presented is the same, so obviously it would be best to reuse the same view and model classes.
My initial thought was to build a separate intermediate service that sat between the models and the WCF service for both scenarios. I would then bind the models to the specific service by registering instances by name.
Unfortunately, this would mean that I would have to instantiate a lot of the classes myself instead of relying on dependency injection which I would prefer.
So, for all the MVVM gurus out there, how should the views, models, and services be structured to best use the features of the Prism framework and promote code-reuse?
Many thanks!
==== Edit: added following text and example ====
Here is a simple example that I hope explains what I'm trying to accomplish.
public class CustomerViewModel : ICustomerViewModel
{
public ICustomerView View { get; private set; }
private readonly ICustomerService customerService { get; set; }
private Customer customer;
public CustomerViewModel(ICustomerView view, ICustomerService service, IEventAggregator eventAggregator)
{
customerService = service;
eventAggregator.GetEvent<SelectedCustomerChangedEvent>().Subscribe(CustomerChanged);
eventAggregator.GetEvent<CustomerInfoUpdatedEvent>().Subscribe(CustomerUpdated);
View = view;
View.Model = this;
}
public string Name
{
get
{
return customer.Name;
}
}
public string Email
{
get
{
return customer.Email;
}
}
public void CustomerChanged(int customerId)
{
customerService.RequestCustomerInfo(customerId);
}
public void CustomerUpdated(Customer customer)
{
this.customer = customer;
}
}
This customer view model based on the current design where the customers are in a grid. Selecting a customer fires the SelectedCustomerChangedEvent which will cause the view model to request information.
It is fed from an underlying WCF service that is using a callback mechanism to provide data (the data can take a long time to retrieve / calculate so a simple WCF call won't work). This works just fine. The problem is that I want to reuse this same view and model in a different area of the application that displays information about a specific customer instead of the current selected customer.
My initial thought was to create an intermediate service that handled the SelectedCustomerChangedEvent for the list and a similar event when the customer-specific view is opened. It would then provide data to the model through the same CustomerInfoUpdatedEvent.
The problem is that since I would now have 2 services that implement the same interface, I would need to name them and then have the view model somehow know which one to retrieve from the container.
I know I've probably made a design error. The good news is that I have time to fix it, but I'm not sure how to fix it.
If the Customer class is the same for all customers (including your specific customer), then use a single service, the same views, and the same model.
Can you tell us why this would not work?
Hmm... there is a lot of information here, but I will take a stab at this.
There's really no reason to complicate this as much as you are trying. It feels like you are receiving callback events from your WCF service... am I right? If so, you want to update the UI if the incoming WCF callback pertains to a customer that the user is viewing. I'll work from these assumptions... let me know if I misunderstand.
I think you have almost what you need. I think all you need to do is the following:
From your WCF callback handler, raise an event with the EventAggregator passing the new customer information along with the customer ID.
From any ViewModel's constructor, subscribe to the CustomerUpdated event and add a filter for the customer ID you are looking at in your view model. You are missing this, but it's critical, otherwise you will get a firehose of events that don't pertain necessarily to your instantiated ViewModel. There is a sample of this technique in this quickstart: http://msdn.microsoft.com/en-us/library/dd458918.aspx
Again, this is my best effort at understanding what you are trying to accomplish. Let us know if it's not.
I have a control in which we show some links to different sites based on some business rules. Currently all business logic to build link list is in control.
I plan to move out the busincess logic from the control.
what will be a good design for this?
can I use any design pattern?
You shouldn't get too caught up in thinking about patterns. Most of the time they are overkill and add too much complexity. Particularly with a trivial scenario like this.
Just utilize good object-oriented practices and you'll be fine. Encapsulate your business logic in another class and provide public properties for your control to access it. Keep it simple!
How about the Model-View-Presenter pattern?
Another good choice might be the Mediator pattern.
Do you really need a custom control for this?
Model-View-Controller suggests that you only have display logic in a control.
Find a solution that allows you to make small changes to a built in control (ListView) and create a custom data set somewhere else to pass to it.
I not sure how you implement your business rules but here is an idea...
I would databind your web forms list control.
public class YourLinks
{
// You could do it by overloading the constructor...
// Again not sure how you determine what links should be displayed...
// If you had consistent types you could make your constructor internal
// and then create a YourLinkBuilder see below...
public YourLinks(User user, Region region)
{
}
public YourLinks(City city)
{
}
// Databind to this method...
public IEnumerable<string> GetLinks()
{
// return your links...
}
}
public class YourLinkBuilder
{
public static YourLinks BuildPowerUserLinks()
{
return new YourLinks(new PowerUser(), new Region("Washington"));
}
public static YourLinks BuildVisitorLinks()
{
return new YourLinks(new VisitorUser(), new Region("Empty"));
}
}
Given the little information provided, I would suggest you create a model of just the links (and its related data). So that you can pass the LinksModel to your views for rendering. Or pass your LinksModel to your existing model (as a sub-model).
Either way, all this data is encapsulated. So if you want to add data to it later, it will not change your method signatures (or general contract). If you want to remove data from it, same advantage. If you want to remove it entirely, its only one object and simplifies the removal.
You can also build links view renderers so that it and only it knows how to visually display the LinksModel. So within your view, you can delegate the visual aspects of the links info to such renderers instead of having logic within your existing view. If you want to change how links view looks later or want to give the user the power of selecting different renditions, you can simply use different renderers rather than jamming your entire code with 'if' blocks.
Jeach!
You should use Model-View-Presenter for sure. In the view, you should have your control.
The control's responsibility should be merely to take input from the user, validate it, and pass that information to the presenter. The presenter should then interact with the model, where your business rules are stored.
From the model, you may wish to return the links that are then passed to the control for display, or you may wish to return some metadata that is passed to another system to retrieve the links.
What I would do is use the Strategy pattern in the model, so that you can easily swap in and out different versions of your business rules.
To abstract interaction with your backend datasource (if you have one) have a look at Martin Fowler's Gateway pattern.