In our WPF application, we have a lot of forms with fixed fields. Every form should now be extended with fields the user can define himself. The database contains a table with these user defined fields, each with a label, a type (text, date, numeric, ...), etc.
I have found a lot of great solutions using DataTemplates, there is one issue with this however: it is not possible to generate a unique x:Name property for each field (using the field id for example).
Our application relies heavily on the x:Name property to do things as: show/hide fields, set a mask on numeric fields, move fields, ... All this functionality is read from the database, so a unique identifier per field is needed.
One solution would be to generate these fields with the x:Name in the codebehind (the Winforms way).
Another solution would be to change the functionality that uses the x:Name to using the Tag property.
Before I implement one of these solutions, I want to make sure there is no better way. Is there an MVVM way to dynamically generate fields with an x:Name?
Edit
There seems to be some confusion as to why I would need an x:Name for my fields in an MVVM scenario, so I'll clear it up with an example:
One requirement of our software is that every form field in our application can be set hidden or visible by the user. I'm talking about thousands of fields here. I could have created an property for every field that contains the visibility status and fill it from the database.
Instead, I have created an attached property (attached once in a style) that retrieves the visibility status based on the name of the field and apply it. So this functionality runs separately from the MVVM architecture (I never use the x:Name in the ViewModel). The disadvantage of using the attached property is that the form fields need an identification, being the x:Name property in my case.
Is there an MVVM way to dynamically generate fields with an x:Name
No, there isn't.
x:Name is a XAML directive that is used to uniquely identify a UI element in a XAML namescope and generate a backing field to store the value in the code-behind class of the view.
The view model doesn't and shouldn't know anything about this and it should certainly not generate such elements or backing fields as this would break everything that the MVVM pattern is all about.
If you do require to generate unique names for your UI elements for some reason, you should implement this functionality in the code-behind of the view.
MVVM is not about eliminating view-related code from the views, it is mainly about separation of concerns and testability.
Related
I have multiple of views (user controls), each with its own ViewModel. To navigate between them I am using buttons. Buttons display image and text from corresponding view model and also need column and row (because there are like 10 views: 10 columns with different number of rows each).
Right now buttons are created dynamically (I made a Navigator control for this) and for view models I have base class to hold text, image, column and row. Number of views available will be different (depends on user level and certain settings), that's why it's I need control here.
Question: how shall my control get data from view models?
Right now I have interface INavigator, defined in (lol) control itself. And view models implement it. I could go opposite, let my control to know about view models. Both looks wrong.
There is a single Navigator control what has, lets say, Items bound to a list of view models. It can cast each view model to INavigator or ViewModelBase (common for all pages) to obtain specific view model image, text, column and row. So either view model knows about control (to implement INavigator) or control knows about ViewModelBase.. And this is a problem, both solution bind tight control and view models, which is bad in mvvm.
Schematically
The way you've drawn your diagram answers your own question as to how you should structure the code for this.
What you need is one VM (let's call it MainVM) which contains an ObservableCollection<VMBase> of the other VMs (using your base type so that they can all happily live in the same collection).
Your View needs an ItemsControl (bound to your ObservableCollection<VMBase>) where you specify a DataTemplate for the Button using the properties exposed by the VMBase type only. Set the Command property in the Button to call SwitchCommand, CommandParameter is set to the item itself (i.e. {Binding .}).
Your View also needs a ContentControl bound to a SelectedVM property on MainVM which you can populate.
Implement SwitchCommand to set the SelectedVM property based on the value from the CommandParameter.
public void ExecuteSwitchCommand(object parameter)
{
var vmBase = parameter as VMBase;
if (vmBase != null)
SelectedVM = vmBase;
}
All properties mentioned here should be INotifyPropertyChanged enabled so that the View registers when they change and updates the UI.
To get the different UIs for the ContentControl, add type-specific DataTemplates for each of your specific VM types to the Resources file of your View (or if you're smart and are building a custom plug-in framework, merge the Resource Dictionaries).
A lot of people forget with MVVM that the whole point is that there is a purposeful separation of View from ViewModel, thus meaning you can potentially have many Views for a single ViewModel, which is what this demonstrates.
I find it's easiest to think of MVVM as a top-down approach... View knows about it's ViewModel, ViewModel knows about its Model, but Model does not know about its ViewModel and ViewModel does not know about its View.
I also find a View-first approach to development the easiest to work with, as UI development in XAML is static (has to be).
I think a lot of people get to wrapped up in 'making every component (M, V, VM) standalone and replaceable', myself included, but I've slowly come to the conclusion that is just counter-productive.
Technically, sure you could get very complicated and using IoC containers, create some ViewLocator object which binds a View-type to a ViewModel-type, but... what exactly does that gain you besides more confusion? It makes it honestly harder (because I've done this at one point) to develop because now you've lost design-time support first and foremost, among other things; and you're still either binding to a specific view model interface in your view or creating the binding at run-time. Why complicate it?
This article is a good read, and the first Note: explicitly talks about View vs. ViewModel. Hopefully, it will help you draw your own conclusions.
To directly answer your question, I think having your ViewModels implement an INavigator interface of some sort is probably ideal. Remember your VM is 'glue' between your view and model/business logic, its job is to transform business data into data that is consumable by your views, so it exists somewhere between both your UI and business layers.
This is why there are things like Messengers and View Services, which is where your navigator service on the ViewModels can fit in nicely.
I think the design has led to a no way out situation.
I believe that creating a custom button control where the dependency properties tie the image, the row and column actually provide a way for the page, which it resides on ,to get that information to them; whether they are dynamically created or not.
Continuing on with that thought. There is no MVVM logic applied to a custom control, the control contains what it needs to do its job and that is through the dependency properties as mentioned. Any functionality of the button should be done by commanding; all this makes the button data driven and robust enough to use in a MVVM methodology or not.
Question: how shall my control get data from view models?
There should only one viewmodel which is the page the control resides on. The control is simply bound to information which ultimately resides on that VM. How it gets there, that is up to the programmer. If the button is going to contain state data, that is bound from its dependency property in a two way fashion back to the item it is bound to.
By keeping VMs out of the buttons and only having one VM that is the best way to segregate and maintain the data. Unless I am really missing something here....
Same as others here I find it a bit hard to actually understand what you are asking, so this is quite general. The answer to the question header is simply: the Control gets the data from the ViewModel through bindings, always. You set the DataContext of your Control to the corresponding ViewModel, and from there you keep the ViewModel and the Control synchronized:
If you add an ItemsControl containing buttons to the View, you add an ObservableCollection<ButtonViewModel> to the ViewModel and bind the ItemsSource of the ItemsControl to this.
If you allow the user to dynamically add content to the View, the actual code that does it resides in the ViewModel, e.g. when the user clicks on a button "Add Button", you use the Command property to call a ViewModel method that adds a ButtonViewModel to the collection and the View will automatically reflect your changes.
There do exist complicated cases that are impossible to code exclusively in the ViewModel, I have found Behaviors to be the missing link there, but I'll get into that when you show me the specific case.
If you'd like to get a working example, please provide as much code as you can, with your exact expectations of what it should do.
I am having a form with different type of controls like Text Box, Drop downs, Check box, Radio buttons etc. All these controls are loaded dynamically from database at run time.
I want to perform validation on Text box on conditional basis. For example, If we have selected any value in drop down, then you must have to fill details in Text box. Otherwise text box details are not required.
I am open to use database to perform this task and I am using MVVM pattern in my project.
Any help on this is highly appreciated.
Thanks.
(I started this as a comment, but it ended up being too long).
In theory you have access to all these controls and their values in your ViewModel.
Without knowing the specifics of your program, it's difficult to suggest anything useful, but in essence you need to expose some more properties from your ViewModel (probably boolean) which will be calculated based on the values in your controls. Then you need to bind IsEnabled properties on your controls to these new properties.
Sounds simple, but I think you have some architectural problems which will make it difficult to implement what I suggested above. In order for this to work and automatically update your controls whenever other controls' content change, your ViewModel needs to implement INotifyPropertyChanged and raise PropertyChanged event every time you update one of those boolean properties.
I think what you're trying to do could be achieved with ItemsControl and DataTemplates (and maybe DataTemplateSelectors). This will allow you to store "data" in your ViewModel (say List or something more specific) without referencing the actual Controls and the relevant DataTemplates will add the right controls for different data types you have in your ViewModel.
I've searched around, but don't think I really found an answer. I'm trying to get a handle more on data binding and starting to see things coming together. Can you do data binding to something like "IsEnabled" based on TWO Properties, if so, how...
ex: A Window has some controls... certain controls may or may not be enabled at certain times. Some times it's as simple as when data is available (such as finding a record to edit), or when adding... I would consider this an "Editing" mode of the window. Sometimes, certain controls are only available when doing an Edit AND the user has admin permissions.
BOTH conditions need to be true for the control to be "enabled". Similarly could be applied to visibility of a control under similar conditions.
If you're using the MVVM model (which you really should if you're doing WPF development), then you're thinking about it the wrong way.
This sort of logic belongs in the ViewModel. You should have a single property on the ViewModel that represents the visiblity of the control (or controls) and have whatever logic is required (permissions, data validity, mode, etc.) in the ViewModel to determine this value. Putting the logic on the view hamstrings you and violates SOC.
The ViewModel is supposed to model your view. That is, there should (in most cases) be a 1:1 correlation between elements and concepts in your view (such as whether or not a feature is enabled or visible) and properties on your ViewModel.
You could use MultiBindings and some custom aggregate multi-value converters to achieve this declaratively. Alternatively, it may be more explicit (and therefore recommended) to place an additional property on your view model which compounds the values of the other view model properties.
I'm on a project where we use MVVM pattern.
By user layout: Sorting order of a grid, state of window or control.
For example is it possible to serialize all WPF control layout?
AvalonDock can serialize its layout, but that won't apply for grid column widths (AvalonDock is by all means great library!).
Also, I have written a set of classes that can make any property (of serializable type) of any object (in an WPF application) persistent only via adding a [Configurable] attribute to the property. It shouldn't be hard to customize it to save the properties based on a different criterion than presence of an attribute. But it saves the values on per-type basis, so it might be something else than you are looking for.
I can share if you wish.
I'm trying to figure out what exactly Dependency Properties are, but when I look anywhere for a definition, I only find "how to use" but not "what it is".
Imagine you are asked on a job interview - what is a dependency property. What would be your answer?
A DependencyProperty is a property whose value depends (or can depend) on some other source (such as animation, data binding, styles, or visual tree inheritance). A regular property's value is stored in the object it belongs to, while you can think of a dependency property as being stored in a database somewhere. This database is essentially composed of a dictionary that maps (object, property) pairs to their values, along with a mapping of which properties depend on other properties (e.g. so when you change the DataContext of a Panel, it can notify all the children inside the panel).
So why do they store property values in some magic database somewhere? There are a few reasons:
It reduces storage space. Adding a property (even if its value is null) to a class adds 4 bytes (8 for a 64-bit process) of space to every instance of the class. A DependencyProperty only takes up space when an instance has a value. For example, a FrameworkElement has dozens of dependency properties, most of which are never assigned values. If all those properties were stored in the class, each instance would be hundreds of bytes. Instead each instance is only about 40 bytes.
It enables attached properties. Properties like Canvas.Left and Grid.Row have to be stored on objects that have never heard of a Canvas or Grid, so where do you put them? You put them in a database somewhere.
It enables automatic property changes. Imagine how you would implement something like styles or property inheritance (the ability to set something like a font or data context on a parent element and have its value propagate to all child elements). Having all of this stored in a database makes it so the code is all in one place instead of being implemented separately for each object and property that needs it.
"gives you a bunch of infrastructure to do all the things that you often want to do with a normal property - validate it, coerce it into a proper range, give out change notifications, and a number of other aspects."
WPF Tutorial - Introduction To Dependency Properties
A dependency property is a property that is backed by the WPF property system instead of by a field in the declaring class.
The significance of this is that, because WPF owns the property, WPF can factor in various considerations when calculating the property value -- such as animations, styles and data bindings. Another consequence is that because properties are managed by WPF they don't have to be declared on the classes that conceptually have the state: hence, atttached properties, which allow e.g. a Grid to associate Grid-specific state with non-Grid objects.
(By the way, I've mentioned WPF above because this is the main framework that uses DPs, but Windows Workflow Foundation also has the notion of dependency properties. So to be strictly correct a DP is a property that is backed by an external property system, specifically one which allows factors other than "the last set value" to come into play when getting the property value.)
MSDN provides a good definition, description and examples
For more deep understanding of DependencyProperty check here
A dependency property depends on multiple providers for determining its value at any point in time. These providers could be an animation continuously changing its value, a parent element whose property value propagates down to its children, and so on.
Arguably the biggest feature of a dependency property is its built-in ability to provide change notification.
Whenever the value of a dependency property changes, WPF can automatically trigger a number of actions, depending on the property’s metadata. These actions can be re-render-
ing the appropriate elements, updating the current layout, refreshing data bindings, and
much more. One of the most interesting features enabled by this built-in change notifica-
tion is property triggers, which enable you to perform your own custom actions when a
property value changes, without writing any procedural code