0
votes

hi i am trying to instantiate view through viewmodel in prism with no luck. The window is shown but none of the module regions are updated.

Please see code snippet below:

 public class Bootstrapper : UnityBootstrapper
    {
        private ShellViewModel shellViewModel;

        protected override DependencyObject CreateShell()
        {
            // register shell types
            var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
            container.RegisterType<IShellView, ShellWindow>("ShellView");
            container.RegisterType<Object, ShellViewModel>("ShellViewModel");
            shellViewModel = container.Resolve<ShellViewModel>();
            this.Shell = shellViewModel.View as DependencyObject;
            return this.Shell;
            //return new ShellWindow();

        }
...

And the view model is defined as follows

 public class ShellViewModel : ViewModelBase<IShellView>
    {
        public ShellViewModel([Dependency("ShellView")]IShellView view)
            : base(view)
        {
        }
    }

 public interface IShellView : IView
    {
        void ShowMessageInOutputWindow(string message);
    }

 /// <summary>
    /// Abstract base class for a ViewModel implementation.
    /// </summary>
    /// <typeparam name="TView">The type of the view. Do provide an interface as type and not the concrete type itself.</typeparam>
    public abstract class ViewModelBase<TView> : ViewBase where TView : IView
    {
        /// <summary>
        /// The view.
        /// </summary>
        private readonly TView view;

        /// <summary>
        /// Initializes a new instance of the <see cref="ViewModel&lt;TView&gt;"/> class and
        /// attaches itself as <c>DataContext</c> to the view.
        /// </summary>
        /// <param name="view">The view.</param>
        protected ViewModelBase(TView view)
            : base(view)
        {
            this.view = view;
        }

        /// <summary>
        /// Gets the associated view as specified view type.
        /// </summary>
        /// <remarks>
        /// Use this property in a ViewModel class to avoid casting.
        /// </remarks>
        public TView View
        {
            get { return this.view; }
        }
    }

using System; using System.ComponentModel; using System.Threading; using System.Windows.Threading;

/// /// Base class for all view models /// public abstract class ViewBase : INotifyPropertyChanging, INotifyPropertyChanged { /// /// The view. /// private readonly IView view;

/// <summary>
/// Initializes a new instance of the <see cref="ViewModelBase"/> class and
/// attaches itself as <c>DataContext</c> to the view.
/// </summary>
/// <param name="view">The view.</param>
protected ViewBase(IView view)
{
    if (view == null)
    {
        throw new ArgumentNullException("view");
    }

    this.view = view;

    // Check if the code is running within the WPF application model
    if (SynchronizationContext.Current is DispatcherSynchronizationContext)
    {
        // Set DataContext of the view has to be delayed so that the ViewModel can initialize the internal data (e.g. Commands)
        // before the view starts with DataBinding.
        Dispatcher.CurrentDispatcher.BeginInvoke((Action)delegate
        {
            this.view.DataContext = this;
        });
    }
    else
    {
        // When the code runs outside of the WPF application model then we set the DataContext immediately.
        this.view.DataContext = this;
    }
}

#region INotifyPropertyChanging Members

public event PropertyChangingEventHandler PropertyChanging;

#endregion

#region INotifyPropertyChanged Members

public event PropertyChangedEventHandler PropertyChanged;

#endregion

#region Administrative Properties

/// <summary>
/// Whether the view model should ignore property-change events.
/// </summary>
public virtual bool IgnorePropertyChangeEvents { get; set; }

#endregion

#region Public Methods

/// <summary>
/// Raises the PropertyChanged event.
/// </summary>
/// <param name="propertyName">The name of the changed property.</param>
public virtual void RaisePropertyChangedEvent(string propertyName)
{
    // Exit if changes ignored
    if (IgnorePropertyChangeEvents) return;

    // Exit if no subscribers
    if (PropertyChanged == null) return;

    // Raise event
    var e = new PropertyChangedEventArgs(propertyName);
    PropertyChanged(this, e);
}

/// <summary>
/// Raises the PropertyChanging event.
/// </summary>
/// <param name="propertyName">The name of the changing property.</param>
public virtual void RaisePropertyChangingEvent(string propertyName)
{
    // Exit if changes ignored
    if (IgnorePropertyChangeEvents) return;

    // Exit if no subscribers
    if (PropertyChanging == null) return;

    // Raise event
    var e = new PropertyChangingEventArgs(propertyName);
    PropertyChanging(this, e);
}

}

#endregion


/// <summary>
    /// Represents a view
    /// </summary>
    public interface IView
    {
        /// <summary>
        /// Gets or sets the data context of the view.
        /// </summary>
        object DataContext { get; set; }

        /// <summary>
        /// Initializes the view
        /// </summary>
        void Initialize();
    }
2
With MVVM the ViewModel doesn't know of any View. And with DI only the composition root knows of an IoC Container. You're not showing where the View's DataContext is assigned, I'm assuming in ViewModelBase<> - I did that recently, and I ended up flipping it around (i.e. inject ViewModel into View instead), because the IoC container was calling view's constructor and was getting a View without a ViewModel, which seems to be your issue?Mathieu Guindon

2 Answers

0
votes

Doing this works though but i don't see the difference.

ShellWindow view = new ShellWindow();
            ShellViewModel viewModel = new ShellViewModel(view);
            return viewModel.View as DependencyObject;
0
votes

When you register a type in the UnityContainer using a name, you have to also resolve it by specifying that name. You also have to resolve using the type that you registered with.

container.RegisterType<Object, ShellViewModel>("ShellViewModel");
shellViewModel = container.Resolve<Object>("ShellViewModel") as ShellViewModel;

You also should define an interface for the ShellViewModel class, and register/resolve using that interface.

public interface ShellViewModel
{
}

Your bootstrapper would then look like this:

public class Bootstrapper : UnityBootstrapper
{
    private IShellViewModel shellViewModel;

    protected override DependencyObject CreateShell()
    {
        // register shell types
        var container = ServiceLocator.Current.GetInstance<IUnityContainer>();
        container.RegisterType<IShellView, ShellWindow>("ShellView");
        container.RegisterType<IShellViewModel, ShellViewModel>("ShellViewModel");
        shellViewModel = container.Resolve<IShellViewModel>("ShellViewModel");
        this.Shell = shellViewModel.View as DependencyObject;
        return this.Shell;

    }
}