Unity & WPF - Injecting a DataContext by Inserting Properties into a Child Control

I followed the example of Jason Dollinger MVVM from Lab49 to learn the basics of using Unity with the MVVM MVVM application. I built a simple pattern, following its basic architecture, using property injection and the Dependency attribute to embed viewmodels in the views. In my example, there is a main window with a child user control created in the XAML window. The child control (and the main window too) has a property for assigning the viewmodel:

[Dependency] public IChildViewModel VM { set { this.DataContext = value;} } 

I plug everything in app.xaml.cs:

 protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); IUnityContainer container = new UnityContainer(); container.RegisterType<IWindowViewModel, Window1ViewModel>(); container.RegisterType<IChildViewModel, UserControl1ViewModel>(); Window1 window = container.Resolve<Window1>(); window.Show(); } 

In the main window, its viewmodel is entered, but the child control is not. Is there any direct way to extend permission to child controls? What architectural changes do I need to do to do this? At the moment I am not tied to Unity, so I can switch to another container if this behavior is supported.

+4
source share
4 answers

If I matched the models of my child view that will belong and set as properties in the viewmodel, and then set the DataContext of the user controls in XAML to the corresponding property, I can remove the property associated with the dependency on the child of the entire code. However, this creates a kind of awkward window. and I'm not quite happy with that. I based this approach on this related issue .

0
source

The answer depends on whether the main windows are "child" child windows like Composite View or creates new views on the fly (for modal or modeless child windows).

In the first case, the main ViewModel must own the child ViewModels directly, which means that you can implement the child ViewModels as read-only properties on the main ViewModel and use data binding to bind the child views to the corresponding properties.

If you want the main ViewModel control to directly create child elements or inject them into it using the Injection constructor , it depends on the degree of variability that you need.

As always, if you need to create new instances of child views at arbitrary points in time, the introduced Abstract Factory can be used as the best model.


As an example, I often define and embed this interface into the ones I need in ViewModels:

 public interface IWindow { void Close(); IWindow CreateChild(object viewModel); void Show(); bool? ShowDialog(); } 

This allows the ViewModel to create new windows and display them (for example, in the form of dialogs). A simple implementation is as follows:

 public class WindowAdapter : IWindow { private readonly Window window; public WindowAdapter(Window window) { if (window == null) { throw new ArgumentNullException("window"); } this.window = window; } #region IWindow Members public void Close() { this.window.Close(); } public IWindow CreateChild(object viewModel) { var cw = new ContentWindow(); cw.Owner = this.window; cw.WindowStartupLocation = WindowStartupLocation.CenterOwner; cw.DataContext = viewModel; return cw; } public void Show() { this.window.Show(); } public bool? ShowDialog() { return this.window.ShowDialog(); } #endregion } 
+4
source

There are two ways to do this. The following code snippet should clarify it.

  //creating Container IUnityContainer _container = new UnityContainer(); //Data Source TasksListViewModel _tasksSource = new TasksListViewModel(); //My Data Source _container.RegisterInstance<TasksListViewModel>(_tasksSource); //Registering it //Resolve Window Window1 window = _container.Resolve<Window1>(); //Answer to your question: Inject ViewModel into the View (User control) //Two ways: //1. Using Build (assuming View IS already added to the main window with the name "myView") _container.BuildUp(typeof(TasksListView), window.FindName("myView")); //---- OR ---- //2. Adding the view to the grid (assuming View IS NOT already added to the main window) //Resolve View //TasksListView view = _container.Resolve<TasksListView>(); //Make sure you have grid (content control) named LayoutRoot //window.LayoutRoot.Children.Add(view); //Add it to the Main Window grid (LayoutRoot) window.Show(); 
+2
source

I also struggled with the concept of putting a DataContext into my views (UserControls).
Does the idea of โ€‹โ€‹exposing view models for children using the main window view model have a limited appeal?

The following idea works, but you get negative feedback from the Visual Studio IDE.

My App.xaml.cs looks like this:

 protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); UnityContainer unityContainer = new UnityContainer(); this.Properties["UnityContainer"] = unityContainer; unityContainer.LoadConfiguration(); unityContainer.Resolve<MainWindow>().Show(); } public static IUnityContainer UnityContainer { get { return (IUnityContainer)App.Current.Properties["UnityContainer"]; } } 

I registered my containers in App.config, but this is just a personal choice.

In my user control code, I have the following:

 protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); this.DataContext = App.UnityContainer.Resolve<MyViewModel>(); } 

In the above example, MyViewModel is not registered and does not have an interface.

As I said above, it works for me, but the IDE complains about the impossibility of creating an instance of a user control. However, if you run the application, it works great.

+1
source

Source: https://habr.com/ru/post/1300803/


All Articles