MVVM Light and LINQ to SQL database connection

Apr 14, 2014 at 2:42 AM
Edited Apr 14, 2014 at 2:59 AM
I have a LINQ to SQL relational database on Windows Phone 8, and I'm implementing MVVM using MVVM Light. Can someone please explain the best way to get my db data context to my view models and/or data services? My view model locator code is set like so:
static ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            if (ViewModelBase.IsInDesignModeStatic)
            {
                SimpleIoc.Default.Register<IDataService, Design.DesignDataService>();
                SimpleIoc.Default.Register<IDetailsDataService, Design.DetailsDesignDataService>();
            }
            else
            {
                SimpleIoc.Default.Register<IDataService, DataService>();
                SimpleIoc.Default.Register<IDetailsDataService, DetailsDataService>();
            }


            SimpleIoc.Default.Register<MainViewModel>();
            // Ensure VM
            var main = SimpleIoc.Default.GetInstance<MainViewModel>();

            SimpleIoc.Default.Register<DetailsViewModel>();
            // Ensure VM
            var details = SimpleIoc.Default.GetInstance<DetailsViewModel>();

            main.NavigationService = new NavigationService();
            details.NavigationService = new NavigationService();
        }

        /// <summary>
        /// Gets the Main property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
            "CA1822:MarkMembersAsStatic",
            Justification = "This non-static member is needed for data binding purposes.")]
        public MainViewModel Main
        {
            get
            {
                return ServiceLocator.Current.GetInstance<MainViewModel>();
            }
        }

        /// <summary>
        /// Gets the Details property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
            "CA1822:MarkMembersAsStatic",
            Justification = "This non-static member is needed for data binding purposes.")]
        public DetailsViewModel Details
        {
            get
            {
                return SimpleIoc.Default.GetInstance<DetailsViewModel>();
            }
        }
I know this isn't a simple question, but I'd sure appreciate any help you can offer.

Thanks!
Apr 14, 2014 at 1:59 PM
Edited Apr 14, 2014 at 3:44 PM
Since you've registered the data service you can inject the data service into your view model constructor
 public class MyViewModel : ViewModelBase
    {
        IDataService dataService; 
        public MyViewModel(IDataService dataService)
        {
            _dataService = dataService;

            _customertypes =  _dataService.GetCustomerTypes() etc 
A reference to your data context or WCF service proxy should be in your data service.
Apr 14, 2014 at 11:48 PM
tazzer wrote:
A reference to your data context or WCF service proxy should be in your data service.
Yep. That's where I'm stuck. Everything I try seems to land me on "XamlParseException: Cannot create instance of type ViewModelLocator."

wrinkles nose

How do I add a reference to my data context in the data service?
Apr 22, 2014 at 3:47 PM
Edited Apr 22, 2014 at 3:56 PM
If you can't create an instance of ViewModelLocator there may a namespace issue in your App.XAML or something.
<Application x:Class="Company.TestHarness.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:vm="clr-namespace:Company.TestHarness.ViewModel"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             StartupUri="View/MainWindow.xaml"
             mc:Ignorable="d">
    
    <Application.Resources>
        <!--Global View Model Locator-->
        <vm:ViewModelLocator x:Key="Locator"
                             d:IsDataSource="True" />
    </Application.Resources>
    
Your locator class might look something like the following
using System;

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Ioc;
using Microsoft.Practices.ServiceLocation;

using Company.TestHarness.ViewModel;
using Company.TestHarness.Services;

namespace Company.TestHarness.ViewModel
{

    public class ViewModelLocator
    {
        static ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

            SimpleIoc.Default.Register<IMyDataService, MyDataService>();
            

            SimpleIoc.Default.Register<MainViewModel>();
            SimpleIoc.Default.Register<SomeOtherViewModel>();
        }

        /// <summary>
        /// Gets the Main property.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance",
            "CA1822:MarkMembersAsStatic",
            Justification = "This non-static member is needed for data binding purposes.")]
        public MainViewModel Main
        {
            get
            {
                return ServiceLocator.Current.GetInstance<MainViewModel>();
            }
        }

        public UserViewModel Other
        {
            get
            {
                return ServiceLocator.Current.GetInstance<SomeOtherViewModel>();
            }
        }
       

        /// <summary>
        /// Cleans up all the resources.
        /// </summary>
        public static void Cleanup()
        {

            // Implements IDisposable
            SimpleIoc.Default.Unregister<IMyDataService>();

            SimpleIoc.Default.Unregister<SomeOtherViewModel>();
            SimpleIoc.Default.Unregister<MainViewModel>();

        }
    }
}
Main View:
<Window x:Class="Company.TestHarness.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:mvvm="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF45"
        xmlns:views="clr-namespace:Company.TestHarness.View"
        mc:Ignorable="d" 
        Height="500"
        Width="800"
        Title="Thindenach WPF Stuff"
        DataContext="{Binding Main, Source={StaticResource Locator}}">
A sample service is shown below, it's just test code and uses an ORM called LLBLGen but it's just a proxy class, that uses a WCF service, just use your data context and build up a data service.
using System;
using System.Data;
using System.Linq;
using System.Xml.Linq;
using System.Windows.Forms;
using System.Collections.Generic;
using System.ComponentModel;
using System.ServiceModel;

using Company.DataServices.Security;
using Company.DataServices.Security.Helpers;
using Company.DataServices.Security.DAL.EntityClasses;
using Company.DataServices.Security.DAL.HelperClasses;

{
    public class MyDataService : IMyDataService, IDisposable
    {

        public MyDataService()
        {
            // NOTE: Config should come from configuration service or config file, this is just for test
            EndpointAddress address = new EndpointAddress("http://Mydomain/SomeService.svc");
            BasicHttpBinding binding = new BasicHttpBinding();
            binding.MaxReceivedMessageSize = 2147483647;
            binding.MaxBufferSize = 2147483647;
            _secChannelFactory = new ChannelFactory<ISecurityService>(binding, address);
        }

        #region Implement IDisposable
        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    if (_secChannelFactory != null)
                    {
                        if (_secChannelFactory.State == CommunicationState.Opened)
                        {
                            _secChannelFactory.Close();
                        }
                        _secChannelFactory = null;
                    }
                }
                disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }

        #endregion



        public EntityCollection GetUserSettings(string userid)
        {
            return (EntityCollection)ServiceCall<IEntityCollection>(x => GetUserSettings(userid));
        }

        public string GetScreenName(string userid)
        {
            return (string)ServiceCall<string>(x => GetScreenName(userid));
        }

        private static TResult ServiceCall<TResult>(Func<ISecurityService, TResult> codeBlock)
        {
            var proxy = (ISecurityService)_secChannelFactory.CreateChannel();
            bool success = false;

            TResult result;
            try
            {
                result = codeBlock((ISecurityService)proxy);
                ((IClientChannel)proxy).Close();
                success = true;
            }
            catch (CommunicationException ce)
            {
                // do something
            }
            catch (Exception ex)
            {
                // do something
            }
            finally
            {
                if (!success)
                {
                    ((IClientChannel)proxy).Abort();
                }
            }

            return result;
        }

        #region Private member vars

        private bool disposed = false;
        private static ChannelFactory<ISecurityService> _secChannelFactory = null;

        #endregion
    }
}
Good luck.
Apr 30, 2014 at 10:04 AM
Thanks for taking the time to respond, tazzer. I have it working now. I think. That ViewModelLocator is a speedy little thing, and I needed to get my db connection established sooner than I'd thought.

shrug

First app, first time using MVVM Light = lots of total noob moments. ;)