Data binding to a UserControl - c#

I have a viewModel which is used to bind to a user control. The user control is basically a AdRotator. One of the feature of AdRotator is that it can be used in multiple positions on same screen. Seperate set of ads will be displayed on these multiple adRotators. The single view model exposes 4 observable collections which is deputed for adRotators on various locations . My problem is that since user controls are 'drag n drop' use i am a looking for a identification method that will let me determine which observablecollection(of the 4) should the an adRotator bind to. Please let me know what are the approaches for this.
Will it be a good approach if i retrieve the name of the user control and bind the collection depending on the name?

ViewModels are for logical parts of your application. For reusable controls, I would create a regular UserControl with code behind. This Control can expose API through properties and events, and in your case would expose a Dependency Property that would get the list of "ads".
This way you can position them all in a View, where each AdRotator control is bound to a different collection. This way the logic would sit in only one place - the ViewModel, and the reusable UI would sit in a dedicated control.
View+ViewModels are for logical seperation (Single Responsibility Principle, SRP) where are reusable controls are for reuse (or DRY: don't repeat yourself). It's very important to identify which type of control you are using. regular reusable controls should not contain ViewModel.

I don't know the specifics of your view models so I will offer one possible approach expressed in general terms.
Suppose you have a view model with four child view models which are all variations that have properties that the bindings in your user control are looking for and are named Vm1, Vm2, etc. which in your case could be your ad collections. You could bind the DataContext of each instance of you user control to each of the child view models.
<my:SampleUserControl DataContext="{Binding Path=Vm1}" />
<my:SampleUserControl DataContext="{Binding Path=Vm2}" />
<my:SampleUserControl DataContext="{Binding Path=Vm3}" />
<my:SampleUserControl DataContext="{Binding Path=Vm4}" />
This way each instance of your user control can bind to and display different data.

Related

How to instantiate an object in ViewModel and edit that in another ViewModel or user control

I'm new to c# and mvvm.
I have a class that has many properties, and because of that, it is not possible to present every property to user in one page. Therefore, I decided to break the UI into 4 different part. I designed one user control for each of these parts.
As of now, I have 4 different user controls which are presented to user with the help of a side bar selection.
However, I still have one object to work with and it is not possible to break the object too.
The problem is I cant access to object from user controls' code behind. It means that I can bind object with UI but I'm not able to change parameters in code behind.
Welcome to SO!
On one hand you talk about MVVM and data-binding, but then on the other hand you talk about modifying changing parameters in code-behind. These are antithetical design patterns. Pick one!
If you are implementing MVVM then, as you know you have the View (UI e.g. Page1.xaml) in XAML, with code behind (Page1.xaml.cs) these then use a ViewModel (e.g. Page1ViewModel.cs) as their data context, i.e. where they can access the Model.
You do not have to have a one-to-one correlation of Views, ViewModels and Models.
You can have more than one View use the same ViewModel as its data context and you can have a ViewModel contain yet more ViewModels and a ViewModel can reference several Models if required.
So in your situation I'd have several pages reference the same ViewModel.

How can control in the view get specific data from view model?

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.

Dynamically generating controls in WPF using Prism, MVVM, MEF

I am using WPF with Prism and MEF for my application. There was a need to create controls dynamically. And so here is my problem!!
As far as I know I should not be having code in my code behind (SomeFile.xaml.cs) to keep my code easily testable. And so the code should be actually moved to ViewModel.
But my code generates UI controls dynamically. And I dont think that the ViewModel should know anything about the Controls.
So where and how should I go about writing this code?? What would be the right approach?
Hope I made myself clear!
Thanks
When working with WPF/MVVM, your data layer is your application (the DataContext), and you use things like Templates to tell WPF how to draw your application components to the UI.
For example, suppose you're given the task to dynamically render a bunch of controls.
The WinForms way might have been to loop through your objects, create a UI control for each object, then add the UI control to the screen.
However with WPF/MVVM, you would instead create a class representing each object (a Model), and give WPF a list of those classes to display.
There are many different controls WPF can use to draw a list of objects, but the most basic of them is probably an ItemsControl. I have some examples of a simple ItemsControl on my blog if you're interested.
Now even though you've given WPF the list of your objects to render, and told it what control to use to render the list, it still probably doesn't know how to draw your object. The usual solution for this is to include an XAML template of some kind to tell it how to draw your object.
Here's a simple example template that is used to tell WPF how to draw an object of type MyClassObject:
<DataTemplate DataType="{x:Type local:MyClassObject}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:" />
<TextBox Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
I hope that helps get you going in the right direction :)
From my perspective, the view has the responsibility to render the data/model provided by the viewmodel. While it is ideal to keep as much of the model->view translation logic in the viewmodel, creation of controls adds significant complexity to move to the viewmodel, because of the coupling or infrastructure that it could add.
While you could:
1) Give the viewmodel direct access to the view, allowing it to create controls directly
This adds coupling...
2) Create an interface on the view to manipulate controls
This means the view must be passed (not simply bound) to the viewmodel
3) Create an abstraction of controls to bind to the view, and have the view render based on the abstraction created by the viewmodel
This adds a maintenance nightmare as your control set expands.
I suggest exposing the model (either directly or wrapped in micro-viewmodels) via a property on the main viewmodel, and binding that to a property on the view via xaml, such that any PropertyChanged on the viewmodel will send an update to the view. Use the model information and your control creation logic inside the view to clear and re-create the controls and bind the model dynamically to the controls you create. This will simplify both the creation and binding of the controls, and you won't have to practice any voodoo to get information entered into the controls back into your model.
Note that even if you created an intermediary class (an attached behavior, adorner, or something else), it will still need to be able to access the view's control structure directly to attach the generated controls to the visual tree, which may cause other problems.

WPF global variables?

This question is quite tricky to word, so please do ask if my explanation is lacking.
I have an application that has several datagrids which contain editable objects, for example containers, shipments and packages.
Now each of these objects (shipment, container, package etc.) often require knowledge of the selected item in another datagrid (for example, package needs to know what container is selected in the containerviewmodel) usually i would fire an event when selectedItem changes and listen for those events on the viewmodels that require this information, however recently changes have been made which require models to know about selections.
So my question is, would it be "bad practice" or bad code wise to have a single class which contains all the currently selected items from all viewmodels, and simply listen to events in that single class, which is then used by viewmodels and models to find out about selected items? (Using IoC.get<> in order to get the instance of the "global" class)
In my opinion, I would say that it was 'bad practice', as you say, to have model data type classes needing to know anything about selected items. I have always believed that the data type classes should just be 'holders of data' and have very little or no functionality... that is the job of the view models.
What I might do in your situation is have a parent view model that holds all of the collections and properties to bind to the selected items from each collection. That way, you could deal with everything in one location. The child views could bind directly to the parent view model as well if that would help:
<DataGrid ItemsSource="{Binding DataContext.Shipments, RelativeSource={
RelativeSource AncestorType={x:Type Views:ParentView}}}" />

wpf data binding to enable control based on multiple criteria

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.

Categories