Here is the scenario:
I have a visual that displays some data
The data to the visual can come in one of two ways
Via user input through the keyboard or mouse
Via some backend source
Both these data inputs can be of one of two forms
Control data or
Raw data for simple display
Control data causes changes in the visual
Raw data is simply showed as is
In other words, the view is being served by two masters, viz user input and backend input.
An example would be a multi-user game that has visuals controlled by user input
but may also have the same visuals controlled by some backend input (say tcp/ip).
Another example would be a terminal emulator that gets user inputs but also gets data
from another source be it telnet or serial, etc.
I was thinking of writing a WPF custom control for the visual. In other words,
it is a black box that will interpret the inputs and display the results.
Getting user input into this custom control is easy since one can listen for the
appropriate events and handle them as needed. However, how can one listen for the
inputs from the backend? Exposing a dependency property that one binds to does not make
sense but exposing a method on the visual that is called with the data also does not make
sense.
Another choice is the MVVM architecture where the Model is the backend data source
and the View Model does all the work. It gets both the backend data (via the model)
and the user inputs (via appropriate command bindings or some such) and it makes
appropriate sense of these and binds to the View to display these changes.
The advantage of the custom control is that it can be consumed as a control that
takes care of itself so that the consumer has to do very little work to use it
but the problem is getting data to it from the backend. The MVVM method is advantageous because it encapsulates the handling logic, view, etc neatly. The problem is that
this pattern has to be repeated for every backend. Thus, making the visual very bare bones
and exposing all the processing logic outside the control. Basically I want
to make it very easy to consume so that someone can take it and use it without adding
too much external logic to do processing etc. All they provide is their backend data
source that feeds into the visual.
Sorry for this being a lengthy post but I am learning WPF and this is an interesting design
question for me. All ideas, comments, etc welcome.
Thanks for reading.
I would definitely use the MVVM pattern. You get a very nice separation of concerns in your code, and your viewmodel can also be tested outside of the user interface. You may also be able to edit you view in Blend. I don't think that hooking up the viewmodel to the backend is more complicated than hooking up a custom control. You may decide to use dependency injection or a service locator to connect things. By using all these design patterns you get a more decoupled and testable solution.
I'd love to know more about CustomControls but in the mean time I think the best option is to use a UserControl as a DataTemplate:
http://www.codeproject.com/Articles/28060/WPF-UserControl-DataTemplate
Related
Can someone please guide me towards how to implement Custom Dialog for displaying Errors or simple messages to the UI and recieving response back without violating MVVM. I am in badly need of this. Please help me out.
Thanks,
Zafar
Referring to your comment I strongly suggest you take a close look at the Messenger class. It even provides GalaSoft.MvvmLight.Messaging.DialogMessage type for this purpose. But you can provide your custom ones be subclassing GenericMessage<T>
You register for a message like this and define what should happen on arrival of a message:
Messenger.Default.Register<DialogMessage>(this,
dm =>
{
MessageBox.Show(dm.Content, dm.Caption, dm.Button, dm.Icon);
});
Although there is only a WeakReference hold, i tend to unregister if I dont want to be informed anymore or the view is discarded. Always be a good citizen ;)
Messenger.Default.Unregister(this);
Send a message to the receiver and optionally define a callback to get back the dialogresult:
Messenger.Default.Send(new DialogMessage(this, "Content",
result => Console.WriteLine(result.ToString()))
{
Caption = "Caption"
Icon = MessageBoxImage.Asterisk,
Button = MessageBoxButton.OK
});
To handle any kind of dialog stuff within the mvvm pattern, you should go with a kind of Dialog-Service. In this post you will find some hints to go with this approach.
Putting dialog stuff into a service keeps the mvvm pattern untouched. The service takes care of all the creation of the dialogs and can provide the results. The view-model just calls methods and subscribes events provided by a service.
A good way to solve your problem this way is using the User Interaction Patterns.
In terms of the MVVM pattern, the view model is responsible for initiating an interaction with the user and for consuming and processing any response, while the view is responsible for actually managing the interaction with the user using whatever user experience is appropriate. Preserving the separation of concerns between the presentation logic implemented in the view model, and the user experience implemented by the view, helps to improve testability and flexibility.
There are two common approaches to implementing these kinds of user interactions in the MVVM pattern. One approach is to implement a service that can be used by the view model to initiate interaction with the user, thereby preserving its independence on the view's implementation. Another approach uses events raised by the view model to express the intent to interact with the user, along with components in the view that are bound to these events and that manage the visual aspects of the interaction.
This is a MVVM pattern for doing DialogServices etc. so it will fit your requirement, too.
I am building a WPF application and using the MVVM for the first time. Overall using MVVM has been very interesting and one of the major benefits is the nice separation between the view and the model classes. It kind of disciplines (at least young developers) to not to mix them together.
We have a scenario where a window needs to be closed on a button click after a confirm message box. Now this can achieved the old-way by handling the button click event and closing the window in the Window class itself. Or we can do it MVVM way by creating a command in ViewModel, call Window to show message box..etc.
I understand what needs to done here, but my question is - is it necessary to use MVVM commands in all cases? Are there exceptions where we should not use commands e.g. simple UI actions? Are we not overusing MVVM here? What exactly will the benefits doing everything the MVVM-way?
Or we can do it MVVM way by creating a command in ViewModel, call Window to show message box..etc.
Let me pick this apart, mainly because IMVHO I see this done wrong all the time - a lot of people try to do too much in the VM. First of all, ask yourself the question:
Is the prompt related to the data or business rules in any way whatsoever?
If it isn't, i.e. it is simply a "are you really sure?" type prompt, then this SHOULD be done purely within the code behind of the view. The only time the viewmodel needs to have any knowledge or take any action is when it actually has something to do with the viewmodel, in which case you should expose a command from the VM, but the actual window closing is still done from the code behind of the view.
The VM should know nothing about the view that it is bound to, that is one of the purposes of the MVVM pattern. It can expose commands, but it shouldn't know that a user has interacted with a specific UI element1, and it shouldn't directly know that the window is about to be closed. It is okay for the VM to prompt (via a dialog service, which you do have, yeah?) that the current data is unsaved, but it doesn't know about the window in general because it doesn't know how its data is presented.
Sometimes you will walk a fine line, and it is easy to over analyze whether something should be done purely from the view, purely from the VM, or as a mixture of both. If you remember the role of the VM, and remember that it is okay to have code behind in the view (provided it is only doing view related stuff and handing VM stuff off to the VM) then 99% of the time you won't have a problem.
1 For example, the VM shouldn't know or care whether the user just clicked a button, hyperlink, or touched a hot spot in an image. The same command can be used to handle any of this.
I have built out a couple of keyboards for a touch aware app we are building in work. Since we use a controller that is aware of when the app is in touch screen mode I thought it would be nice if, in design mode, we could associate a control with a keyboard type and have the controller look after the calling of the keyboard.
One of the things I do not want to do is to sub class each type of control just to add this property as I feel it is a very heavy for small gain. I had thought of using the tag property but it is not available in all controls due to use.
I was wondering if there is a way of attaching a property to a control on design time for the purpose of adding this meta data. So to recap I would like to be able to give each control a value that would be read by the controller to decide what keyboard to show.
Yes, the designer supports this. Good examples of existing components that do this are ErrorProvider and HelpProvider. Note how they add properties to existing control types.
You'll want to implement your own component, it needs to implement the IExtenderProvider interface. The MSDN Library article for it has a good example that should help you getting it right.
I'm doing a WPF application, using Blend4 and VS2010 for editing the XAML files.
One of the most anoying things of this is the process of making small changes and see them in action. As the data in the View is populated from a ViewModel and a Model via Bindings, the things you see in the Blend designer aren't the same you get when you run your application. You need to recompile and "re-run" your application every time you make a change, no matter if it was only to change a pixel in the margin of some element.
I want to know if there is any way to perform quick changes in your XAML and watch them in the real interface.
Like in the Websites, the idea is similar to make a change in the HTML and then press F5 to see the changes.
Maybe you can run "part" of your application to bind the view data to the model, and then change only the "view code" of the xaml.
Do you know if this is possible?
Thanks!
Whether using Blend or Visual Studio, the key to rapid design of MVVM user interfaces is sample data. You can use the same view model at design-time as you you do at run time as long as the data is doesn't access services.
Whether you are using MVVM Light or not, you can use its technique to allow your view-model to detect design time and return different data. You can also read Laurent Bugnion's ideas on sample data here:
WPF: Simulating data in design mode in Microsoft Expression Blend
I have a service that returns an observable collection of persons that will be used to display the person name in a list box in my Silverlight application.
While designing the list box, the designer used sample data. However, when the xaml reaches the developer working on the view model and the service that returns an observable collection of persons to be displayed, there are some changes that need to be done.. like remove all bindings to the sample data, plug in the observable collection persons properties.
So my questions are:-
Is there a way to do this in a way where in design mode it shows the sample data and when it runs it shows the service data?
Is there a way for it to return service data while in design mode itself?
Does the designer using Expression Blend need to know what properties of the observable collection {persons} will be bound to the list box?
I would want to do this in an MVVM friendly manner {without using MVVM Light toolkit}.
Thanks for your time...
Loads of good examples out there:
http://blogs.msdn.com/b/avip/archive/2010/12/06/the-simplest-way-to-do-design-time-viewmodels-with-mvvm-and-blend.aspx
http://karlshifflett.wordpress.com/2009/10/28/ddesigninstance-ddesigndata-in-visual-studio-2010-beta2/
It's very simple. Lots of other resources on google if you need them
Edit based on comment
2. Is there a way for it to return service data while in design mode itself?
Possibly but I've not seen it. In my mind you probably wouldn't want to do this for many reasons.
You may get a delay before your data
shows up which could get quite
frustrating if you need to make a lot
of small changes.
You have a reliance on services being
available which is going to make you
even more unproductive if they ever
go down.
You or a designer doesn't have any
control over changing what is
displayed on an ad-hoc basis. At
least using the sample data system
you can change values to test
different scenarios without having to
get services data changed.
3. Does the designer using Expression Blend need to know what properties of the observable collection {persons} will be bound to the list box?
The designer/developer workflow is a tricky one. Obviously each project will be different, but having just finished a design heavy wpf project I can tell you that our designers want as little to do with Blend as possible.
The workflow that has worked for us, is for the developers (we have a front end team that work at the view/viewmodel level and backend team that build up the model and service layer) to build up the views as best they can. That means building the layout, composing the controls, adding most of the design and hooking up the bindings. We then had a designer who had experience in using Blend (there aren't many) delve in and tweak the designs to get them exactly as they wanted.
This way they had very little to do with the main brunt of the work and we could keep clean and organised views (something few designers would have the experience to do). The designers didn't really have to know anything about domain objects. It all worked very well once we'd worked out how it was going to work. Having the designers build up the views themselves would have been a nightmare in my opinion... and not something they'd have enjoyed either.