내용 보기

작성자

관리자 (IP : 172.17.0.1)

날짜

2020-07-10 04:32

제목

[WPF] 10 things you might have missed about mvvm light


10 things you might have missed about mvvm light

Ever since I started playing with XAML based technologies (which actually isn’t that long ago) I’ve been looking into the MVVM (Model ? View ? ViewModel) pattern. I stumbled across MVVM Light pretty soon and liked the way it worked. Turns out I’m not the only one that likes it, there’s a whole set of developers, both hobby and professional, that really love this set of libraries. MVVM Light is, according to the author, not a framework but a set of libraries that take care of the plumbing to set up an MVVM structure and provide some extra helper classes to make life easier.

MVVM Light has changed a lot in its history, some elements were dragged out, others dragged in. Fact remains that it’s a fast, easy to use and lightweight framework. The author, Laurent Bugnion, does a great job of listening to the people that use MVVM Light, incorporating requested features and helping developers out. While talking to some of my fellow developers I’ve noticed a few times that there are certain elements of MVVM Light that others hadn’t heard of, and the same goes in the other direction. I’ve learned a lot of new things about MVVM Light just from talking with other users. Thinking about that gave me the idea of this blogpost and since those “10 things about…” posts seem to be popular, this was my chance. So here are my top 10 hidden gems of MVVM Light that you might have missed.

1. The MVVM Light installer

This one might seem a bit obvious, but in this NuGet driven world we would forget the added benefit of an installer. MVVM Light has an MSI installer that not only installs the binaries on your drive but it also provides project and itemtemplates in Visual Studio, along with a list of snippets. In case the Visual Studio 2012 update 2 removed your templates, reinstall the VSIX from C:\Program Files (x86)\Laurent Bugnion (GalaSoft)\Mvvm Light Toolkit\Vsix that should put the project templates back in place.

2. Constructor injection

This one is just awesome, and is actually a feature that can be found in most DI frameworks. MVVM Light uses SimpleIoc to register viewmodels and service classes at application launch (or during the app lifetime). Constructor injection means that you can specify a parameter in a class his constructor. When that class gets instantiated SimpleIoc will try to find a registered class of the same type as the parameter, when it finds one, that instance will get injected as the parameter of the constructor. Here’s an example, let’s say that in the ViewModelLocator, we register a navigation service.

Code Snippet
  1. SimpleIoc.Default.Register<INavigationServiceNavigationService>();

We state here that we want to register an INavigationService in the IOC container, when it creates the instance we want it to be of type NavigationService. This “record” in the IOC container doesn’t have an instance yet, it gets instantiated when we fetch it from the container the first time. There are some occasions where you would want to create an instance of a class immediately when it gets registered. the Register<T> function of SimpleIoc has an overload to do just that.

Code Snippet
  1. SimpleIoc.Default.Register<INavigationServiceNavigationService>(true);

Just pass in true as a parameter and it will create an instance right there and then.

Now we want to use the NavigationService in the MainViewModel.

Code Snippet
  1. ///<summary>
  2. /// Initializes a new instance of the MainViewModel class.
  3. ///</summary>
  4. public MainViewModel(INavigationService navigationService)
  5. {
  6.     
  7. }

SimpleIoc will search for a registered class of type INavigationService and will inject it in this constructor. This saves us the hassle of manually contacting the IOC container and requesting the correct instance.

WARNING: do be careful with this, the order in which you register your classes with the IOC container can be important, especially when using the overload to create instances. If I would create the MainViewModel before the NavigationService is registered I would get a nullreference exception. So be aware of that.

3. SimpleIoc to simple? replace it!

The SimpleIoc library works great and is a cool, lightweight addition to MVVM Light, but it is actually really lightweight. It is a very realistic scenario that for larger apps the SimpleIoc just won’t do (or you’re like me and want to try out how hard it is to replace it with another one). In this example I’m going to replace SimpleIoc with AutoFac, another well known and very powerful IOC service.

First of all, we’re going to need the AutoFac libraries and the extra library that allows us to use the ServiceLocator, just like SimpleIoc does. So either from the package manager console or from the UI, add the CommonServiceLocator extra for AutoFac, the AutoFac libraries are a dependency so they’ll get installed as well. I’m using a brand new Windows Phone 8 project for this, started from the MVVM Light project template.

Code Snippet
  1. Install-Package Autofac.Extras.CommonServiceLocator

The only place we’ll need to change some code is in the ViewModelLocator.

This is the new ViewModelLocator constructor, I’ve put the old SimpleIoc code in comments so it’s easy to compare

Code Snippet
  1. static ViewModelLocator()
  2. {
  3.     var container = newContainerBuilder();
  4.  
  5.     //ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
  6.     ServiceLocator.SetLocatorProvider(() => newAutofacServiceLocator(container.Build()));
  7.  
  8.     if (ViewModelBase.IsInDesignModeStatic)
  9.     {
  10.         //SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
  11.         container.RegisterType<Design.DesignDataService>().As<IDataService>();
  12.     }
  13.     else
  14.     {
  15.         //SimpleIoc.Default.Register<IDataService, DataService>();
  16.         container.RegisterType<DataService>().As<IDataService>();
  17.     }
  18.  
  19.     //SimpleIoc.Default.Register<MainViewModel>();
  20.     container.RegisterType<MainViewModel>();
  21. }

And that’s it, we declare a ContainerBuilder, set it as the LocatorProvider. The container is then used to register everything we need. The SimpleIoc overload that creates an instance upon registering would look something like this in AutoFac.

Code Snippet
  1. container.RegisterInstance(newDataService()).As<IDataService>();

That’s it, constructor injection should still work exactly like before with SimpleIoc.

4. Built-in messages

MVVM Light has something called the messenger, it registers classes as listeners and can send messages to them. This is commonly used to do communication between viewmodels. Generally I would create a message class for each type of message that I want to send, but MVVM Light has some build in messages that we can use.

GenericMessage<T>(T content) A message that can contain whatever of type T.

Code Snippet
  1. Messenger.Default.Send(newGenericMessage<string>("my message"));
NotificationMessage(string notification)a message that contains a notification. this might be
used to send a notification to a notification factory that will show the message in the preferred way.
Code Snippet
  1. try
  2. {
  3.     //try something
  4. }
  5. catch (Exception ex)
  6. {
  7.     Messenger.Default.Send(newNotificationMessage(ex.Message));
  8. }

There’s also a NotificationMessage<T>(T notification) should you need it.

The next one is NotificationMessageAction(string notification, Action callback) basically the same as the NotificationMessage but you can add a callback action that will fire once the message is received. This one also has the generic implementation just like NotificationMessage.

DialogMessage(string content, Action<MessageBoxResult> callback) 
This message is meant to ask the user to input something and it will return the result of that input in the
MessageBoxResult. MessageBoxResult is an enum that lives in System.Windows
Code Snippet
  1. publicenumMessageBoxResult
  2. {
  3.   None = 0,
  4.   OK = 1,
  5.   Cancel = 2,
  6.   Yes = 6,
  7.   No = 7,
  8. }

 

Code Snippet
  1. Messenger.Default.Send(newDialogMessage("Are you sure?", result =>
  2.     {
  3.         if (result == MessageBoxResult.Yes)
  4.         {
  5.             //do something
  6.         }
  7.     }));

The DialogMessage class inherits from GenericMessage<string>

PropertyChangedMessage(T oldValue, T newValue, string propertyName)
The PropertyChangedMessage is meant to use like the RaisePropertyChanged implementation. This is great when multiple
viewmodels need to respond to a changed property.
Code Snippet
  1. publicstring WelcomeTitle
  2. {
  3.     get
  4.     {
  5.         return _welcomeTitle;
  6.     }
  7.  
  8.     set
  9.     {
  10.         if (_welcomeTitle == value)
  11.         {
  12.             return;
  13.         }
  14.  
  15.         Messenger.Default.Send(newPropertyChangedMessage<string>(_welcomeTitle, value"WelcomeTitle"));
  16.  
  17.         _welcomeTitle = value;
  18.         RaisePropertyChanged(WelcomeTitlePropertyName);
  19.     }
  20. }

Be careful when registering listeners, try to use as many different types of messages as makes sense. You don’t want a wrong listener to receive a message because it happens to listen to the same type of message. To register a listener do this:

Code Snippet
  1. Messenger.Default.Register<PropertyChangedMessage<string>>(this, message =>
  2.     {
  3.         var a = message.NewValue;
  4.         //do something
  5.     } );

5. Portable libraries

MVVM Light is available on every XAML based platform. And it comes with a portable version now. The portable version is a separate library on NuGet.

Code Snippet
  1. Install-Package Portable.MvvmLightLibs

If you decide to use the portable version, make sure that every project in your solution that needs the MVVM Light libraries references the portable version. It does not work together with the “normal” MVVM Light libraries. When you use the PCL version, you can put your viewmodels in a separate, portable library and share them over, for example, a Windows Store and a Windows Phone app.

6. Event to Command behavior

MVVM Light has an ICommand implementation called RelayCommand that can be used to bind commands to actions. Like for example a button in XAML has a Command property that can be bound to an ICommand on its datacontext, so that when the button is clicked the ICommand will fire. Unfortunately not every XAML UI element has a bindable command property for every event that they can trigger and that’s where EventToCommand comes into play. With EventToCommand you can bind any event from a XAML UI element to an ICommand in the viewmodel.

First we’ll need two namespaces in our XAML page

Code Snippet
  1. xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
  2. xmlns:command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WP8"

Let’s say that we want to use the Tap event on a stackpanel.

Code Snippet
  1. <StackPanel Grid.Row="0" Orientation="Horizontal">
  2.     <i:Interaction.Triggers>
  3.         <i:EventTrigger EventName="Tap">
  4.             <command:EventToCommand Command="{Binding GoToCommand}" CommandParameter="Edit" />
  5.         </i:EventTrigger>
  6.     </i:Interaction.Triggers>

Line 3 specifies the event that we want to handle, note that this is a string so be aware of typos. Line 4 binds the actual command and can even pass a parameter to the ICommand implementation.

Code Snippet
  1. privateRelayCommand<string> _goToCommand;
  2. publicRelayCommand<string> GoToCommand
  3. {
  4.     get { return _goToCommand jQuery15206875578026641675_1366095632942 (_goToCommand = newRelayCommand<string>(NavigateAway)); }
  5. }

The NavigateAway method has this signature

Code Snippet
  1. privatevoid NavigateAway(string parameter)

The parameter will be the word “Edit” in this case as that’s what we’ve specified in the XAML. We can even pass the eventargs from the event to the Command by changing line 4 from the XAML snippet to this

Code Snippet
  1. <command:EventToCommand PassEventArgsToCommand="True" Command="{Binding GoToCommand}" />

Windows Store applications don’t have these behaviors out of the box so you won’t be able to use EventToCommand there unless you install the Win8nl toolkit from NuGet. Joost Van Schaik has build his own implementation of behaviors in WinRT and thanks to his efforts (and of some other people that have helped in the project) we can now use EventToCommand in WinRT.

7. DispatcherHelper

Since .net 4.5 we have the await/async keywords and being the good little citizens that we are we do a lot of stuff async now. That means if we want to update something that lives on the UI thread we’ll need the Dispatcher class to marshall our action to that thread. Normally we don’t have access to the Dispatcher from our viewmodel classes. MVVM Light contains a DispatcherHelper that will execute an action on the UI thread when needed.

Code Snippet
  1. DispatcherHelper.CheckBeginInvokeOnUI(() =>
  2.     {
  3.         //do something
  4.     });

The DispatcherHelper gets initialized in the App.xaml.cs in the InitializePhoneApplication method (in a WP8 project that is).

DispatcherHelper also has a RunAsync method. The difference with the CheckBeginInvokeOnUI is that the CheckBeginInvokeOnUI will first check if it’s already on the UI thread, if it is it will just execute the action, if it isn’t it will call the RunAsync method.

8. Blendable

MVVM Light has complete Blend support, meaning you can drag and drop properties from the viewmodel onto the view to generate a binding, or you can generate design time data based on the datacontext and so on. I’m really not that good in Blend so I’m not going into detail about this one, just remember that MVVM Light was build with Blend in mind.

9. Open Source

This one you probably knew but MVVM Light is completely open source. http://mvvmlight.codeplex.com/ is the place to be if you want to dive into the source code.

10. Laurent is on Twitter and he’s a nice guy Glimlach

Laurent Bugnion, the founder of MVVM Light, is on Twitter! https://twitter.com/LBugnion he’s a great guy to chat with and very eager to help out anyone who needs help.

 

Conclusion

MVVM Light is a great library with a few hidden gems. In this article I’ve discussed 8 very interesting ones that can make your life as a developer easier. I’ve included two more extra items because 10 is a prettier number than 8

출처1

http://www.spikie.be/post/2013/04/12/10-things-you-might-have-missed-about-mvvm-light.html

출처2