Custom control, View Model and dependency properties - silverlight

I'm creating custom control and because I need to do lot's of binding inside a style/template it makes perfect sense to go with MVVM. Where do I declare dependency properties then?
Do they stay in control class? How do I link them to VM?

See my answer to your other question about custom controls and view models. Here's the short version:
Custom controls shouldn't have view models.Don't set the data context of your own control. That's reserved for the consumer.All of your dependency properties should be declared in your MyCustomControl.cs file.Use TemplateBinding in your genric.xaml because it's more efficient that Binding.
To put it another way, what's the view model for a Border or a Button? Answer: they don't have one because they're just controls. UserControls have view models, but controls just present and interact with the data which you give them (where? In your UserControl). Custom control development is probably the hardest thing for a seasoned MVVM developer: your reflex is to make a view model, but that reflex is unfortunately wrong. I know because I've made this mistake myself.

Dependency Properties could be delared in the Control they are belongs to.
When following MVVM in WPF/Silverlight the common approach is to set ViewModel as DataContext of the appropriate View. So you would be able to link custom Dependency Properties to the ViewModel properties using Bindings in XAML.
Let's assume you already set ViewMosel to DataContext of the View:
var view = new UserView
{
DataContext = new UserViewModel { Name = "Custom Name" }
};
public class UserViewModel
{
string Name { get; set; }
}
UserView.xaml:
<TextBlock Text="{Binding Name}" />

When creating a custom control, the control itself is a view model. Declare dependency properties on it to expose bindings that users of the custom control can leverage. For example if you have a timeline control, you might have properties like StartDate and EndDate on the control exposed as dependency properties. Your Controls Default Template would make template bindings to the dependency properties. A consumer of your control might then have a project timeline viewmodel that he binds to the properties on the control.
The primary purpose of a custom control is to provide behavior and a default look and feel for that behavior which is easy to override (by providing a new template). Hope this helps.

Related

Binding a viewmodel's property to another's

I have a main window coupled with a view model.This main window uses a usercontrol which also has its own viewmodel.
What I would like to achieve is setting a binding in the main window's xaml between one of its viewmodel's custom property and one of the usercontrol's viewmodel's custom property.
How would one go about doing that?
Could you instead use the ViewModels as projections of a Model?
That is, could you have a class that holds the state (or actions) that both the VMs need to expose and have both the VMs reference this class?
If for some reason you have to couple views to something outside their own DataContext I believe you can only go up the visual tree by using RelativeSource FindAncestor in the binding. I don't think you can traverse down (e.g. Window -> Control).
If you really want to Bind them together you could make your ViewModel's properties Dependency Properties and your ViewModel derive from DependencyObject - then you could do..
var binding = new Binding("Something");
binding.Source = myViewModel1;
binding.Mode = BindingMode.TwoWay;
BindingOperations.SetBinding(viewModel2,ViewModelType.SomethingProperty,binding);
If this is a good design having your viewmodels derive from DependencyObject is another question..
You could also try looking at this library that allows binding to and from POCOs.
I ended up not using a modelview for my usercontrol, not as neat but at least it works and is less complicated datacontext wise.
Thanks to all.

passing data to a mvvm usercontrol

I'm writting a form in WPF/c# with the MVVM pattern and trying to share data with a user control. (Well, the User Controls View Model)
I either need to:
Create a View model in the parents and bind it to the User Control
Bind certain classes with the View Model in the Xaml
Be told that User Controls arn't the way to go with MVVM and be pushed in the correct direction. (I've seen data templates but they didn't seem ideal)
The usercontrol is only being used to make large forms more manageable so I'm not sure if this is the way to go with MVVM, it's just how I would of done it in the past.
I would like to pass a class the VM contruct in the Xaml.
<TabItem Header="Applicants">
<Views:ApplicantTabView>
<UserControl.DataContext>
<ViewModels:ApplicantTabViewModel Client="{Binding Client} />
</UserControl.DataContext>
</Views:ApplicantTabView>
</TabItem>
public ClientComp Client
{
get { return (ClientComp)GetValue(ClientProperty); }
set { SetValue(ClientProperty, value); }
}
public static readonly DependencyProperty ClientProperty = DependencyProperty.Register("Client", typeof(ClientComp),
typeof(ApplicantTabViewModel),
new FrameworkPropertyMetadata
(null));
But I can't seem to get a dependancy property to accept non static content.
This has been an issue for me for a while but assumed I'd find out but have failed so here I am here.
Thanks in advance,
Oli
Oli - it is OK (actually - recommended) to split portions of the View into UserControl, if UI became too big - and independently you can split the view models to sub view models, if VM became too big.
It appears though that you are doing double-instantiations of your sub VM. There is also no need to create Dependency Property in your VM (actually, I think it is wrong).
In your outer VM, just have the ClientComp a regular property. If you don't intend to change it - the setter doesn't even have to fire a property changed event, although it is recommended.
public class OuterVm
{
public ClientComp Client { get; private set; }
// instantiate ClientComp in constructor:
public OuterVm( ) {
Client = new ClientComp( );
}
}
Then, in the XAML, put the ApplicantTabView, and bind its data context:
...
<TabItem Header="Applicants">
<Views:ApplicantTabView DataContext="{Binding Client}" />
</TabItem>
I answered a similar question as yours recently: passing a gridview selected item value to a different ViewModel of different Usercontrol
Essentially setting up a dependency property which allows data from your parent view to persist to your child user control. Abstracting your view into specific user controls and hooking them using dependency properties along with the MVVM pattern is actually quite powerful and recommended for Silverlight/WPF development, especially when unit testing comes into play. Let me know if you'd like any more clarification, hope this helps.

Can I have a MVVM model inherited from an other model?

I have a ProductViewModel class which contains different properties.
Then I have a ProductDetailsViewModel class which inherit from ProducViewModel class. The reason I am doing it this way is in order to get correct binding environement and avoid duplication of properties from previous view.
I am allowed to do this or each ViewModel should be clearly isolated?
Through code I can acess the properties of the ProductViewModel class from ProductDetailsViewModel view but when I set the datacontext of my ProductDetailView to ProducDetailsViewModel class and bind properties URI for instance which is define inside the inherited class, binding seems not occurs.
Any idea ?
You can do this too, but i think maybe better would be to separate them and use Dependency Injection.
You create and interface for your ProductViewModel and implement it and then you inject this into your ProductDetailsViewModel.
MVVM + WPF + DI
MSDN DI
Yes this is fine, and I do this all the time in my WPF projects so it should just work. Some suggestions:
Can you check your output window when debugging the application. Are there any binding errors suggesting a mis-typed xaml binding?
Are you using any DataTemplates in xaml which bind to a specific type, e.g. ProductViewModel not ProductDetailsViewModel?
Does the base type (ProductViewModel) implement INotifyPropertyChanged?
Are all the properties in ProductViewModel and ProductSetailsViewModel raising the PropertyChanged event with directly typed string property name?
Best regards,

How can I easily expose bindable properties of nested controls from a custom UserControl?

My first question here on the Stack. Forgive me for the bad explanation in advance.
I am working on my first MVVM application (Silverlight). I have a custom user control that contains a ListBox to show navigation items. This control is placed in my main xaml page. I don't know if I need to create a composite view model (my main page view model) with a view model especially for the custom control in it or if there is some way to elevate the ListBox properties that I need to bind to.
Through XAML I don't know how to bind, let's say, the ItemsSource property of the ListBox inside the custom control to my main page viewmodel. Basically, I'm at the point that I am questioning my design decision for trying to bind the custom control through my main page view model.
What I have done so far is create dependency properties for the custom control and try to tunnel those dependency properties down to the ListBox properties. I've achieved success with this method for ItemsSource but am having issues with SelectedItem.
Even if I do get SelectedItem to work, it still feels Wrong. Thanks for any advice in advance.
The UserControl should inherit the DataContext from its parent control, unless you are setting it directly. You can then bind to the properties on your view model from your UserControl.
If you would like to create a ViewModel specifically for the UserControl, you can also do that. You would then expose it as a property on your main ViewModel, and bind to it in the MainPage. Example:
public class MainViewModel
{
public ChildViewModel ChildInfo { get; private set; }
}
And then in the view:
<Grid>
...
<lcl:ChildView DataContext="{Binding ChildInfo}" />
...
</Grid>
Your ChildViewModel would then contain properties like SelectedItem to bind your ListBox to.

How do I databind to a ViewModel in Expression Blend?

In WPF and Silverlight you can make a view model object and set it into the DataContext of a control when the control is constructed at runtime. You can then bind properties of the visual object to properties in your DataContext.
One way to set the binding is to type the binding directly into the tag:
<TextBox Text="{Binding Path=Description}"/>
And this will bind the textbox to the Description property in the view model.
The problem with typing in the binding is that you may make a typing mistake. (And you will almost certainly make a mistake if you have hundreds of bindings to make.)
In Expression Blend there is a little white dot beside the Text property in the Properties window. This brings up a menu from which you can Create Data Binding.
How can I get my view model properties to show in the Create Data Binding dialog so that I can select them.
Will the configuration of data binding in Blend interfere with setting my view model into the DataContext at runtime?
One technique is to include the VM as a resource in your view:
<UserControl>
<UserControl.Resources>
<local:YourViewModel x:Key="ViewModel"/>
</UserControl.Resources>
</UserControl>
You can then reference that as DataContext="{StaticResource ViewModel}" elsewhere.
Can't say I like it, but I can't say I like any of the view-first idiosynchrasies that Blend imposes on your design.
I experimented with Blend to find the drag and drop approach to data binding which still lets you override your view model in code easily.
First make your view model object which implements INotifyPropertyChanged and raises the notify event in the setters. The view models can be hierarchical. For example you could have an ObservableCollection within your main view model.
In Blend open up your page or control and go to the data tab.
On the right open the menu under the "Add live data source" icon.
Pick "Define new object data source"
Select your top level view model class and confirm the dialog
In my experiments I found that it was important to bind the data source to where I wanted it first or else Blend might make a less than optimal configuration if I didn't do the next step first.
Open the Objects and Timeline window in Blend
Select the root object, for example UserControl
Open Properties and verify that the root object is selected
Find DataContext and click the square to open the menu and select DataBinding
Select the data source that was just previously created
Now that the data source has been created data binding is very easy.
put some controls on the page
open the Data window
from the DataSource for your view model drag properties onto the controls to create the bindings or set the binding from the Properties window.
Now you can create you live view model object in the constructor of the control
public MainPage()
{
// Required to initialize variables
InitializeComponent();
mVm = new MyViewModel();
this.DataContext = mVm;
}
private MyViewModel mVm;
Add any initialization to retrieve data and you are ready to go.
I have a screen cast on my blog Blendable MVVM : Introduction and Databinding which shows setting this up for Siverlight.
Essentially you create the ViewModel as the DataContext of the UserControl using the "New Object Initialiser" and then using the "Explicit Data Context" tab of the Binding dialog for the controls themselves.
Hope this helps.

Resources