How can i access a control in mvvm model in viewmodel?

53,185

Solution 1

Use Supervising Controller pattern.

Reading:

Example implementation for CaliburnMicro MVVM framework is shown here (will work same for all other frameworks - or you can do it by hand if you are doing MVVM by yourself):

http://drc.ideablade.com/devforce-2012/bin/view/Documentation/cocktail-tutorial-talk-to-view

Example:

1) Define interface IView in which ViewModel (VM) will talk to View with the required method(s)

public interface IView 
{
    void AddTextBoxToGrid();
}

2) Inherit code behind View from your IView and implement IView.AddTextboxToGrid() method

public partial class View: IView 
{
    public void AddTextBoxToGrid() 
    {  
        // implement here your custom view logic using standard code behind; 
    }
}

3) Add a property of type IView to your VM

public class ViewModel 
{
    public IView View { get; set; }
}

4) Set View property on VM to an instance of View as IView e.g. in code behind:

 DataContext.View = this as IView; 

or in Caliburn you can use IScreen.OnViewAttached override method)

public partial class View: IView 
{
    public View()
    {
        // access you VM by the strategy of your framework or choice - this example is when you store your VM in View's DataContext
        (DataContext as ViewModel).View = this as IView;
    } 

    public void AddTextBoxToGrid() 
    {  
        // implement here your custom view logic using standard code behind; 
    }
}

5) In your VM call IView.AddTextboxToGrid()

public class ViewModel 
{
    public IView View { get; set; }

    public void AddTextBoxToGrid() 
    {
        if (View == null) return;
        View.AddTextBoxToGrid()
    }
}

Solution 2

You should move your creation code to View, and ViewModel should just notify view when it should be called.

Share:
53,185
Sanjay Patel
Author by

Sanjay Patel

Updated on June 06, 2020

Comments

  • Sanjay Patel
    Sanjay Patel about 4 years

    I have a WPF Window, and in that window I have a grid.

    I use M-V-VM model and I want to add a TextBox to the grid dynamically in code(in viewmodel)

    How can I get access to the grid?

  • Mohammad Dehghan
    Mohammad Dehghan over 10 years
    It is better to use constructor injection to send the IVew instance to ViewModel (I mean, ViewModel class' constructor should accept an IView instance).
  • heltonbiker
    heltonbiker about 9 years
    It is important to stress that creating a dependency from viewmodel in the view is not the purest mvvm either. When you use (DataContext as SomeViewModel), your view becomes dependent on SomeViewModel, which might be undesireable. What do you think?
  • Niklas Hoesl
    Niklas Hoesl over 8 years
    @MohammadDehghan: How would you implement this using Caliburn?
  • rollsch
    rollsch over 7 years
    Very clear answer. Are there any alternatives whilst staying in the MVVM pattern?
  • Alejandro
    Alejandro over 7 years
    @heltonbiker Why is that undesirable? The view always knows the viewmodel (remember that all bindings refer to viewmodel's properties) and adding one more direct dependency doesn't hurts in any other way. What is "forbidden" is the viewmodel knowing the view directly.
  • heltonbiker
    heltonbiker over 7 years
    @Alejandro I didn't mean it's forbidden, just that it might be undesireable. For example if you have a View in a UserControl library, you might want to use the same view in other projects. I have been using dependency inversion for that lately, so that I have DataContext as ISomeInterface, or else DataContext as SomeAbstractClass and then I can pass different working implementations. The important thing is to judge if the view is intended for reuse, and if so, avoid coupling it to a specific viewmodel implementation, IMO.
  • Alejandro
    Alejandro over 7 years
    @heltonbiker That's true, but still not a bad practice. It's quite common to have binding of the form Text={Binding SomeText}, where SomeText is a viewmodel property, meaning the view already knows the viewmodel, or at the very least an interface of it. Then casting explictly to a concrete class or an interface is pretty much the same. Casting to one or another depends on your specific case, but the point is, the view knows the viewmodel.
  • heltonbiker
    heltonbiker over 7 years
    @Alejandro Binding creates a very weak coupling, since they are "Stringly Typed". Its the type dependency I think should be avoided if the View is intended for reuse (that is, intended to have different possible viewmodels as datacontext). In you example, usually the View knows only property names, not the actual type of the DataContext, and much less depends on such type.
  • Admin
    Admin over 6 years
    BomView = SomeViewClass. the Name of View Class.