How to manage cascading GUI changes in winforms? - c#

In the application I'm working on, there are a lot of dependencies between GUI fields. For example, when the user changes the value in a textbox, other controls on the form need to change based on the new value, which in turn may or may not trigger other changes on the form. These relationships can get arbitrarily complicated, and user requirements change frequently.
I know there are patterns such as MVC to separate out business logic into a controller, but I think the problem I'm trying to solve is different, because it is the logic itself that gets complicated. It seems the relationships can be modeled as a directed graph with each GUI control being a node. I was wondering if this was the right way to approach it and if there are any frameworks out there before I try rolling my own.

We use an 'Appearance Model' to have the controller update the state of that model, and the view updates itself based on the appearance model only.
MyAppModel.MyControl.Readonly = true;
that would be bound to a controls readonly property on the view.
so now based on some event I can flick these states on /off to change the view.

Related

WPF Data Binding - Handling User Cancelation

So I have an app that makes heavy use of data binding. One feature in the app is a pop-up window that lets users manage some records. They select a record from a ListBox, and then they use a form to edit the properties of that record's object instance.
Users are typically accustomed to having the option to either Save or Cancel at the end of the form. Save commits the changes, and Cancel abandons the changes.
However, with the two-way data binding, the object is being updated in real-time as the field value changes.
Is there a "best practices" way of approaching the Commit/Cancel behavior with data binding within WPF? I've thought about cloning the object being edited so that the changes occur on that clone, and then the Save applies the changes to the original record, but I feel like this is something that Microsoft probably has built in already and I'm just unaware of how to use it properly.
WPF provide BindingGroup to deals with the situation you have run into. BindingGroup allow you to handle multiple value change at the same time. You can commit or cancel changes base on the result of validating all the changes at the same time but not just each one separately. And for edit transaction to work, the source(s) in BindingGroup should implement IEditableObject interface.

MVVM architecture: one model - several view models + place for data access

I'm quite confused about the architecture of my MVVM application (formerly WinRT, now targeting UWP) concerning data access. I'm quite unsure how to propagate changes across the UI and where to put access to the data layer.
Here's the basic architecture:
Model layer: contains models that only have auto properties (no navigation properties that reference other models, just Ids; so they are basically just representations of the database). They don't implement INotifyPropertyChanged.
Data acccess layer: A repository that uses sqlite-net to store models in a database. It exposes the basic CRUD operations. It returns and accepts model from the model layer.
ViewModels:
ViewModels for the Models: They wrap around the models and expose properties. Sometimes I two-way bind content of controls (e.g. TextBoxes) to properties. The setters then access the data layer to persist this change.
PageViewModels for Views: They contain ViewModels from above and Commands. Many Commands have become very long as they do the data access, perform domain specific logic and update the PageViewModels properties.
Views (Pages): They bind to the PageViewModels and through DataTemplate to the ViewModels for the models. Sometimes there is two-way databinding, sometimes I use Commands.
I now have several problems with this architecture:
Problem 1: One model can be represented on the screen at several palaces. For example, a master-detail view that displays a list of all available entities of a type. The user can select one of them and its content is displayed in the detail view. If the user now changes a property (e.g. the model's name) in the detail view, the change should be immediatelly reflected in the master list. What is the best way of doing this?
Have one ViewModel for the model? I don't think this makes much sense, as the master list needs only very little logic, and the detail view much more.
Let the model implement INotifyPropertyChanged and thus propagate the change to the ViewModels? The problem I have with this, is that the data layer currently doesn't guarantee that the objects it returns for two read operations on one model id are identical - they just contain the data read from the database and are newly created when they are read (I think that's the way sqlite-net works). I'm also not really sure how to avoid memory leaks happening because of all the PropertyChanged event subscriptions from the ViewModels. Should I implement IDisposable and let the PageViewModel call its children's Dispose() method?
I currently have a DataChanged event on my data access layer. It is called whenever a create, update or delete operation occurs. Each ViewModel that can be displayed simultaneously listens to this event, checks whether the changed model is the one its the ViewModel for and then updates its own properties. Again I have the problem of the memory leak and this becomes slow, as too many ViewModels have to check whether the change is really for them.
Another way?
Problem 2: I'm also not sure whether the place I access data is really well chosen. The PageViewModels have become extremely convoluted and basically do everything. And all ViewModels require knowledge of the data layer with my architecture.
I've been thinking of scrapping data access with sqlite-net and using Entity Framework 7 instead. Would this solve the problems above, i.e. does it guarantee object identity for one model when I use the same context? I also think it would simplify the ViewModels as I rarely need read operations, as this is done through navigation properties.
I've also been wondering whether having two way databinding is good idea at all in a MVVM application, as it requires the property setter to call the data access layer to persist the changes. Is it better to do only one-way binding and persist all changes through commands?
I'd be really happy if someone could comment on my architecture and suggest improvements or point to good articles on MVVM architecture that focus on my problems.
Have one ViewModel for the model? I don't think this makes much sense, as the master list needs only very little logic, and the detail view much more.
ViewModel is not dependent on the model. ViewModel uses the model to address the needs of the view. ViewModel is the single point of contact for the view so whatever the view needs the viewmodel has to provide. So it can be a single model/multiple models. But you can break down a single ViewModels into multiple sub ViewModels to make the logic easier. Its like detail pane can be separated into a user control with its own view model. Your master page will just have the window that will host this control and the MasterViewmodel will push the responsibilities to the sub ViewModel.
Let the model implement INotifyPropertyChanged and thus propagate the change to the ViewModels? The problem I have with this, is that
the data layer currently doesn't guarantee that the objects it returns
for two read operations on one model id are identical - they just
contain the data read from the database and are newly created when
they are read (I think that's the way sqlite-net works). I'm also not
really sure how to avoid memory leaks happening because of all the
PropertyChanged event subscriptions from the ViewModels. Should I
implement IDisposable and let the PageViewModel call its children's
Dispose() method?
The danger is not using INotifyPropertyChanged, but as your rightly said its with the subcribing and unsubscribing. Wherever there is a need to subscribe to any event - not only INotifyPropertyChanged you need to use IDisposable to unsubscribe itself and its child ViewModels. I am not clear on the datalayer you describe, but if it publishes the property changed event for any modification I dont see any problem using INotifyPropertyChanged.
3.I currently have a DataChanged event on my data access layer. It is called whenever a create, update or delete operation occurs. Each
ViewModel that can be displayed simultaneously listens to this event,
checks whether the changed model is the one its the ViewModel for and
then updates its own properties. Again I have the problem of the
memory leak and this becomes slow, as too many ViewModels have to
check whether the change is really for them.
As I said earlier, if you handle the subscribe/unsubscribe properly for all models you need not worry about performance issue of INotifyPropertyChanged. But what might be adding to the problem is the number of calls you make to the database for requesting data. Have you considered using Async...Await for the data access layer which will not block the UI for any update thats happening. Even if the data update is slow a reactive UI which doesnt get blocked by the data calls is a better option.
So try adding a data access service which is abstracted over the DAL layer and provide a asynchronous approach to accessing the data. Also have a look at the Mediator Pattern. That might prove helpful.
I'm also not sure whether the place I access data is really well
chosen. The PageViewModels have become extremely convoluted and
basically do everything. And all ViewModels require knowledge of the
data layer with my architecture.
2 main problems i see,
If you feel the PageViewModel is too huge break down into sub view models of manageable size. Its very subjective, so you have to try to see what all parts can be broken down to its own component/usercontrol with its own viewmodel.
When you say ViewModels require knowledge of data layer, I hope you mean they are dependent on a Interface that manages the DAL layer services and doesn't have direct access to class with CRUD methods. If not try to add an abstract layer which does you actually do in your view model. And that will handle the DAL CRUD operations.
I've been thinking of scrapping data access with sqlite-net and using
Entity Framework 7 instead.
Don't try to replace sqlite-net with EF without hard evidence. You need to measure performance in your app before trying to jump into such big changes. What if the problem lies in your code rather than the component you are using. First try to fix the above mentioned issues then you can segregate the DAL layer via interfaces and replace it if needed.
I've also been wondering whether having two way databinding is good
idea at all in a MVVM application, as it requires the property setter
to call the data access layer to persist the changes. Is it better to
do only one-way binding and persist all changes through commands?
If you are making a call to database directly everytime you make a change to the field/ for every key stroke then its a problem. Then you should have a Copy of the Data Model and persist the changes only when you click the save button.

Creating a wizard in wpf

I'm currently creating a "wizard" to create new projects inside my program. I have a solution that is almost done but it doesn't feel "right" and start to think about other solutions. Maybe should note that I also use MVVMLight.
My current solution:
I have a window and the window contains custom user controls (they represent every page of the wizard).
Both the window and the user controls share the same view model
When you click back/next the view model handles which user control that should be visible
The problem with this one is that I don't like the shared view model. I have a shared view model because all pages configure different things on the same object and it's easier to follow. But at the same time thew view model contains a lot of things that each individuell user control doesn't need (for example only one page need methods to add/edit filters). It also makes it hard to re-user the user control later if I want them for something else than the wizard.
So should I instead create diffrent view models for the window and each user control and send messages between the view models with MVVMLights MessengerInstance? I feel that's cleaner but as a reader it's maybe harder to follow (something I feel in general when I sending messages around)?
With messenger it would be a workflow like this:
User enter all the information on a "page"
User click on next (that belongs to the window)
The windows view model have to send a message to the user control to check if all the data is valid
The user control check the data and have to send back if it's valid or not. If it's valid tell the next page to get visible, if not show error message.
So it would be a lot of messages back and forth that I don't need with the shared view model solution.
Or is there a better solution that I should do?
I would expect that the answers you receive here are primarily opinion based, but here goes anyway.
Currently, your view model has more than one responsibility, and therefore, more than one reason to change. It's certainly a good idea to split up your view models into smaller, more manageable classes. This may appear to reduce readability, however I would disagree. The idea of ensuring that classes only have one responsibility keeps things simple and promotes re-use.
That being said, your main view model will most likely hold references to many other child view models, but this isn't the end of the world, in fact, it's a good thing. The parent-child relationship between your view models is much like the parent-child relationship in your views. For example, a Window contains many UserControls, there's nothing wrong with mimicking this relationship with the view models.
Now, there are of course a few ways to communicate between view models. I personally prefer to use events, where a child view model raises an event that the parent view model subscribes to. Pretty simple, really. Although there is some degree of coupling in this scenario, you could of course abstract your classes away into interfaces and use dependency injection to inject them into the parent view model. Using events is down to personal preference, however MVVMLight has quite a nice MessengerInstance that decouples view models even further.
So. My suggestion:
Work out the responsibilities of your view model.
Split up the massive view model into smaller view models (based on the responsibilities).
Create a parent-child relationships between view models. Your view will in fact point you in the right direction in terms of the relationships.

How many views, viewmodels and models do I need?

I'm trying to develop a WPF application - actually it's more a tool - using the MVVM pattern. I've read several articles, watched videos, posted questions but somehow I feel that my approach to or understanding of this MVVM thing is not "the right one".
I'll start from the UI. In a first stage the UI shall display the following:
Group box with
text box for the username
text box for the password (let's ignore the PasswordBox for the start)
Group box with
combo box for a list of project names available for this user (will be retrieved from a webservice)
button "Login" for logging in to the selected project
button "Logout" for logging out from the current project
So I would identify the following data that need to be handled:
A string for the username
A string for the password
An ObservableCollection<Project> for the list of projects
A Project object representing the active project
A boolean if logged in to a project or not
My worries, I have no idea how I should structure or design this following MVVM. How many views, viewmodels and models should I use here? Of course, the application will grow but not this much. Let's stick to the above.
There is no right or wrong answer to this
Think of Views, ViewModels, and Models as cut off points. They allow you to modularize your application versus taking a non-reusable monolithic approach.
In general, ViewModels to Views is 1:M however reality is that most of the time they are 1:1 relationship. The ViewModel and View are where the bulk of work resides, with the Model acting as nothing more than a POCO which implements INotifyPropertyChanged for binding needs.
In your example I would use a single View backed by a single ViewModel and multiple Models as is needed (Project, UserCredentials, etc...). You may have services which perform the actual login effort however you can perform that work in the ViewModel.

How do I handle events from controls inside a User Control derived from a Tab Page meant to be added dynamically to a Tab Control at run time?

I created a User Control derived of a Tab Page with certain controls such as ListView, Buttons, and Textboxes in it, to add Tab Pages to a Tab Control dynamically during run time.
How do I handle the events from such controls within each User Page (multiple instances of these user control tabs) in my main form where my Tab Control is going to be located? Initially I want to be able to communicate the data in some of these controls inside each User Page back to the main form.
This isn't just in regards to tab pages, although we use a tab page derived in a similar fashion. Sending events willy-nilly through the UI causes me much confusion (keeping the order in which the various events trigger and so on). Instead, I create a controller class which is passed to the various UI components and those components notify the controller with changes and the UI elements subscribe to events on the controller to receive information about the environment.
To make this concrete, each of the derived Tab Pages is passed a reference to the controller. They may change the state of the controller based on user actions. Say the current record is changed, the UI calls a method on the controller telling it the new record.
The other UI elements on the page are notified of this change because they subscribe to the controller's OnCurrentRecordChange event.
While this introduces another class into the mix, the advantage is that you have a single controller orchestrating the changes to the UI, rather than a bunch of events percolating and passing information around. I find that is also breaks dependencies on UI elements collaborating: I can add, remove or change UI elements and as long as they all speak to the controller for updates there is far less code rework.
If you have ever found yourself debugging UI "loops" (where changes in one control are triggering changes in other controls which trigger yet more changes which eventually affect the original component) then the extra work of a controller class will pay off immediately.
Update: Answering your comment... A first stop would be to read up on the Model View Controller architecture: http://en.wikipedia.org/wiki/Model%E2%80%93View%E2%80%93Controller
For a concrete example: http://www.dotnetheaven.com/Uploadfile/rmcochran/MVC_intro02012006001723AM/MVC_intro.aspx
When working with Windows Forms many people get stuck in a two tier design: UI + Data Layer. The binding system makes this very natural as there is an easy way to get at data (Entity Framework, LINQ) and an easy way to wire data to the UI (the designers). Adding a controller between them isn't as hard as it may seem though.
In my work I use LLBLGen (http://www.llblgen.com/defaultgeneric.aspx) for my low level data layer, but you could substitute LINQ or Entity Framework or any other data access tool and the general overview would be the same.
Above this layer I build my business objects. Many of them are nothing more than facades for the LLBLGen objects (if my business rules don't say much about the entity), while others have a lot of validation built in and they aggregate several low level objects into more usable business objects. Finally there are the business objects that don't directly have entities behind them (communications objects between systems, for example).
The controller object I mention lives alongside my business objects in that it knows about these objects and it even hands them out to the UI for data binding purposes. When the UI wants a change make, it notifies the controller and it uses the business objects to ensure the updates are permitted and if so passes the changes back down the the data layer.
In the diagram on Wikipedia, the View is my UI. The Controller is my coordination object which is mediating changes in both directions while the Model is my business object layer (which has a low level below this, but that is an implementation detail that is hidden from the higher layers).
Although going from "View <-> Model" (classic data binding) to "View <-> Controller <-> Model" seems to be adding complexity, the major benefit is that the controller becomes the one stop shopping location for "truth" about the application. The UI requests data from the controller, so the controller knows about all the UI elements that have a given data binding. If things change, an event notifies all the UI elements and they change visually for the user. The nice thing is that there is one "truth" about system state, and that is the truth the controller is managing for the UI.
When data needs to be persisted, the request goes to the controller to update the model. Again, we have a single place for the coordination of the save and subsequent updates. All of the data validation integrity rules are in the business logic layer (the Model) so the controller's code is kept light.
By separating your UI concerns, your coordination concerns and your business logic concerns
you end up with each having very "lightweight" methods and properties. More importantly, each subsystem can take a very simplistic view of the application as they focus on that piece of the puzzle instead of threading events, UI updates and data updates in one monolithic piece of code.
For further reading I would recommend any of the articles or books about ASP.NET MVC. While this is not Winforms, the basic ideas underlying the MVC can be applied to winforms. There are some good comments here as well: https://stackoverflow.com/questions/2406/looking-for-a-mvc-sample-for-winforms
I should be clear that what I am doing with my projects is probably not considered "pure" MVC, but simply a separation of concerns along the natural fault-lines found in the applications we develop. We don't use a "framework" for this (although some code generation is involved).

Categories

Resources