How can i access a control in mvvm model in viewmodel?
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.
Sanjay Patel
Updated on June 06, 2020Comments
-
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 over 10 yearsIt is better to use constructor injection to send the
IVew
instance toViewModel
(I mean,ViewModel
class' constructor should accept anIView
instance). -
heltonbiker about 9 yearsIt 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 onSomeViewModel
, which might be undesireable. What do you think? -
Niklas Hoesl over 8 years@MohammadDehghan: How would you implement this using Caliburn?
-
rollsch over 7 yearsVery clear answer. Are there any alternatives whilst staying in the MVVM pattern?
-
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 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 elseDataContext 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 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}
, whereSomeText
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 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 over 6 yearsBomView = SomeViewClass. the Name of View Class.