Bind to System.Attribute from model

Apr 12, 2012 at 9:21 PM
Edited Apr 12, 2012 at 9:22 PM

Hallo,

is it possible to access custom attributes from a model in a viewModel and bind to them?

If you have a model like this:

 

public class Person
{
  [MyAttribute("Some Description")]
  public string Name { get; set; }


 

 

Thanks,

Mark

Coordinator
Apr 12, 2012 at 9:22 PM

There is currently no way to get attributes or info from the mapping system. The mappings are currently private to the ViewModelBase (internally it has a mapping helper). Why would you want something like this (if there is a use case, we might have a new feature request :) )

Apr 12, 2012 at 9:52 PM
Edited Apr 12, 2012 at 10:14 PM

Wow, that was fast. Amazing.

I thought about a way how to set things like display Caption(column header name), toolTip text, images and so on to the models. To have sth. like a global configuration for them.

The big next step would be something like creating controls dynamically for all properties, like filters. Because this is really annoying to design such filters 100 times. I would give the models properties attributes like ShowInGUI (true/false), maybe sth. like the type of control which to create for the property (textbox, combobox, ...) and then let the user design the filter by himself and safe the layout.

I worked as a student for company which had sth. like that in winforms and i liked it and the customers too.

And if the viewmodel property has no such attribute, then look in the model property for it.

I know I can do this in viewmodel and use an converter to bind it, but if you use the same model in several viemodels, than it would be pointless to rewrite every time the same attributes.

Coordinator
Apr 13, 2012 at 8:00 AM

I understand. What you need is access to how properties on a view model are mapped to a model. We will see how we can make this accessible. However, I don't think we can make it for 3.1 (it's going to be released very soon).

Apr 13, 2012 at 8:29 AM
Edited Apr 13, 2012 at 8:35 AM

That sounds very nice and I think this could be a nice feature in your framework? But I have to say I am new to wpf especially MVVM, so maybe there are better ways to accomplish such behavior in WPF/MVVM, without Attributes?

The only way I see at the moment is to put a "Description" Property in the model, in which a special object/List offeres the Parameters for the each Property. The Properties must be registered to that object. What did you think about this?

 

OT: My actual company, I just started to work there, offers a huge logistic software. But this is really bad stuff, started to developed at 1995 in delphi/win32 with no thinking about about achitecture and so. And until know nothing changed.

So my task is to develop a new architecture and I came around wpf/MVVM. And i started to read many about mvvm and the many frameworks out there. Finally I came to your one and I think this is the one. Best support. documention, ... . And the possibility to extend it is also fantastic. So maybe the new ERP System of my company will build on your framework, maybe combined with Prism.

So Nice Job!

Coordinator
Apr 13, 2012 at 8:47 AM

Not really, the problem is that you want to define something on your model without repeating it on your view models. If you say that you have to rewrite something 100 times, than there should be another way.

However, think of this: why defining something that is used by a view in the model itself? I know that it sounds tempting, but should it really be located there? Maybe you can consider some kind of metadata system that maps the ModelType/PropertyName to a display string. Then you can query this stuff and it is loosely coupled from the models. Then it is located where it should be => in the view or at least as a helper to the views.

Thanks for the compliments. I know I am kind a biased, but I think you made the right choice. All these "simple" and "light" frameworks are great for demos, but do not solve any real LoB problems (except for property change notifications...). For example, how about auditing, command authentication on a higher level, logging, etc. And, you definitely made the right choice with WPF, it is great!

Apr 13, 2012 at 11:02 AM

Yes, I thougt about the problem that the model has influence on the view. But i saw with Catel there is a way to handle validation by model and so I thougt this is also redirected to view, so also a kind of influence on the view, or am i missunderstanding this?

Yes is's very temping to use the model for that. Hm hm hm. Is this breaking mvvm, in a passive way I think?

 

A Helper to the view, ok. Is it possible to give a very short example how you would do that? To direct me in the right position in combination with the mvvm.

 

Should I hardcode the properties with their Attributes, or sth. like a register of the properties. I alwyas think of mvvm, I think this is the normal way of getting MVVM at the beginning, always afraid of doing sth wrong ;-)

 

 

Coordinator
Apr 13, 2012 at 11:16 AM

Validation is totally different. You want to validate your models (data integrity), and you want to let the user know what goes wrong. That is really something different that a string representation of a label for a specific property.

Is it breaking MVVM? No, because there is no direct links from model to a view model or view. Keep in mind that the only thing MVVM really is about is this:

View => View Model => Model

Instead of

View <=> View Model <=> Model

However, I think it is better to create a metadata system for such cases to get a good separation of concerns (because actually, it simply has nothing to do with the model itself).

Apr 13, 2012 at 1:16 PM
Edited Apr 13, 2012 at 1:19 PM

Thanks for your replies

In thinking of creating controls at runtime.

As I mentioned, I want to create dynamically a control for each property in viewModel, which is in the Helper Metadata registered with (ShowInGui....) and bind that control content to the corresponding porperty in VM.

Still questions now, I hope you wouldn't get bugged out of this... I see now two possible solutions.

1) One way to do this I read about in MVVM is to have a List (observable) with all the objects on the viewModel and then bound an itemssource to this List (with the combination of templates in the view). Is this the normal way to do this? And if yes, should this List be generated by the helper. That means there must be a reference in the ViewModel to that helper, where the viewmodel asks for the List with parameter for the needed model description and which property to bind to.

OR:

2) Have no such list on the viewModel. Instead have a reference (static resource?) in the view to the helper and bind itemsSource directly to the helper (which control to build, looking of the control). And the content of the controls then would be bounded to the viewModel Properties.

I think second way is the right solution?

 

Thanks,

Mark

Coordinator
Apr 13, 2012 at 1:22 PM

Disclaimer: this is just my vision on MVVM.

I don't think you should ever, ever bind to helper classes, it is wrong and people showing you this should not call themselves MVVM experts (although they do so...). If you do this, you defeat the whole purpose of MVVM (View, View Model (which is now a combi of a VM with helper), and the model).

However, please take into account the following:

MVVM is for custom code that needs logic. This means that if you need to write (business) logic that you would normally write in the code-behind, you can now do so in the view model. However, what you want is much more dynamic, and the view models will act more as a proxy than a real view-model containing logic. If that is the case, you should really consider just writing a control that can handle models.

I don't know if you are aware of LightSwitch, but they claim to do MVVM as well. Well, if I generate a proxy object between every view and model, and call that a view model, I can indeed call it MVVM, but it fully defeats the whole purpose and the VM is completely useless. 

So, if you are all doing it dynamically, what is the whole point of a view model at all? If you need to apply actions (such as add / delete, etc), you can create a "smart" view model (generic) that can handle all your models. This way, you can actually implement shared logic for all models, but don't have to write tons of useless view models.

Apr 13, 2012 at 2:08 PM
Edited Apr 13, 2012 at 2:10 PM

Yes of thinking the dynamic way to the end, often a special viewModel is not really needed. But I think there could be many cases where you need in fact special logic which can't be autogenerated/generic. I see the dynamic way of building not only in combination with "stupid" logic like filters, more a way to give the user abillity to design the gui by himself, with the possibility to remove some fields he don't need but with the possibility to add them later. So the logic for that fields must be there. I' am also thinking of authentification, don't create that field instead of simple hiding it.

Also after positioning of the controls, the layout can be saved. This gives the possibility, also the developer doesn't need to put Label, combox, Button on the view and bind it. Just start the app with the form, design the layout and save it. Of course in very complex situations there is the normal way of design view.

 

Let's say I need special logic, but let the controls created dynamically. I think MVVM is still the one for go.

So how could i get access to the helper, and where to access it from. If I'am not allowed to bind to it. And I don't get why not.

This is the point I don't get and really need your help.

 

And I don't get the point, why the developer have to put the controls at design time on the view and type binding manual? What the problem of doing this for him?

Coordinator
Apr 13, 2012 at 2:13 PM

I always implement such helpers in the form of services. In catel, there are tons of services available (such as IMessageService (to show message boxes), etc). What you now need to do is write a custom service:

public interface IDynamicDataService
{
    string GetDisplayName(Type type, string propertyName);
}


 Then, you register the service in the IoC container:

ServiceLocator.Instance.RegisterType<IDynamicDataService, DynamicDataService>();

Now in your whole app (thus also in your views, you can do something like this:

var dynamicDataService = ServiceLocator.Instance.ResolveType<IDynamicDataService>();

string displayName = dynamicDataService.GetDisplayName(myModelType, myProperty);

Apr 13, 2012 at 4:33 PM

Again thanks. Using a Service is a good idea.

You say I can use this in the whole app. So I can decide where to put the var dynamicDataService ?

If I put it in view, I have to use CodeBehind. So I can also put it in ViewModel, no matter because it doesn't affect model. Am I right?

For the dynamic creation of the controls, I can either have a list on ViewModel and bind to that List or make it directly in view code behind. What is the better one?

 

 

Coordinator
Apr 13, 2012 at 4:44 PM

Yes, you register it once at application startup, then you can use it anywhere.

The view is a good place for this, because it contains no business logic. Keep in mind that a view model is there to separate business logic from the view, not just to make sure you don't have code behind. Lots of people think that writing code-behind in MVVM is wrong, but it is not. For example, for generating labels for a view, code-behind is the best solution (or a helper class where you inject the view).

It is better to use code-behind to interact with your view then to interact with your view in your view model (I see a lot of "experts" referencing views...). So, in this case, I would create a helper class.

public static class DynamicDataViewHelper
{
    public static void UpdateLabels(IUserControl view)
    {
	    Argument.IsNotNull("view", view);
		
		var dynamicDataService = ServiceLocator.Instance.ResolveType<IDynamicDataService>();
		
		// TODO: Get access to your models somehow, maybe via view.ViewModel
		
		foreach (var model in models)
		{
		    foreach (var property in model.GetType.GetProperties())
			{
			    // TODO: Get label representing the property
				label.Content = dynamicDataService.GetDisplayName(model.GetType(), property.Name);
			}
		}
    }
}

In your code-behind, you can do something like this:

public MyView()
{
    InitializeComponent();

    DynamicDataViewHelper.UpdateLabels(this);
}

Now you ask yourself: why a helper class, not a service this time?

Well, views are hardly unit tested (do you unit tests your views)? The cool thing about services in an IoC container is that you can replace the services during unit tests. For example a IMessageService that shows message boxes shouldn't be used during unit tests, so you register a fake or mocked one during unit tests. But, in the view, you can also use helpers. These are not as loosely coupled as services, but you hardly need loosely coupled code in your views (in the end, that's the piece of software the user actually communicates with, the "end of the line").