Reuse or create new View/ViewModel for MDI tool windows - wpf

In a MVVM MDI app with singleton tool windows (think of Visual Studio), the tool window contents change according to current selected document. There are 5 tool windows now and more to come.
I can either reuse or create new View and/or ViewModel for each tool window per each document. My question is whether there is an overwhelming reason to choose or exclude one of these options? Is there another option I totally missed?
For each tool window:
Create a new View+ViewModel per document. When the user switches document, the tool window switches View+ViewModel. The memory cost is higher with this option but perf is good.
Create a ViewModel per document but reuse View. With MVVM pattern this is doable but UI re-layout can be expensive.
Reuse both View and ViewModel to minimize memory usage. Resetting ViewModel and loading another set of data could be hard to get right.

Always go for 1, this provides better performance like you said and creates a nice separation of concern for you as develop. Since the view models stay open, you can do much more with them (such as showing a list of open documents, etc).

I ended up reusing View but not ViewModel i.e. option 2.
To answer the original question, option 3 should be excluded from consideration. Reusing VM is pointless - if the previous VM can be reused, it can as well be disposed and creating a new VM for the new data is much easier to do at a very ignorable mem/perf cost.
Option 1 vs. 2 depends on rendering complexity, performance goal and memory quota. In most cases the performance hit of switching data on the same UI should be acceptable. If the rendering really take as long as I need to save the view, there might be something wrong.

Related

What is the real purpose of ViewModel in MVVM?

I had a talk with teamlead about this topic and from his point of view we can just use bindings and commandings omitting ViewModel, because we can test UI behaviour without VM using Automation or our own developed mechanisms of UI testing (based on automated clicks on Views). So, if there are no real benefits, why should I spawn "redundant" entities? Besides, automated integration tests look much more indicative than VM tests. So, it seems that we can mix VMs and Models.
update:
I agree that mixing VMs and Models brings into single .cs a data model and rules of data transformation for representing it in a View. But if this is only one benefit - I don't want to create a VM for each View.
So what pros of VM do you know?
The VM is the logic behind your UI. combining the UI code with the logic ends up in a mess, at least from my experience. Your view should define what you see - buttons, menus etc. Your VM is in charge of the binding and handling events caused by the user.
Edit:
Not wanting to create a VM for each view doesn't sound like a SW-oriented reason. Doing so will leave your view clean of logic and your model free to be the connecting layer between the core layer and your app layer.
I like the following example referring to the model and its role (why it shouldn't be combined with the VM): imagine you're developing some Android app using Google maps. Google maps are your core. Then one fine day you really need the option to, say, color parts of the map in pink, bright pink. An email to Google asking for colorPink(Map)will probably get you nowhere. That's where your model steps in and provides you the map wrapper that you need to define your pinky method.
Without a separate model, you'd have to go through every VM that uses map and update it.
So, the view has a role, the model has a role, the VM is the logic between those.
Edit 2:
There are some cases where there's no need of a model layer - I tended to disagree at first but was convinced after a discussion: In relatively small applications, the model can end up being a redundant wrapper with no added functionality over the core. In such cases, you can use the core objects directly.
What is he binding to? Whatever he is binding to is effectively a view model, whether you call it that or not. If it also doubles as a data model, then you're violating the Single Responsibility Principal (SRP). Essentially, the problem here is that you're lumping together code that is servicing different parts of the application architecture, which will lead to a convoluted mess.
UI Testing is a pain not just because you need to accomodate for changes in the View which can occur many times but also because UI tends to interfere with its own testing. Depending on the tests needed you'll need to keep track of focus, resize and possibly other (mouse) events which can be extremely hard to make it a representative test.
It is much easier to scope the test to the logic in the ViewModel and leave the UI testing to humans. The human testers do not need to test the logic; their only consern should be the UI.
By breaking down a ViewModel into a hierarchy of ViewModels you might be able to reuse a ViewModel multiple times. There is no rule that states that you should have a ViewModel for each View. (After a release or two I end up there but that's besides the point :) )
It depends on the nature of your Model - sometimes they are simple and can serve as both like you are suggesting. However, depending on the framework, you'll need to dirty up your model with some PropertyChanged event code which can get messy and distracting. In more complex cases, they serve as a mediator between your the view and the model. Let's suppose you're creating a client app that monitors a remote process or database entries - creating View Model's for these entities let's you surface your data in a way that is convenient to bind to for a UI framework (but is silly in a DB framework), encapsulate operations as commands, perform validation, etc etc.

Switching views in WPF, high level design question

So I am currently working on a UI written in WPF. One thing I really like about WPF is the way it leads you to write more decoupled, isolated UI components. One pain point for me in WPF is that it leads you to write more decoupled, isolated UI components that sometimes need to communicate with one another :). This is probably due to my relative lack of UI experience, especially in WPF (I'm not a novice, but most of my work is far more low level than UI design).
Anyway, here is the situation:
At any one time, the central area of the UI displays one of three views implemented as UserControls, let's call them Views A, B, and C.
The user will be switching between these views at various times, and there is more than one way to switch views (this works well for the customer, causes some pain in code design currently).
Right now each view switching mechanism does its own thing to transition to another view. A certain singleton class takes care of storing data and communicating between the views. I don't like this, it's messy, error prone, and the singleton class knows way too much about the details of the UI. I want to eliminate it as much as is possible.
I ran into a bug today that had to do with the timing of switching between views. To make it simple, one view needs to perform some cleanup when it is unloaded, but that cleanup erases some data that is needed for another view. If the cleanup runs after the other view is loaded, problems ensure. See what I mean? Messy.
I am trying to take a step back and imagine a different way to get these views loaded with the data they need to do their job. Some of you more experience UI / WPF people out there must have come across a similar issue. I have a couple of ideas, but I am hoping someone will present a cleaner approach to me here. I don't like depending upon order of operations (at a high level) for my code to work properly. Thanks in advance for any help you may be able to offer.
I would recommend some kind of parent ViewModel that handles the CurrentView. I wrote an example here a while back if you're interested.
Basically the parent view will have a List<ViewModelBase> AvailablePages, a ViewModelBase CurrentPage, and an ICommand ChangePageCommand
How you choose to display these is up to you. My preferred method is a ContentControl with it's Content bound to the CurrentPage, and using DataTemplates to determine which View should be displayed based on the ViewModel stored in CurrentPage
Rachel's post sums up my basic approach to this, quite well. However, I would like to add a few things based on your comments which you may want to consider here.
Note that this is all assuming a ViewModel-first approach, as mentioned in comments.
The user will be switching between these views at various times, and there is more than one way to switch views (this works well for the customer, causes some pain in code design currently).
This shouldn't cause pain in the design. The key here is to have a single, consistent way to request a "current ViewModel" change, and the View will follow suit automatically. The actual mechanism used in the View can be anything - changing the VM should be consistent.
Done correctly, there should be little pain in the design, and a lot of flexibility in terms of how the View actually operates.
Right now each view switching mechanism does its own thing to transition to another view. A certain singleton class takes care of storing data and communicating between the views. I don't like this, it's messy, error prone, and the singleton class knows way too much about the details of the UI. I want to eliminate it as much as is possible.
This is where a coordinating ViewModel can really ease things. It does not require a singleton, as it effectively "owns" the individual ViewModels of the views. One option here, that's fairly simple, is to implement an interface on the ViewModels that includes an event - the ViewModel can raise the event (which I would name based more on what the intent is, not based on the "view change"). The coordinating VM would subscribe to each child VM, and based on the event, change it's "CurrentItem" property (for the active VM) based on the appropriate content to make the request. There are no UI details at all required.
I ran into a bug today that had to do with the timing of switching between views. To make it simple, one view needs to perform some cleanup when it is unloaded, but that cleanup erases some data that is needed for another view. If the cleanup runs after the other view is loaded, problems ensure. See what I mean? Messy.
This is screaming out for a refactoring. A ViewModel should never clean up data it doesn't own. If this is occurring, it means that a VM is cleaning up data that really should be managed separately. Again, a coordinating VM could be one way to handle this, though it's very difficult without more information.
I don't like depending upon order of operations (at a high level) for my code to work properly.
This is the right way to think here. There should be no dependencies on order within your code if it can be avoided, as it will make life much simpler over time.
I am trying to take a step back and imagine a different way to get these views loaded with the data they need to do their job.
The approach Rachel and I are espousing here is effectively the same approach I used in my series on MVVM to implement the master-detail View. The nice thing here is that the "detail" portion of the View does not always have to be the same type of ViewModel or View - if you use a ContentPresenter bound to a property that's just an Object (or an interface that the VMs share), you can easily switch out the Views with completely different Views merely by changing the property value at runtime.
My suggestion for this is to have one main view model that coordinates everything (not static / singleton) that you then use sub view models to transfer data around. This keeps the decoupling you are looking for, provides testability, and allows you to control when the data for each object is changed.

Global Entity Framework Context in WPF Application

I am in the middle of development of a WPF application that is using Entity Framework (.NET 3.5). It accesses the entities in several places throughout. I am worried about consistency throughout the application in regard to the entities. Should I be instancing separate contexts in my different views, or should I (and is a a good way to do this) instance a single context that can be accessed globally?
For instance, my entity model has three sections, Shipments (with child packages and further child contents), Companies/Contacts (with child addresses and telephones), and disk specs. The Shipments and EditShipment views access the DiskSpecs, and the OptionsView manages the DiskSpecs (Create, Edit, Delete). If I edit a DiskSpec, I have to have something in the ShipmentsView to retrieve the latest specs if I have separate contexts right?
If it is safe to have one overall context from which the rest of the app retrieves it's objects, then I imagine that is the way to go. If so, where would that instance be put? I am using VB.NET, but I can translate from C# pretty good. Any help would be appreciated.
I just don't want one of those applications where the user has to hit reload a dozen times in different parts of the app to get the new data.
Update:
OK so I have changed my app as follows:
All contexts are created in Using Blocks to dispose of them after they are no longer needed.
When loaded, all entities are detatched from context before it is disposed.
A new property in the MainViewModel (ContextUpdated) raises an event that all of the other ViewModels subscribe to which runs that ViewModels RefreshEntities method.
After implementing this, I started getting errors saying that an entity can only be referenced by one ChangeTracker at a time. Since I could not figure out which context was still referencing the entity (shouldn't be any context right?) I cast the object as IEntityWithChangeTracker, and set SetChangeTracker to nothing (Null).
This has let to the current problem:
When I Null the changeTracker on the Entity, and then attach it to a context, it loses it's changed state and does not get updated to the database. However if I do not null the change tracker, I can't attach. I have my own change tracking code, so that is not a problem.
My new question is, how are you supposed to do this. A good example Entity query and entity save code snipped would go a long way, cause I am beating my head in trying to get what I once thought was a simple transaction to work.
A global static context is rarely the right answer. Consider what happens if the database is reset during the execution of this application - your SQL connection is gone and all subsequent requests using the static context will fail.
Recommend you find a way to have a much shorter lifetime for your entity context - open it, do some work, dispose of it, ...
As far as putting your different objects in the same EDMX, that's almost certainly the right answer if they have any relationships between objects you'll want them in the same EDMX.
As for reloading - the user should never have to do this. Behind the scenes you can open a new context, reloading the current version of the object from the database, applying the changes they made in the UI annd then saving it back.
You might want to look at detached entities also, and beware of optimistic concurrency exceptions when you try to save changes and someone else has changed the same object in the database.
Good question, Cory. Thumb up from me.
Entity Framework gives you a free choice - you can either instanciate multiple contexts or have just one, static. It will work well in both cases and yes, both solutions are safe. The only valuable advice I can give you is: experiment with both, measure performance, delays etc and choose best one for you. It's fun, believe me :)
If this is going to be a really massive application with tons of concurrent connections I would advise using one static context or one static, core context and just few additional ones just to support the main one. But, as I wrote just few lines above - it's up to your requirements which solution is better for you.
I especially liked this part of your question:
I just don't want one of those
applications where the user has to hit
reload a dozen times in different
parts of the app to get the new data.
WPF is a really, really powerful tool and basically times when users have to press buttons to refresh data are gone forever. WPF gives you a really wide range of asynchronous, multithreading tools such as Dispatcher class or Background worker to gently refresh desired data in the background. This is really great, because not only you don't have to worry about pressing various buttons, but also background threads don't block UI, so data is refreshed transparently from user's point of view.
WPF together with Entity Framework are really worth the effort of learning - please feel free to ask if you have any further concerns.

WPF and LINQ/SQL - how and where to keep track of changes?

I have a WPF application built using the MVVM pattern:
My Models come from LINQ to SQL.
I use the Repository Pattern to abstract away the DataContext.
My ViewModels have a reference to a Model.
Setting a property on the ViewModel causes that value to be written through to the Model.
As you can see, my data is stored in my Model, and changes are therefore tracked by my DataContext.
However, in this question I read:
The guidelines from the MSDN
documentation on the DataContext class
are what I would recommend following:
In general, a DataContext instance is
designed to last for one "unit of
work" however your application defines
that term. A DataContext is
lightweight and is not expensive to
create. A typical LINQ to SQL
application creates DataContext
instances at method scope or as a
member of short-lived classes that
represent a logical set of related
database operations.
How do you track your changes? In your DataContext? In your ViewModel? Elsewhere?
When I write this kind of software, my VMs never have a reference in any way to the data model. When you couple them like this, you are pretty much married to a simple two-tier solution which can be really tough to break out.
If you disconnect the DataContext entirely from your VM and have them live on their own, your application becomes:
Much more testable -- your VMs can be tested without the datacontext
Potentially stateless at the data layer -- it's easy to change your architecture to adopt a stateless 3-tier based solution.
Able to easily integrate other data sources -- your VMs can elegantly contain aggregates and combinations of other data sources on their own.
So in short, yes, I would recommend decoupling the data access classes from the ViewModel objects throughout the app. It might be a bit more code, but it will pay dividends down the road with the architecture's flexibility.
EDIT: I don't use the change tracking features of the L2SQL objects once they've crossed a distribution boundary. That turns into a can of worms pretty quickly -- you can spend a lot of time with the care and feeding of your data model's object graph inside your viewmodel - which adds not only complexity to the ViewModel, but at least transitively couples the ViewModel to the schema of the database. Instead of doing that, I make the ViewModel pure. When the time comes for them to be persisted, your service layer/repository/whatever does the translation between the ViewModel and the data objects. This at first seems like a lot of work, but for anything other than simple CRUD, this design pays off pretty quickly.
However you manage data inside a program, instances of objects of L2SQL generated classes are created like regular objects, without any using of a data context. DataContext is only responsible for interacting with a database.
Those guidelines may mean that you can do anything with objects of L2SQL generated classes, but don’t keep an object that transfers data between them and a database. You can treat L2SQL classes like any other classes, which you can use as you want, with an additional capability of being read from and written to a database.
This is a guess. I cannot say what was in the head of the MSDN author of that magic phrase, but this explanation makes sense. Store data in L2SQL generated classes objects during the whole program’s activity and synchronize it with database by temporary DataContext objects.

How to speed up .NET winforms rendering

I have a series of forms and navigate between them.
Each form has a set of controls for which I load properties from SQLite database and this is the long (about 1s) operation that doesn't give users the best feeling because the form is gradually being drawn.
I don't quite mind the delay but I'd like the form to be drawn when all data is loaded. I'd like to avoid new threads because this would result in cross-thread operation issues.
Is there any good solution apart from speeding the whole application up by caching the loaded data?
There is a simple way to speed up perceived performance of many controls, especially data intensive ones like listviews, listboxes, combo boxes etc.
Before you populate them call the BeginUpdate() method and when done call the EndUpdate(). This disables the redrawing of the control until you're done populating it with data.
Sorry. This is what threading is for. "Cross-thread operation issues" are well defined and there are common patterns for dealing with them. Just reduce the places where threads interact to a minimum (in this case, it would be a single place--after data is loaded) and it becomes trivial.
There are also some classes which make multithreading in a winforms app much easier, as they abstract away the interaction between threads. The BackgroundWorker (link to blog post about it) will perform work on another thread for you, and notifies you when its done by firing an event on the UI thread. You get the benefits of multithreading without any of the pitfalls.
I've found that loading Winform controls, like combo boxes and listboxes, load a lot faster when they are pointing to Views instead of a table itself, especially if you can limit the view to be leaner compared to the control having to look through an entire table.
Back in VB days I used LockWindowUpdate API. Since this takes a window handle, it should be usable also with WinForms. Though, never tried.
this link has some nice solution, as far as i think BackgroundWorker process should help.
http://devcomponents.com/blog/?p=361

Resources