What is the alternative to allowing key instances with Simple Injector for the WPF window broker service?

Looking at the “ Allow instances by key ” section of the Simple Injector website section, I played with the proposed IRequestHandlerFactory implementations to improve the code below, but notes like:

Note. The need to register with a key can be a sign of ambiguity in the design of the application and a sign of a violation of the Liskov replacement principle. Look carefully if each registered registration should not have its own unique interface, or perhaps each registration should implement its own version of the universal interface.

and

Note. Please remember the previous note on the ambiguity of the design of the application. In this example, the design is likely to be better using the common IRequestHandler <TRequest> interface. This would allow you to register parties using a single line of code, save you from using keys and lead to a configuration that can be checked by the container.

I am curious.

Q : how would my real implementation be detected in a real note (IRequestHandler <TRequest>)? I spent some time trying to figure out what it could be, but I can't come up with a way that works.

What i have now

, , MVVMLight Messenger Windows .

IWindowResolver, factory ( ), Simple Injector factory .

RegisterViewHandler , , (, HandleEmailPopupMessage , , HandleEmailPopupMessage, ). , IWindowResolver , , , , .

- - IRequestHandler <TRequest> / / factory, Doco Simple Injector, tidyup?

// Current IWindowResolver
interface IWindowResolver
{
   Window CreateWindow<TWindow>(TWindow windowType) where TWindow : class;
}

// Current Simple Injector IWindowResolver implementation
[UsedImplicitly]
private sealed class SimpleInjectorWindowFactory : IWindowFactory
{
   private readonly Container _container;

   public SimpleInjectorWindowFactory(Container container)
   {
      _container = container;
   }

   public Window CreateWindow<TWindow>(TWindow windowType) where TWindow : class
   {
      return _container.GetInstance<TWindow>() as Window;
   }
}

public class ShowEmailPopupFormMessage
{
   public ShowEmailPopupFormMessage()
   {
      Params = new ParamsMessage();
   }

   public class ParamsMessage
   {
      public string CustomerName { get; set; }
      public string EmailTo { get; set; }
   }

   public ParamsMessage Params { get; set; }
}

// Current ViewConstructor
class ViewConstructor
{
   IWindowResolver _windowResolver;
   Dictionary<Type, Type> _viewMap = new Dictionary<Type, Type>(); // Maps a message type to a particular window/view type

   public ViewConstructor(IWindowResolver windowResolver)
   {
      _windowResolver = windowResolver;
      RegisterViewHandler<ShowEmailPopupFormMessage, EmailPopupWindow>(HandleEmailPopupMessage);
   }

   private void RegisterViewHandler<TMessage, TWindow>(Action<TMessage> messageAction)
      where TMessage : class
      where TWindow : Window
   {
      if (_viewMap.ContainsKey(typeof(TMessage)))
      {
         throw new ArgumentException("View already registered");
      }

      // Store the map of Message type to Window type
      _viewMap[typeof(TMessage)] = typeof(TWindow);

      // Register with the message handler
      Messenger.Default.Register(this, messageAction);
   }

   private void HandleEmailPopupMessage(ShowEmailPopupFormMessage msg)
   {
      var frm = GetMappedWindow(msg.GetType());

      // We know that the View and it associated ViewModel are now created
      // so we can send some initialization parameters to the view and or ViewModel
      Messenger.Send(msg.Params);

      frm.ShowDialog();
   }

   private Window GetMappedWindow<TMessage>(TMessage messageType)
   {
      var windowType = _viewMap[typeof(TMessage)];

      var frm = _windowResolver.CreateWindow(windowType);

      if (frm == null)
      {
         throw new ApplicationException("Window is not of the specified Type!");
      }

      // Hookup common events such as cleanup events
      frm.Unloaded += FormOnUnloaded;

      return frm;
   }

   private static void FormOnUnloaded(object sender, RoutedEventArgs eArgs)
   {
      var frm = sender as Window;

      if (frm == null)
      {
         return;
      }

      // Cleanup the ViewModel 
      var dataContext = frm.DataContext as ICleanup;

      if (dataContext != null)
      {
         dataContext.Cleanup();
      }
   }
}

public class EmailPopupWindow : Window
{
   // Window knows how to set it datacontext ViewModel (in this case EmailPopupVm) using the ViewModelLocator declared in XML.
   // The window does not handle any messages.
}

// The View Model for the EmailPopupWindow. ViewModelBase is from MVVMLight
public class EmailPopupVm : ViewModelBase
{
   public EmailPopupVm()
   {
      Messenger.Register<ShowEmailPopupFormMessage.ParamsMessage>(HandleParamsMessage);
   }

   private void HandleParamsMessage(ShowEmailPopupFormMessage.ParamsMessage msg)
   {
      // Initialize the ViewModel with the parameters
      this.CustomerName = msg.CustomerName;
      this.EmailTo = msg.EmailTo;
   }
}

ViewModel ( ) ShowEmailPopupFormMessage.ParamsMessage. - .

+4
1

-, , . , , .

, , ; IMessageHandler<TMessage>:

public interface IMessageHandler<TMessage>
{
    void Handle(TMessage message);
}

, , . , :

public interface IWindow<TMessage>
{
    void ShowDialog();
}

, , , ( MVVMLight, ):

public interface IMessageDispatcher
{
    void Dispatch(object message);
}

IMessageHandler<TMessage>, , ShowEmailPopupFormMessage:

public class ShowEmailPopupFormMessageHandler : IMessageHandler<ShowEmailPopupFormMessage>
{
    private readonly IWindow<ShowEmailPopupFormMessage> frm;
    public ShowEmailPopupFormMessageHandler(IWindow<ShowEmailPopupFormMessage> frm) {
        this.frm = frm;
    }

    public void Handle(ShowEmailPopupFormMessage message) {
        Messenger.Send(msg.Params);
        frm.ShowDialog();
    }
}

EmailPopupWindow ShowEmailPopupFormMessage, IWindow<ShowEmailPopupFormMessage>:

public class EmailPopupWindow : Window, IWindow<ShowEmailPopupFormMessage>
{
    // window stuff here
}

, , :

// Composition Root
container.Register(typeof(IWindow<>), applicationAssemblies);
container.Register(typeof(IMessageHandler<>), applicationAssemblies);
container.RegisterSingleton<IMessageDispatcher>(
    new SimpleInjectorMessageDispatcher(container));
container.RegisterInitializer<Window>(frm => {
    frm.Unloaded += FormOnUnloaded;
});

, IWindow<T> IMessageHandler<T> . , Window.Unload .

SimpleInjectorMessageDispatcher :

private sealed class SimpleInjectorMessageDispatcher : IMessageDispatcher
{
    private readonly Container container;
    public SimpleInjectorMessageDispatcher(Container container) {
        this.container = container;
    }

    public void Dispatch(object message) {
        Type handlerType = typeof(IMessageHandler<>).MakeGenericType(message.GetType());
        dynamic handler = this.container.GetInstance(handlerType);
        handler.Handle((dynamic)message);
    }
}

, ( ), , , , , . , , , ( ) . ; SOLID. ( ).

+2

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


All Articles