Emuforums.com

Go Back   Emuforums.com > General Discussion > Web development / Programming
Home Register Downloads FAQ Members List Calendar Arcade Mark Forums Read

WON'T YOU JOIN US?
You are not a registered member and
are viewing this site as a guest.
Registration is simple and FREE.
Join this CrowdGather community today.
Registration offers the following perks:

» Less advertising throughout
» Post and participate in discussions
» Network with other forum members
» Free private messaging

join

 
 
Thread Tools Display Modes
Prev Previous Post   Next Post Next
Old February 22nd, 2012, 23:11   #1
@ruantec
Crazy GFX coder
 
@ruantec's Avatar
 
Join Date: Nov 2002
Location: Dominican Republic/Austria
Posts: 8,106
MVVM coding pattern and global Exception handling Tutorial

After chatting with some developers i got asked to post a tutorial here in order to explain a bit how MVVM actally works and why it works. MVVM can be used in C#, WPF, C++(Qt) and Java(eFACE). Since am short in time this days i'll try to write some posts later explaining more about t.

MVVM is basically the "art" of separating your code from the UI so that your code have no idea about your UI yet can be used on it anytime. Now... what's so great about separating the logic and the UI? quite simple... there are times when things in the UI changed and that is the time a lot of coders spend an incredible amount of time trying to fix broken events or missing UI objects in the code behind after a big facial change. By using proper MVVM coding pattern you totally free your code and because of that you are able to change anything in the UI or in your logic without being affraid of breaking something in your code or just getting insane amounts of errors/exceptions just because something is missed.

Here a small wikipedia explanation:
Quote:
The Model View ViewModel (MVVM) is an architectural pattern used in software engineering that originated from Microsoft as a specialization of the Presentation Model design pattern introduced by Martin Fowler.[1] Largely based on the model–view–controller pattern (MVC), MVVM is targeted at modern UI development platforms (HTML5 [2][3], Windows Presentation Foundation or WPF, and Silverlight) in which there is a user experience (i.e., user interface) (UXi) developer who has requirements different from those of a more “traditional” developer (e.g. oriented toward business logic and back end development). The View-Model of MVVM is a value converter[4] meaning that the View-Model is responsible for exposing the data objects from the Model in such a way that those objects are easily managed and consumed. In this respect, the View-Model is more Model than View, and handles most if not all of the View’s display logic (though the demarcation between what functions are handled by which layer is a subject of ongoing discussion[5] and exploration).

MVVM was designed to make use of specific functions in WPF to facilitate the separation of View layer development from the rest of the pattern by removing virtually all “code-behind” from the View layer.[6] Instead of requiring Interactive Designers to write View code, they can use the native WPF markup language XAML and create bindings to the ViewModel, which is written and maintained by application developers. This separation of roles allows Interactive Designers to focus on UX needs rather than programming or business logic, allowing for the layers of an application to be developed in multiple work streams.
Source

In this tutorial am going to handle 2 big points that may help others to improve there way of coding as also keep there code clean and those 2 points are:

- MVVM(Model View ViewModel)
- Global Exception handling

Part I - MVVM(Model View ViewModel):

The simpliest way to explain how it works is imagine a machine that expects information of any kind by expecting a determined set of properties. if you feed that machine with information and any part of that information matches to the ones expected then only those will work and the rest will just not be used until the administrator decide to add those missed definitions back(hope that is easy enough).

To explain it better am going to use WPF and C# and am going to create a new project(In this case i will use @ES MVVM base project):


As you can notice i've created several sub-projects which is something very common but.... if you look closely you will notice that i create a project for the UI only and another one for the UI logic and both are in separated projects.

Now here is the trick... I create an application which serves as a place holder and load the necessary layers on it on demand:

Main application XAML:
Code:
<Window
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	x:Class="GraFX.Main"
	x:Name="GraFXMain"
	Title="@ES - GraFX 'Gray Moon'"
	MinWidth="706" MinHeight="510" Icon="/GraFX;component/mario.ico">
	<Grid x:Name="LayoutRoot">
        
    </Grid>
</Window>
As you can see apart from a "Grid" there is nothing there... now lets check our codebehind:
Code:
using AES.UI.Main;

namespace GraFX
{
	/// <summary>
	/// Main Window
	/// Here we load plugins, layers, content and skins
	/// </summary>
	public partial class Main
	{
		/// <summary>
		/// Base constructor
		/// </summary>
        public Main()
		{
			InitializeComponent();
		    Content = new UIMain();
		}
	}
}
As you can see there is nothing special here either except for "Content = new UIMain();" which is the code i use to add my main UI control to the grid container. Now lets check the main UI control XAML.
Code:
<UserControl x:Class="AES.UI.Main.UIMainContent"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignWidth="706" d:DesignHeight="510">
    <Grid>
    	<Viewbox Margin="20,39,0,312" HorizontalAlignment="Left">
    		<Grid Height="165" Width="686" HorizontalAlignment="Left">
    			<Label x:Name="UILabelTime" Margin="0,0,0,55" Content="{Binding CurrentTime}" Foreground="WhiteSmoke" FontSize="76" HorizontalAlignment="Left" />
    			<Label x:Name="UILabelTDate" VerticalAlignment="Bottom" Height="80" Content="{Binding CurrentDate}" Foreground="WhiteSmoke" FontSize="35" HorizontalAlignment="Left" />
    		</Grid>
    	</Viewbox>
    </Grid>
</UserControl>
As you can notice there is a lot more here since i have a UI with UI-objects here but what about its codebehind?
Code:
using AES.ViewModels.ViewModels.Main;

namespace AES.UI.Main
{
    /// <summary>
    /// Interaction logic for UIMainContent.xaml
    /// </summary>
    public partial class UIMainContent
    {
        public UIMainContent()
        {
            InitializeComponent();
            DataContext = new UIMainContentViewModel();
        }
    }
}
As you can notice there is nothing special here either. However in the main contructor you will notice something and that is no other than this line: "DataContext = new UIMainContentViewModel();" in this line we actually tell our UI that it should feed itself from the UILMainViewModel class which is the one containing the logic. That process can be swaped anytime and i can define a different class if i wish to and interact with it as long as my bindings are valid. If you check the main UI XAML code you will find things like "Command="{Binding FullscreenCommand}" those are the bindings to use from the class we are feeding the UI if they are valid they will interact, if they aren't then nothing will happen and the coder need to re-bind them if necessary.

Now lets have a close look to our MainViewModel class:
Code:
using System;
using System.Globalization;
using System.ComponentModel;
using System.Windows.Threading;

namespace AES.ViewModels.ViewModels.Main
{
    public class UIMainContentViewModel : INotifyPropertyChanged
    {
        /// <summary>
        /// this is the timer we're going to use to display the current time
        /// </summary>
        private readonly DispatcherTimer timer;
        /// <summary>
        /// Get or Set current time variable
        /// </summary>
        private string currentTime;
        /// <summary>
        /// Get or Set current date variable
        /// </summary>
        private string currentDate;
        /// <summary>
        /// Current time binding property
        /// </summary>
        public string CurrentTime
        {
            get { return currentTime; }
            set { currentTime = value; InvokePropertyChanged("CurrentTime"); }
        }
        /// <summary>
        /// Current date binding property
        /// </summary>
        public string CurrentDate
        {
            get { return currentDate; }
            set { currentDate = value; InvokePropertyChanged("CurrentDate"); }
        }
        /// <summary>
        /// Base constructor
        /// </summary>
        public UIMainContentViewModel()
        {
            //initialize timers
            timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(1000) };
            timer.Tick += TimerTick;
            timer.Start();
        }
        /// <summary>
        /// Timer tick responsible to display the time and date on the main layer
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void TimerTick(object sender, EventArgs e)
        {
            SetTimeAndDate();
        }
        /// <summary>
        /// Set current time and date values
        /// </summary>
        private void SetTimeAndDate()
        {
            CurrentTime = DateTime.Now.ToShortTimeString();
            CurrentDate = string.Format("{0} {1} {2}", DateTime.Now.Day, CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(DateTime.Now.Month), DateTime.Now.Year);
        }
        /// <summary>
        /// Event trigger when a property has changed
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
        /// <summary>
        /// Invoke property name using our trigger
        /// </summary>
        /// <param name="propertyName">Name of the property</param>
        private void InvokePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler changed;
            switch (propertyName)
            {
                default:
                    changed = PropertyChanged;
                    break;
            }
            if (changed != null) changed(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
All i do here is setup the necessary properties and code the logic of my main UI that is going to be ready for use on every UI i feed with it as long as the bindings match my properties. If you have a close look you will notice that i have a constructor, a timer, a dispatcher and a InvokePropertyChanged method which is the one that will trigger the property changed event to update my objects in case they are in use. a very important note here(at least in C#) is the fact that my ViewModel class use the "INotifyPropertyChanged" interface which allows me to notify chages("public class UIMainContentViewModel : INotifyPropertyChanged" at the top).

With that in mind you now can see how it actually works. Basically you change your properties or collections and they are reflected back to the UI by using bindings. While i have to admit that it may sound strange i can garantee you that once you get the idea you will fully understand how it works and why it works

Down sides:

Not every stone that shines may be gold.... that's a fact we all know and just like any other coding patterns there are pros and contras. One of the tipical problems that may rise are when you really need access to a actual object of your UI but since you separated both how in hell are you going to achieve that??? MVVM doesn't prohibits you from using codebehind at all but just avoid it as much as you can... now what to do??? one way to achieve your goal is by using events callbacks from the ViewModel. Since those are event callbacks they an easily be used in your codebehind and if you don't it won't break you code either.

To achieve that goal you start by declaring a event callback:
Code:
/// <summary>
        /// Triggers on settings event
        /// </summary>
        public event PropertyChangedEventHandler OnSettings;
And by using our previously mentioned "InvokePropertyChanged" you invoke the property when necessary so that our codebehind get our callback if it was previously registered.

Here the invoke handling:
Code:
/// <summary>
        /// Invoke property name using our trigger
        /// </summary>
        /// <param name="propertyName">Name of the property</param>
        private void InvokePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler changed;
            switch (propertyName)
            {
                case "OnFullScreen":
                    changed = OnFullScreen;
                    break;
                case "OnSettings":
                    changed = OnSettings;
                    break;
                default:
                    changed = PropertyChanged;
                    break;
            }
            if (changed != null) changed(this, new PropertyChangedEventArgs(propertyName));
        }
And here the callback registration in my codebehind:
Code:
/// <summary>
        /// Base constructor
        /// </summary>
        public UIMain()
        {
            InitializeComponent();
            UILMainViewModel main = new UILMainViewModel();
            main.OnSettings += main_OnSettings;
            DataContext = main;
        }

        void main_OnSettings(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            //Event callback from my ViewModel
        }
By using the callback i can access the UI once again and do whatever i need to do there but keep in mind that you should do the task required and nothing else as dependencies should be avoided in order to keep them separated.


Part II - Global Exception handling:

One of the biggest problems is to handle exceptions in a good way. Ever seen a project full of try-catches? we could say that one should write the code in a good way so that such try-catches in the code aren't needed all the time... While that may be true at a certain level there are areas were something unexpected may happen and your app will sudendly die.

Now what to do??? should a coder write try-catches on every single method written???? obviously that would be ugly and silly at the sametime. also there are times when the coder wants to know what was wrong but don't want the application to die but just to stay in its previous state which is the one before the code that caused the exception was executed.

Now how to achieve that???? recently at work we got the challenge to do exactly that and after a while thinking in a solution something came to my mind that does exactly that(at least in C# and WPF). Every WPF application can have an app.config which is just a XML settings file and i remember that you can set the runtime policy there and one of them is nothing but the "legacyUnhandledExceptionPolicy" which if enabled set a dispatcher to the exception in order to catch it even if it wasn't handled.

Now all we have to do is catch the exception and Voila!!! to do that we use our App.XAML.cs and write the following:
Code:
using System;
using System.IO;
using System.Windows;

namespace GraFX
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App
    {
        public App()
        {
            Dispatcher.UnhandledException += OnDispatcherUnhandledException;
        }

        void OnDispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            var errorMessage = string.Format("An exception occurred: {0}", e.Exception.Message);
            MessageBox.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            //Write log containing our exception information
            File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "\\log.txt", e.Exception.StackTrace);
            e.Handled = true;
        } 
    }
}
All we do here is register our dispatcher to send back the exception when it happen in our code. In that way i don't have to handle expected exceptions everywhere in my code if not necessary(am still free to handle them) but just have a place to handle them propertly and not just have to look my entire code for try-catches and handle each of them in case something changed.

A very important fact is that this is not a "on error resume next" silliness but what it does is try to execute a code and if it fails it will execute the dispatcher which will send the exception object to the app.XAML.cs for handling. What is more important... the app will return to the previous state as if the code was never executed(not totally true but you get the idea). The idea is to determine in our global exception handler if the exception that was thrown was a critical one and in that case ask the user to re-start if necessary. However during my tests i can say that a re-start is not necessary at all.

Here is an example:

Lets say i try to convert "22A" to a integer. As every coder here know that will throw an exception and if not handled my app will suddendly die. Now lets see what happen to my app:


As you can see here the debugger is showing me the exception and as a coder i usually know what that means and that's no other than the fact that my app is gonna die after i press F5 to continue.... since i added my code lets see what really happen this time:


As you can see here the dispatcher catched the exception and the message was displayed and loged in my log.txt file. After clicking the OK button my app is still alive and kicking and at the same state as it was before the code that caused the exception was thrown

Here the stacktrace from my log.txt:
Quote:
at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
at System.Convert.ToInt32(String value)
at AES.UI.Main.UIMain.UserControl_Loaded(Object sender, RoutedEventArgs e) in C:\Users\aruantec\Documents\Expression\Blend 4\Projects\AES_GraFX_GM\AES.UI\Main\UIMain.xaml.cs :line 32
at System.Windows.RoutedEventHandlerInfo.InvokeHandle r(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Objec t source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(Dependency Object sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArg s e)
at System.Windows.BroadcastEventHelper.BroadcastEvent (DependencyObject root, RoutedEvent routedEvent)
at System.Windows.BroadcastEventHelper.BroadcastLoade dEvent(Object root)
at MS.Internal.LoadedOrUnloadedOperation.DoWork()
at System.Windows.Media.MediaContext.FireLoadedPendin gCallbacks()
at System.Windows.Media.MediaContext.FireInvokeOnRend erCallbacks()
at System.Windows.Media.MediaContext.RenderMessageHan dlerCore(Object resizedCompositionTarget)
at System.Windows.Media.MediaContext.RenderMessageHan dler(Object resizedCompositionTarget)
at System.Windows.Media.MediaContext.Resize(IComposit ionTarget resizedCompositionTarget)
at System.Windows.Interop.HwndTarget.OnResize()
at System.Windows.Interop.HwndTarget.HandleMessage(Wi ndowMessage msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Interop.HwndSource.HwndTargetFilter Message(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation( Object o)
at System.Windows.Threading.ExceptionWrapper.Internal RealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCat chWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
That's all for now and hope my small tutorial helped you to comprehend more about MVVM and exception handling in WPF and C#. I've attached the source code of @ES base. There you have some base controls such as the screen slider control(similar to mobile devices screen slide) as well as some other base stuff that will hopefuly help you to comprehend the logic behind. The file is a bit big since it contains some pics and other base stuff from @ES hence why i had to split it in 3 parts however this is not the @ES - GraFX source code but just the start base of it.

If you have any questions or suggestion do not hesitate to ask them. I may not respond immediatly since am very busy this days but i do check the forums frequently enough to answer your questions

Happy coding!
Attached Files
File Type: rar AES_GraFX_GM.part1.rar (3.30 MB, 7 views)
File Type: rar AES_GraFX_GM.part2.rar (3.30 MB, 7 views)
File Type: rar AES_GraFX_GM.part3.rar (2.34 MB, 14 views)
__________________


Current development tools:

Visual C++.net, Visual C#.net
Visual VB.net, Visual Webdeveloper.net
Bloodshed Dev C++, Borland C++
Visual Basic 6

Last edited by @ruantec; February 23rd, 2012 at 07:05..
@ruantec is offline   Reply With Quote

Advertisement [Remove Advertisement]
 

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

All times are GMT +1. The time now is 02:44.

© 2006 - 2012 Emu Forums | About Emu Forums | Advertisers | Investors | Legal | A member of the Crowdgather Forum Community


Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2013, vBulletin Solutions, Inc.