Wpf UserControl and MVVM
Asked Answered
T

3

28

I am thinking about writing a WPF User Control for my application. I am using MVVM in my application.

User control's may require Dependency Properties that can be set my Parent View. when using MVVM, the idea is that the Parent View will eventually create a binding between the UserControls DP with Parent View's VM)

Dependency Properties need to be created in the View class as VM do not inherit from DependencyObject. This means adding code within the XAML code behind.

I was wondering if you can give advice as to how I should design a user control when developing WPF application using MVVM...

Toddler answered 26/7, 2010 at 10:17 Comment(0)
C
32

Case 1: If you are creating this control just to be consumed in your application then you can go ahead and create a ViewModel for it, but then you don't need to create DP's, your ViewModel can just implement INotifyPropertyChanged and your parent Vm can still bind to them.

In our case, for user controls we have created separate VM's and an instance of it was present in ParentVM. So parent view will have this control in it and will bind the UserControlVM to this control(ParentVM.UserControlVM) and usercontrol will take care of other bindings.

Case 2: If your control will be used by other applications/developers and you don't want to keep it simple then go ahead with creating custom controls following control template implementation. This way you can create look-less controls and use dependency properties too. Moreover whoever uses that control doesn't need to know about the related view model and use it.

Some of the similar questions/posts:

WPF design question (custom control or mvvm): WPF design question (custom control or mvvm)

Custom control in WPF using MVVM concept: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/6293b176-e1e9-4610-af49-d53e6d294969/

WPF User Control hell with MVVM and Dependency Properties: WPF User Control hell with MVVM and Dependency Properties

Chronograph answered 26/7, 2010 at 12:32 Comment(4)
hi akjoshi, what startegy do you use to bind from parent VM to the controls VM property ? Could you give a small example?Toddler
Genrally I set the DataContext of the child control to the object of UserCOntrolVM which is present in the ParentVM. so Say you have a main window inside which your user control is present. Now, data context of Main window is set to ParentVM, this ParentVM will expose a property of type UserControlVM. Now we just need to set the data context of user control like this - <local:UserControl DataContext="{Binding Path=UserControlVM}" />Chronograph
Thanks akjoshi, I use this strategy in my application and all VM implement INotifyPropertyChanged. My question was more about property binding in your comment "your ViewModel can just implement INotifyPropertyChanged and your parent Vm can still bind to them." Do you create the controls VM in ParentVM and let the ParentVM directly bind to controls VM ??Toddler
Hmm a negative vote after 8 years; will be great to know the reason! Please enlighten.Chronograph
Q
13

A UserControl is part of the "View" in "MVVM" just like the TextBox or ListView controls are part of the View.

Whether you decide to use MVVM to develop your UserControl itself or write it in QBASIC (not recommended) it does not break the MVVM pattern for the consumers of your UserControl so long as they can do every thing they need with your UserControl by binding to DependencyProperty's exposed on your UserControl. i.e. Your UserControl should expose the properties it is dependent upon (hence the name). Once you grasp this DependencyProperty's suddenly make a whole lot of sense and you want their helpful on changed event handlers and default values you specify in their constructor.

If your UserControl is in a different assembly or not I cannot see how that makes a difference.

That said many would advocate you build your UserControl using the MVVM pattern itself for all the good reasons MVVM brings e.g. helping another developer looking at your code. However some things simply are not possible and/or much harder more complex and less performant hacking the XAML to do this - I am not talking about your garden variety Add User Form but for example a UserControl handling the layout of thousands of visuals. Furthermore since you are working in your View you do NOT want your UserControl's ViewModels mixed in with you applications!

Basically I am saying it is well within MVVM not to use MVVM on your View!

Quiteria answered 10/4, 2014 at 0:53 Comment(3)
Good recommendation to keep the VMs of the application and UserControl separate (+1).Environmentalist
"Your UserControl should expose the properties it is dependent upon (hence the name)" - Just like that, I now understand the idea behind Dependancy Properties..Thank you sir!Stickpin
With this definition of DP as noted by @ENDEESA, it means we may just be needing a regular properties inside user control that implements INotifyPropertyChanged interface? But then the view of user control should implement that instead of it having viewmodel? I see setting DataContext inside user control is not advisable.Southwestwards
S
2

Basically, instead of binding your UserControl's datacontext to the userControlViewModel, it's better to do it on the first child element of the user control. That way, all the references that you make within the control will be bound to the userControlViewModel, but the dependencies properties can be set from the data context set where you want to use your UserControl.

This pattern has worked pretty well for me, on your UserControl XAML:

<UserControl x:Class="Six_Barca_Main_Interface.MyUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Six_Barca_Main_Interface"
             xmlns:System="clr-namespace:System;assembly=mscorlib" 
             mc:Ignorable="d" 
             d:DesignHeight="900" d:DesignWidth="900">

    <DockPanel  x:Name="rootDock" >
        <TextBlock>{Binding SomethingInMyUserControlViewModel}</TabControl>
    </DockPanel>
</UserControl>

Then on the code behind:

public partial class MyUserControl : UserControl
{
    UserControlViewModel _vm;

    public MyUserControl()
    {
        InitializeComponent();

        //internal viewModel set to the first child of MyUserControl
         rootDock.DataContext = new UserControlViewModel();

        _vm = (UserControlViewModel)rootDock.DataContext;    

        //sets control to be able to use the viewmodel elements

     }

     #region Dependency properties 
     public string textSetFromApplication
     {
         get{return (string)GetValue(textSetFromApplicationProperty);}
         set{SetValue(textSetFromApplicationProperty, value);}
     }

     public static readonly DependencyProperty textSetFromApplicationProperty = DependencyProperty.Register("textSetFromApplication", typeof(string), typeof(MyUserControl), new PropertyMetadata(null, OnDependencyPropertyChanged));

     private static void  OnDependencyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
     {
        ((MyUserControl)d)._vm.SomethingInMyUserControlViewModel = 
             e.NewValue as string;
     }
     #endregion
Splashy answered 20/2, 2018 at 18:39 Comment(1)
+1 for a PropertyChangedCallback method but, can you tell me whay you set rootDock.DataContext = new UserControlViewModel(); instead rootDock.DataContext = this;Support

© 2022 - 2024 — McMap. All rights reserved.