Can MVVM Usercontrols have property defined in codebehind? - wpf

I have a WPF user control ...which is in MVVM. The user control(which contains a listview) need data from the page (where it is included). I have to set a property to get this data input. Will this comply with MVVM...if not, what is the way for the same?

I'm afraid this won't be correct in MVVM design pattern. try to stick to your view model to define properties. Why don't you consider moving that property to control's vm?

Use an ObservableCollection rather.
ObservableCollection<myModel> myOC = new ObservableCollection<myModel>();
where myModel is a class that has to be constructed transforming your columns in the DataTable to Properties.
In your MainViewModel, loop through the DataReader and create myOC out of it.
Now bind myOC to a ListView in your page.
The DataTemplate of ListView should be a view(UserControl) drawing data from a ViewModel constructed out of myModel
But your UserControl has the entire ListView inside. If that is on purpose, then let me know the entire design to give a better idea.

Related

WPF MVVM - Binding DataGrid to ObservableCollection of Model

I am pretty new to WPF MVVM, so pardon me if I understood MVVM concepts wrongly.
I have a DataGrid in my View, which I have bound the ItemsSource to an ObservableCollection<M> in the ViewModel. The M class is a Model class. However, the M class has bool properties, which are to be displayed in the DataGrid as "Yes/No" strings.
Currently, I am using a Converter to convert the bool value to string. But, it just feels wrong for the ViewModel to expose a list (ObservableCollection) of a Model to the View. I have also read that in MVVM, conversions should be done at ViewModel. So, what is the right way to implement this the MVVM way for a DataGrid?
In an ideal world, you would wrap your Model objects in their own ViewModel so that your ObservableCollection contains a ViewModel type with those bool Model properties converted to Yes/No string properties.
However, in a pragmatic world, if you are not editing those values, I wouldn't bother except to note that if you are exposing many of those bool properties and have many thousands of rows, you will take a performance hit on rendering the grid while the DataGrid instantiates a Converter per property and row.
Using converters is not a wrong way. As per my suggestion, you should bind the data as you're doing now and in the view you can create and use a BoolToStringConverter for converting the boolean value to yes or no.

WPF DataBinding with MVVM and User Controls

Let's say I have a Customer Window showing information about a customer, like Name, address and phone number. On the bottom there is a DataGrid of their orders. Of course the Customer has an Orders property, so if you're using MVVM, you would just set:
ItemsSource = "{Binding Customer.Orders}"
However, now let's say that the data grid is now part of a user control, which also includes controls for editing/adding/removing Orders. I want to use this same set of controls in multiple places, and I would like all the logic for editing/adding/removing Order objects to be encapsulated in the user control. And because I want to use commands, rather than event handlers, I would like the user control to have its own view model.
So now the question is: how do I pass the orders from the Customer view model to the Orders user control's view model? Because the Orders user control will be bound to a view model, I can't say:
<local:OrdersUserControl DataContext="{Binding Customer.Orders}" />
because the user control has it's own view model. It would expect to see Customer.Orders there, and of course it's not.
I guess this is kind of a chicken or the egg situation.
Your help is always appreciated.
Aaron
And now for my weekly "don't do that" answer...
I can't say ... because the user control has it's own view model.
To which I say
Creating a ViewModel for your UserControl is a code smell.
You're experiencing this issue because of that smell, and it should be an indication that you're doing something wrong.
The solution is to ditch the VM built for the UserControl. If it contains business logic, it should be moved to an appropriate location in another ViewModel.
You should think of a UserControl as nothing more than a more complex control. Does the TextBox have its own ViewModel? No. You bind your VM's property to the Text property of the control, and the control shows your text in its UI.
MVVM doesn't mean no codebehind. Put your UI logic for your user control in the codebehind. If it is so complex that you need business logic inside the user control, that suggests it is too encompassing. Break it down into two or more.
Think of UserControls in MVVM like this--For each model, you have a UserControl, and it is designed to present the data in that model to the user. You can use it anywhere you want to show the user that model. Does it need a button? Expose an ICommand property on your UserControl and let your business logic bind to it. Does your business logic need to know something going on inside? Add a routed event.
Normally, in WPF, if you find yourself asking why it hurts to do something, it's because you shouldn't do it.
There are many ways to skin a cat. The way I've been doing this is by having my CustomerViewModel have a property of type OrdersViewModel. Then in the constructor (or wherever you are setting the customer) have it set the "OrdersContext" with a new OrdersViewModel passing in the customer.orders.
XAML:
<local:OrdersUserControl DataContext="{Binding OrdersContext}" />
ViewModel:
public CustomerViewModel(Customer customer)
{
Customer = customer;
OrdersContext = new OrdersViewModel(customer.Orders);
}

WPF DataGrid Binding - Which is best?

I am fairly new to WPF and MVVM.
I see that a DataGrid can be bound to a CollectionViewSource or an ObservableCollection or a DataSet.
What is the significance of using one over the other?
CollectionViewSource is the XAML equivalent (can be instanciated in XAML) for CollectionView, which provides functionality for grouping, sorting, filtering, and navigating in any data collection. If you want to provide any of these features in the view (XAML) only and do not want to do this in the viewmodel, use a CollectionViewSource else use the ObservableCollection or CollectionView in your viewmodel. Use a DataSetwhen you have your data already in that form and do not want to go through the hassle of creating a viewmodel.
I mostly use the ObservableCollection in the viewmodel.
I would not recommend you using DataSet. You could sort, group and filter data using CollectionViewSource.

Silverlight MVVM: MainView w/ SubViews OR MainViewModel w/SubViewModels

I have a MainView with a Tabbed UI.
How do I add a new TabItem (= View) to the TabControl?
Basicaly I see 2 ways:
1.)
* from code in the MainView I can add a new tab.
* the new tab contains a view with a referece to it's viewmodel.
2.)
* from code in the MainViewModel I can add a new viewmodel to a List of childViewModels
* the tabcontrol of the mainView is bound to that list
I prefere case #1 somehow, cause I think the view should know and instanciate it's VM (maybe by using the MVVM light ViewModelLocator) and not the other way round.
But how can I refere from the newly created VM to the MainVM? For example: the MainVM has a property 'IsAdmin'; how can I access (bind) that property from the SubViewModel?
alternative #2: how does the TabControl know, which view should be "rendered" for different ViewModels? How can I "map" from the SubViewModels to the corresponding "SubViews"?
Thanks for sharing your ideas!
I would check out this SO post as the answer can be applied to helping you with your problem.
In the spirit of MVVM, you will want to follow alternative #2. Let your ViewModel logic help you determine which "tabs" you need to display and use DataTemplates to represent those objects. Then you will get them bound to the DataContext of the View and your binding in the DataTemplate (View) will work correctly.
Thomas,
MVVM really is MVVMC. I would advise having a controller for the MainView which contains a method for creating a new tab. If the TabControl is complicated, you might put the functionality in the TabControl itself.
Separation of concerns (MODEL versus VIEWMODEL versus VIEW versus CONTROLLER) is compromised when actuation functionality is located in the models. (M or VM).
Regards,
Guido

Dynamically specify and change a Silverlight DataGrid's columns during runtime (MVVM)

What's the best method of dynamically specifying DataGrid columns in the Silverlight DataGrid control at runtime following the MVVM pattern?
What I'd like to do would be bind the "DataGrid.Columns" property to a property in my ViewModel so that, if the user adds/removes columns, I simply update the ViewModel property and the DataGrid would change. Problem is, the "DataGrid.Columns" property can't be bound to (I don't think).
Because this property isn't available nor is the DataGrid control itself available at the ViewModel level, my current approach is to step outside of the MVVM pattern for this particular implementation and capture certain events in View's code-behind using MVVM Light's Messenger class and then talk directly with the DataGrid control to achieve this capability. I know this is a general statement to this approach without details but is there an easier way... or maybe not so much easier, but a better way that adheres to the MVVM pattern a little better?
It's driving me crazy that the DataGrid control's Columns property can't be bound... seems like such a simple thing.
FYI - Before it's suggested to use AutoGenerateColumns = True, the class being bound for each item in the collection that's bound to DataGrid.ItemsSource does not have individual properties to identify what is bound to the columns... it's a collection property that contains the columns in order to keep them completely dynamic so that particular path is out. Also, handling the AutoGeneratingColumns and using e.Cancel to show/hide columns is also iffy for this same reason (I think).
I agree that it is a pain that DataGrid.Columns cannot be bound to. My recommendation here would be to define your columns in the ViewModel in an ObservableCollection. In the View (code behind), handle the CollectionChanged event of this ObservableCollection, and modify the DataGrid.Columns in code.
While this solution is less elegant, it is straightforward. For your ViewModel, you can unit test that the CollectionChanged event is raised properly when columns are added, removed or moved. The View code cannot be tested, so I guess this is something you need to live with. The advantage is that, if some day the DataGrid.Columns property can be databound, it will be easy to refactor this to remove the code behind.
Another way (I think) would be to create an attached behavior or a Blend behavior to take care of this. Attach it to the DataGrid; instead of binding to the DataGrid.Columns directly, bind to a property on the behavior, and have the behavior modify the DataGrid (the AssociatedObect) directly.
Does that make sense?
Cheers,
Laurent

Resources