0

I've following architecture: desktop application, .Net 4.5, C#, WPF, MVVM Light, Messenger, IoC - ViewModel locator, so ViewModels doen't know anyhing about Views.

I have main view with data grid of some elements, and I want to display details of each individual element in new/child windows after double click on data grid.

I've bind event double click on main view to main view model. From this event handler in main view model, message is sent via Messanger.

New view (new/child window) is created in main view via delegate of also double click.

New/child window is a view which locate his view model and this view model register to the specific message in his constructor.

The problem is that new/child window (new view, and view model so on) is created too late, because message is already sent when new view model register for it.

Do you know maybe some patterns for such architecture. Any ideas will be appreciated.

catcher
  • 101
  • 1
  • 5
  • possible duplicate of [Best Way to Pass Data to new ViewModel when it is initiated](http://stackoverflow.com/questions/18497991/best-way-to-pass-data-to-new-viewmodel-when-it-is-initiated/18521197#18521197) – Ian Flynn Jan 22 '14 at 23:40
  • WP7Contrib has such an implementation called [LastMessageReplayMessenger](http://wp7contrib.codeplex.com/SourceControl/latest#7.0/WP7Contrib.Messaging/LastMessageReplayMessenger.cs). The codes can be used in WPF, but the .dll in codeplex was built for WP only. Find blog post about LastMessageReplayMessenger [here](http://blogs.xamlninja.com/xaml/wp7-contrib-the-last-messenger) – har07 Jan 23 '14 at 04:44

2 Answers2

0

It would help to know exactly what you try to do.

If your problem is just to display a detailed Window when double click on a row, I would say: create only one childWindow at start, and play with its visbility when required.

If you really need a new window each time, you could create it from your viewModel with an injected service for example.

In any case, you never has to create your window from main view! Either you create one window at start, either you dynamically create it from view model.

You cannot hope to create it from view and send the message in your view model.

Edit about the injected service, you could use something like that:

   public interface IWindowService
   {
    void Open<TWindow>(ViewModelBase viewModel)
        where TWindow : Window;
   }

    public class WindowService : IWindowService
    {
        private readonly IUIDispatcher _dispatcher;

        public WindowService(IUIDispatcher dispatcher)
        {
            _dispatcher = dispatcher;
        }

        public void Open<TWindow>(ViewModelBase viewModel)
            where TWindow : Window
        {
            _dispatcher.Run(() => OpenThreadSafe<TWindow>(viewModel));
        }

        private static void OpenThreadSafe<TWindow>(ViewModelBase viewModel) where TWindow : Window
        {
            var view = (TWindow) Activator.CreateInstance(typeof(TWindow), viewModel);
            view.Show();
        }
    }

public class UIDispatcher : IUIDispatcher
{
    public void Run(Action action)
    {
        var dispatcher = DispatcherHelper.UIDispatcher;
        if (dispatcher == null)
        {
            action();
            return;
        }

        DispatcherHelper.CheckBeginInvokeOnUI(action);
    }

Note this DispatcherHelper come from MVVMlight, but you could erplace it easily.

Hope it helps.

Ouarzy
  • 3,015
  • 1
  • 16
  • 19
  • Thanks. I need to create and open new window each time dblclick on new (not dblcliked yet) row on data grid... and when dblclick on the same row again (when already have opened window) coresponding window should popup. Could you add more details about the injected service. – catcher Jan 25 '14 at 19:23
  • Edit for more details about the injected service – Ouarzy Jan 29 '14 at 08:41
0

The problem is that the ViewModel Locator creates the viewmodel instance only when it is needed (lazy loading).

just configure the ViewModelLocator to instantiate the viewmodel eager instead of lazy. This is done by passing the parameter "true" to the IoC Container.

Sample:

namespace Administration.ViewModel
{
    public class ViewModelLocator
    {
        public ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            //Eager Loading
            SimpleIoc.Default.Register<UserManagementViewModel>(true);

            //Lazy Loading
            SimpleIoc.Default.Register<InformationManagementViewModel>();
        }

        public UserManagementViewModel UserManagementViewModel
        {
            get
            {
                return ServiceLocator.Current.GetInstance<UserManagementViewModel>();
            }
        }

        public InformationManagementViewModel InformationManagementViewModel
        {
            get
            {
                return ServiceLocator.Current.GetInstance<InformationManagementViewModel>();
            }
        }

        public static void Cleanup()
        {
            SimpleIoc.Default.Unregister<UserManagementViewModel>();
            SimpleIoc.Default.Unregister<InformationManagementViewModel>();
        }
    }
}
Joel
  • 4,862
  • 7
  • 46
  • 71