Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version
Go to top

An Address Book Application Made in MVVM For Metro Style App in Windows 8 Part 2

, 29 May 2012
This is the Second Part XML file as data source in Windows8
Mvvm3_Full.zip
Mvvm3_Basic
Mvvm3_Basic
Assets
Logo.png
SmallLogo.png
SplashScreen.png
StoreLogo.png
bin
ARM
Debug
Release
Debug
AppX
Assets
Logo.png
SmallLogo.png
SplashScreen.png
StoreLogo.png
Common
microsoft.system.package.metadata
S-1-5-21-3520127098-591485480-2378297468-1001.pckgdep
Mvvm3_Basic.exe
Mvvm3_Basic.pdb
resources.pri
vs.appxrecipe
Assets
Logo.png
SmallLogo.png
SplashScreen.png
StoreLogo.png
Common
Mvvm3_Basic.build.appxrecipe
Mvvm3_Basic.exe
Mvvm3_Basic.pdb
resources.pri
Release
x64
Debug
Release
x86
Debug
Release
Common
Model
Mvvm3_Basic_TemporaryKey.pfx
obj
Debug
Common
DesignTimeResolveAssemblyReferencesInput.cache
intermediatexaml
Mvvm3_Basic.exe
Mvvm3_Basic.pdb
LanguageQualifiers.txt.intermediate
layout.resfiles
layout.resfiles.intermediate
Mvvm3_Basic.exe
Mvvm3_Basic.pdb
pri.resfiles
pri.resfiles.intermediate
priconfig.xml.intermediate
resources.resfiles
resources.resfiles.intermediate
TempPE
Package.appxmanifest
Properties
ViewModel
Mvvm3_Basic.v11.suo
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace Mvvm3_Basic.Common
{
    /// <summary>
    /// Typical implementation of Page that provides several important conveniences:
    /// application view state to visual state mapping, GoBack and GoHome event handlers, and
    /// a default view model.
    /// </summary>
    [Windows.Foundation.Metadata.WebHostHidden]
    public class LayoutAwarePage : Page
    {
        private List<Control> _layoutAwareControls;
        private IObservableMap<String, Object> _defaultViewModel = new ObservableDictionary<String, Object>();
        private bool _useFilledStateForNarrowWindow = false;

        /// <summary>
        /// Initializes a new instance of the <see cref="LayoutAwarePage"/> class.
        /// </summary>
        public LayoutAwarePage()
        {
            if (Windows.ApplicationModel.DesignMode.DesignModeEnabled) return;

            // Map application view state to visual state for this page when it is part of the visual tree
            this.Loaded += this.StartLayoutUpdates;
            this.Unloaded += this.StopLayoutUpdates;

            // Establish the default view model as the initial DataContext
            this.DataContext = _defaultViewModel;
        }

        /// <summary>
        /// Gets an implementation of <see cref="IObservableMap<String, Object>"/> set as the
        /// page's default <see cref="DataContext"/>.  This instance can be bound and surfaces
        /// property change notifications making it suitable for use as a trivial view model.
        /// </summary>
        protected IObservableMap<String, Object> DefaultViewModel
        {
            get
            {
                return _defaultViewModel;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether visual states can be a loose interpretation
        /// of the actual application view state.  This is often convenient when a page layout
        /// is space constrained.
        /// </summary>
        /// <remarks>
        /// The default value of false indicates that the visual state is identical to the view
        /// state, meaning that Filled is only used when another application is snapped.  When
        /// set to true FullScreenLandscape is used to indicate that at least 1366 virtual
        /// pixels of horizontal real estate are available - even if another application is
        /// snapped - and Filled indicates a lesser width, even if no other application is
        /// snapped.  On a smaller display such as a 1024x768 panel this will result in the
        /// visual state Filled whenever the device is in landscape orientation.
        /// </remarks>
        public bool UseFilledStateForNarrowWindow
        {
            get
            {
                return _useFilledStateForNarrowWindow;
            }

            set
            {
                _useFilledStateForNarrowWindow = value;
                this.InvalidateVisualState();
            }
        }

        /// <summary>
        /// Invoked as an event handler to navigate backward in the page's associated
        /// <see cref="Frame"/> until it reaches the top of the navigation stack.
        /// </summary>
        /// <param name="sender">Instance that triggered the event.</param>
        /// <param name="e">Event data describing the conditions that led to the event.</param>
        protected virtual void GoHome(object sender, RoutedEventArgs e)
        {
            // Use the navigation frame to return to the topmost page
            if (this.Frame != null)
            {
                while (this.Frame.CanGoBack) this.Frame.GoBack();
            }
        }

        /// <summary>
        /// Invoked as an event handler to navigate backward in the page's associated
        /// <see cref="Frame"/> to go back one step on the navigation stack.
        /// </summary>
        /// <param name="sender">Instance that triggered the event.</param>
        /// <param name="e">Event data describing the conditions that led to the
        /// event.</param>
        protected virtual void GoBack(object sender, RoutedEventArgs e)
        {
            // Use the navigation frame to return to the previous page
            if (this.Frame != null && this.Frame.CanGoBack) this.Frame.GoBack();
        }

        /// <summary>
        /// Invoked as an event handler, typically on the <see cref="Loaded"/> event of a
        /// <see cref="Control"/> within the page, to indicate that the sender should start
        /// receiving visual state management changes that correspond to application view state
        /// changes.
        /// </summary>
        /// <param name="sender">Instance of <see cref="Control"/> that supports visual state
        /// management corresponding to view states.</param>
        /// <param name="e">Event data that describes how the request was made.</param>
        /// <remarks>The current view state will immediately be used to set the corresponding
        /// visual state when layout updates are requested.  A corresponding
        /// <see cref="Unloaded"/> event handler connected to <see cref="StopLayoutUpdates"/>
        /// is strongly encouraged.  Instances of <see cref="LayoutAwarePage"/> automatically
        /// invoke these handlers in their Loaded and Unloaded events.</remarks>
        /// <seealso cref="DetermineVisualState"/>
        /// <seealso cref="InvalidateVisualState"/>
        public void StartLayoutUpdates(object sender, RoutedEventArgs e)
        {
            var control = sender as Control;
            if (control == null) return;
            if (this._layoutAwareControls == null)
            {
                // Start listening to view state changes when there are controls interested in updates
                ApplicationView.GetForCurrentView().ViewStateChanged += this.ViewStateChanged;
                Window.Current.SizeChanged += this.WindowSizeChanged;
                this._layoutAwareControls = new List<Control>();
            }
            this._layoutAwareControls.Add(control);

            // Set the initial visual state of the control
            VisualStateManager.GoToState(control, DetermineVisualState(ApplicationView.Value), false);
        }

        private void ViewStateChanged(ApplicationView sender, ApplicationViewStateChangedEventArgs e)
        {
            this.InvalidateVisualState(e.ViewState);
        }

        private void WindowSizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
        {
            if (this._useFilledStateForNarrowWindow) this.InvalidateVisualState();
        }

        /// <summary>
        /// Invoked as an event handler, typically on the <see cref="Unloaded"/> event of a
        /// <see cref="Control"/>, to indicate that the sender should start receiving visual
        /// state management changes that correspond to application view state changes.
        /// </summary>
        /// <param name="sender">Instance of <see cref="Control"/> that supports visual state
        /// management corresponding to view states.</param>
        /// <param name="e">Event data that describes how the request was made.</param>
        /// <remarks>The current view state will immediately be used to set the corresponding
        /// visual state when layout updates are requested.</remarks>
        /// <seealso cref="StartLayoutUpdates"/>
        public void StopLayoutUpdates(object sender, RoutedEventArgs e)
        {
            var control = sender as Control;
            if (control == null || this._layoutAwareControls == null) return;
            this._layoutAwareControls.Remove(control);
            if (this._layoutAwareControls.Count == 0)
            {
                // Stop listening to view state changes when no controls are interested in updates
                this._layoutAwareControls = null;
                ApplicationView.GetForCurrentView().ViewStateChanged -= this.ViewStateChanged;
                Window.Current.SizeChanged -= this.WindowSizeChanged;
            }
        }

        /// <summary>
        /// Translates <see cref="ApplicationViewState"/> values into strings for visual state
        /// management within the page.  The default implementation uses the names of enum values.
        /// Subclasses may override this method to control the mapping scheme used.
        /// </summary>
        /// <param name="viewState">View state for which a visual state is desired.</param>
        /// <returns>Visual state name used to drive the
        /// <see cref="VisualStateManager"/></returns>
        /// <seealso cref="InvalidateVisualState"/>
        protected virtual string DetermineVisualState(ApplicationViewState viewState)
        {
            if (this._useFilledStateForNarrowWindow &&
                (viewState == ApplicationViewState.Filled ||
                viewState == ApplicationViewState.FullScreenLandscape))
            {
                // Allow pages to request that the Filled state be used only for landscape layouts narrower
                // than 1366 virtual pixels
                var windowWidth = Window.Current.Bounds.Width;
                viewState = windowWidth >= 1366 ? ApplicationViewState.FullScreenLandscape : ApplicationViewState.Filled;
            }
            return viewState.ToString();
        }

        /// <summary>
        /// Updates all controls that are listening for visual state changes with the correct
        /// visual state.
        /// </summary>
        /// <remarks>
        /// Typically used in conjunction with overriding <see cref="DetermineVisualState"/> to
        /// signal that a different value may be returned even though the view state has not
        /// changed.
        /// </remarks>
        /// <param name="viewState">The desired view state, or null if the current view state
        /// should be used.</param>
        public void InvalidateVisualState(ApplicationViewState? viewState = null)
        {
            if (this._layoutAwareControls != null)
            {
                string visualState = DetermineVisualState(viewState == null ? ApplicationView.Value : viewState.Value);
                foreach (var layoutAwareControl in this._layoutAwareControls)
                {
                    VisualStateManager.GoToState(layoutAwareControl, visualState, false);
                }
            }
        }

        /// <summary>
        /// Implementation of IObservableMap that supports reentrancy for use as a default view
        /// model.
        /// </summary>
        private class ObservableDictionary<K, V> : IObservableMap<K, V>
        {
            private class ObservableDictionaryChangedEventArgs : IMapChangedEventArgs<K>
            {
                public ObservableDictionaryChangedEventArgs(CollectionChange change, K key)
                {
                    this.CollectionChange = change;
                    this.Key = key;
                }

                public CollectionChange CollectionChange { get; private set; }
                public K Key { get; private set; }
            }

            private Dictionary<K, V> _dictionary = new Dictionary<K, V>();
            public event MapChangedEventHandler<K, V> MapChanged;

            private void InvokeMapChanged(CollectionChange change, K key)
            {
                var eventHandler = MapChanged;
                if (eventHandler != null)
                {
                    eventHandler(this, new ObservableDictionaryChangedEventArgs(CollectionChange.ItemInserted, key));
                }
            }

            public void Add(K key, V value)
            {
                this._dictionary.Add(key, value);
                this.InvokeMapChanged(CollectionChange.ItemInserted, key);
            }

            public void Add(KeyValuePair<K, V> item)
            {
                this.Add(item.Key, item.Value);
            }

            public bool Remove(K key)
            {
                if (this._dictionary.Remove(key))
                {
                    this.InvokeMapChanged(CollectionChange.ItemRemoved, key);
                    return true;
                }
                return false;
            }

            public bool Remove(KeyValuePair<K, V> item)
            {
                V currentValue;
                if (this._dictionary.TryGetValue(item.Key, out currentValue) &&
                    Object.Equals(item.Value, currentValue) && this._dictionary.Remove(item.Key))
                {
                    this.InvokeMapChanged(CollectionChange.ItemRemoved, item.Key);
                    return true;
                }
                return false;
            }

            public V this[K key]
            {
                get
                {
                    return this._dictionary[key];
                }
                set
                {
                    this._dictionary[key] = value;
                    this.InvokeMapChanged(CollectionChange.ItemChanged, key);
                }
            }

            public void Clear()
            {
                var priorKeys = this._dictionary.Keys.ToArray();
                this._dictionary.Clear();
                foreach (var key in priorKeys)
                {
                    this.InvokeMapChanged(CollectionChange.ItemRemoved, key);
                }
            }

            public ICollection<K> Keys
            {
                get { return this._dictionary.Keys; }
            }

            public bool ContainsKey(K key)
            {
                return this._dictionary.ContainsKey(key);
            }

            public bool TryGetValue(K key, out V value)
            {
                return this._dictionary.TryGetValue(key, out value);
            }

            public ICollection<V> Values
            {
                get { return this._dictionary.Values; }
            }

            public bool Contains(KeyValuePair<K, V> item)
            {
                return this._dictionary.Contains(item);
            }

            public int Count
            {
                get { return this._dictionary.Count; }
            }

            public bool IsReadOnly
            {
                get { return false; }
            }

            public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
            {
                return this._dictionary.GetEnumerator();
            }

            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return this._dictionary.GetEnumerator();
            }

            public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex)
            {
                int arraySize = array.Length;
                foreach (var pair in this._dictionary)
                {
                    if (arrayIndex >= arraySize) break;
                    array[arrayIndex++] = pair;
                }
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

santosh_pathak
CEO Addya Technologies
India India
"I am the CEO"
An Entrepreneur, Driving an Business Transformation Unit.
Follow on   Twitter

| Advertise | Privacy | Mobile
Web02 | 2.8.140916.1 | Last Updated 29 May 2012
Article Copyright 2012 by santosh_pathak
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid