Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

In this tutorial, you're going to learn how to create a simple to-do app which syncs ToDo data with Project data using multiple sync channels. This tutorial is a continuation of the the previous tutorial: Walkthrough: Create a To-Do App with OS-Level Data Synchronization. At the end of this tutorial, you should have the following result.

Panel

Samples:

CrosslightToDoMultipleSyncChannels.zip

Follow these steps:

Table of Contents
maxLevel3
stylecircle

Anchor
preqreuisite
preqreuisite

Prerequisite

Before starting the walkthrough, it is recommended that you have followed these walkthroughs in order:

It is also recommended that you have read through these conceptual topics in order to get a better understanding:

To use this walkthrough, you will need to use at least Crosslight version 5.0.5000.626-experimental in order to achieve the desired result. You also need to have Mobile Studio for Windows installed. If you haven't done so, download here.

Let's get started. 

Preparing the Project

In this tutorial, we're going to continue from the previous tutorial, where you've learned how to perform OS-level synchronization with SyncAdapter and Background App Refresh. Download the sample here (from the previous tutorial). After you've downloaded the sample, you're ready to proceed.

We're going to modify the current database models and EDMX. So, in the application, one user can have multiple Projects, where in each project may consists of multiple ToDo items.

Modifying the Database

Start by modifying the CrosslightDb.mdf database inside CrosslightToDo.WebAPI/AppData folder. Add a new table called Project.

Use the following query to create the Project table. 

Code Block
languagesql
CREATE TABLE [dbo].[Project]
(
	[Id] INT NOT NULL PRIMARY KEY, 
    [Text] NVARCHAR(MAX) NOT NULL,
	[CreatedBy] NVARCHAR(128) NOT NULL,
    [CreatedOn] DATETIME NOT NULL, 
    [ModifiedOn] DATETIME NOT NULL, 
    [IsDeleted] BIT NOT NULL
)

Next, open up the ToDo table.

Change the CreatedBy column to ProjectID, with reference to the Id column of the newly created Project table. Update your database. Use this query, if you prefer.

Code Block
languagesql
CREATE TABLE [dbo].[ToDo] (
    [Id]          UNIQUEIDENTIFIER NOT NULL,
    [Text]        NVARCHAR (MAX)   NULL,
    [IsCompleted] BIT              DEFAULT ((0)) NOT NULL,
    [CreatedOn]   DATETIME         NULL,
    [ModifiedOn]  DATETIME         NULL,
    [IsDeleted]   BIT              DEFAULT ((0)) NOT NULL,
    [ProjectId]   UNIQUEIDENTIFIER   NOT NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC), 
    CONSTRAINT [FK_ToDo_Project] FOREIGN KEY ([Projectid]) REFERENCES [Project]([Id])
);

In the CrosslightToDo.DomainModels project, select the other three files other than ToDoModel.edmx, then delete them.

Then in the CrosslightToDo.Core/DomainModels, delete both of these files.

Once you've done that, open up ToDoModel.edmx inside CrosslightToDo.DomainModels/ToDo folder.

Right click on the empty area in the designer surface and select Update Model from Database.

In the dialog that appears, untick the option Save connection settings as shown in the following image.

Click Next. In the next screen, add the Project table.

Then, change to the Refresh tab. Select the ToDo table and hit Finish.

When this dialog appears, click OK on all dialogs.

You will end up an updated EDMX. However, you may notice that it will still have CreatedBy in the ToDo model. Right-click on the property and select Delete from Model.

Save this EDMX and hit OK on all dialogs that appear.

Click on the Project table.

Don't forget to set the properties of the Project table such as changing the Repository Type to EditableLocalEntityRepository, setting the Logical Delete Property to IsDeleted, and Synchronization Date Property to ModifiedOn.

Should you get a compile error similar to the following (especially in CrosslightToDo.DomainModels project), simply set the Build Action to None.

If you try to build the project, you'll get several errors. Let's resolve these errors next. Open up SimpleViewModel.cs inside CrosslightToDo.Core/ViewModels folder and modify the ExecuteAdd method.

Remove this line for now. Next, open up ToDoController.cs inside CrosslightToDo.WebAPI/Controllers folder. In BeforeExecuteQueryDelegate method, comment out these lines for now.

Associating User with Project

From the previous tutorial, we have made created a single, simple ViewModel for displaying the user's ToDo items, which is the SimpleViewModel. Since we're going introduce the Projects to the application, let's rename the SimpleViewModel into ToDoListViewModel instead. 

Use the following code for ToDoListViewModel.

Code Block
titleToDoListViewModel.cs
languagec#
using System;
using CrosslightToDo.Core;
using CrosslightToDo.DomainModels.ToDo;
using Intersoft.AppFramework;
using Intersoft.AppFramework.Identity;
using Intersoft.AppFramework.Services;
using Intersoft.AppFramework.ViewModels;
using Intersoft.Crosslight;
namespace CrosslightToDo.ViewModels
{
    public class ToDoListViewModel : DataListViewModelBase<ToDo, IToDoRepository>
    {
        #region Constructors
        /// <summary>
        ///     Initializes a new instance of the <see cref="ToDoListViewModel" /> class.
        /// </summary>
        public ToDoListViewModel()
        {
            this.Title = "My To-Do List";
            this.EnableRefresh = true;
        }
        #endregion
        #region Fields
        private Project _project;
        private IQueryDefinition _viewQuery;
        #endregion
        #region Properties
        public IAccountService AccountService => ServiceProvider.GetService<IAccountService>();
        public AppSettings AppSettings => Container.Current.Resolve<AppSettings>();
        public bool IsLoginDisplayed { get; set; }
        public Project Project
        {
            get { return _project; }
            set
            {
                if (_project != value)
                {
                    _project = value;
                    OnPropertyChanged("Project");
                }
            }
        }
        public IPushRegistrationService PushRegistrationService => ServiceProvider.GetService<IPushRegistrationService>();
        public ISynchronizationService SynchronizationService => ServiceProvider.GetService<ISynchronizationService>();
        public IUserService UserService => ServiceProvider.GetService<IUserService>();
        protected override IQueryDefinition ViewQuery
        {
            get
            {
                return _viewQuery;
            }
        }
        #endregion
        #region Methods
        protected override void ExecuteAdd(object parameter)
        {
            base.ExecuteAdd(parameter);
            this.DialogPresenter.Show<AddViewModel>(new DialogOptions("Add New Item"), async result =>
            {
                User user = await this.UserService.GetUserAsync(this.AccountService.GetAccount());
                if (user != null)
                {
                    AddViewModel viewModel = result.ViewModel as AddViewModel;
                    if (viewModel != null)
                    {
                        if (string.IsNullOrEmpty(viewModel.Text))
                            this.ToastPresenter.Show("You haven't entered any text.");
                        else if (this.Project != null)
                        {
                            ToDo todo = new ToDo
                            {
                                Id = Guid.NewGuid(),
                                Text = viewModel.Text,
                                CreatedOn = DateTime.Now,
                                IsCompleted = false,
                                ModifiedOn = DateTime.Now,
                                ProjectId = this.Project.Id
                            };
                            this.Repository.Insert(todo);
                            //Important: call this to refresh the table view
                            this.OnDataInserted(todo);
                            this.SaveAndSynchronize();
                        }
                    }
                }
            });
        }
        protected override void ExecuteEditAction(object parameter)
        {
            EditingParameter editingParameter = parameter as EditingParameter;
            if (editingParameter != null)
            {
                ToDo todo = editingParameter.Item as ToDo;
                string editAction = editingParameter.CustomAction;
                if (todo != null)
                {
                    if (editAction == "Delete")
                    {
                        this.Repository.Delete(todo);
                        //Important: call this to refresh the table view
                        this.OnDataRemoved(editingParameter.Item as ToDo);
                        this.SaveAndSynchronize();
                    }
                    else if (editAction == "Complete")
                    {
                        todo.IsCompleted = true;
                        //Important: call this to refresh the table view
                        this.OnDataChanged(todo);
                        this.SaveAndSynchronize();
                    }
                    editingParameter.ShouldEndEditing = true;
                }
            }
        }
        public override async void Navigated(NavigatedParameter parameter)
        {
            this.Project = parameter.Data as Project;
            if (this.Project != null)
                _viewQuery = new ToDoQueryDefinition(this.Project);
            // since this list depends on the Project as the parent, let's add it to the ParentEntities
            // to enable automatic closing when the Project was deleted due to data sync.
            this.ParentEntities.Add(this.Project);
            base.Navigated(parameter);
            User user = await this.UserService.GetCachedUserAsync();
            this.UserService.SetCurrentUser(user);
            await this.SynchronizationService.SynchronizeDataAsync(SynchronizeAction.LoadLocalDataFollowedWithSyncData);
        }
        private async void SaveAndSynchronize()
        {
            await this.Repository.SaveChangesAsync();
            SynchronizationChannel toDoSyncChannel = this.SynchronizationService.GetSynchronizationChannel("ToDo");
            if (toDoSyncChannel != null)
                toDoSyncChannel.Start(SynchronizeAction.SyncData);
        }
        protected override bool ValidateNewSynchronizedItem(ToDo item)
        {
            if (this.Project != null)
                return this.Project.Id == item.ProjectId;
            return base.ValidateNewSynchronizedItem(item);
        }
        #endregion
    }
}

Note that you can simply override ValidateNewSynchronizedItem method inside this ViewModel in order to display the ToDo items relative to the project.

Then, in the same folder, create a new Crosslight Data List View Model and give it a name of ProjectListViewModel. Use the following code.

Code Block
titleProjectListViewModel.cs
languagec#
using System;
using CrosslightToDo.Core;
using CrosslightToDo.DomainModels.ToDo;
using Intersoft.AppFramework;
using Intersoft.AppFramework.Identity;
using Intersoft.AppFramework.Services;
using Intersoft.AppFramework.ViewModels;
using Intersoft.Crosslight;
namespace CrosslightToDo.ViewModels
{
    public class ProjectListViewModel : DataListViewModelBase<Project, IProjectRepository>
    {
        #region Constructors
        public ProjectListViewModel()
        {
            this.Title = "My Projects";
            this.EnableRefresh = true;
        }
        #endregion
        #region Properties
        public IAccountService AccountService => ServiceProvider.GetService<IAccountService>();
        public AppSettings AppSettings => Container.Current.Resolve<AppSettings>();
        public bool IsLoginDisplayed { get; set; }
        public IPushRegistrationService PushRegistrationService => ServiceProvider.GetService<IPushRegistrationService>();
        public ISynchronizationService SynchronizationService => ServiceProvider.GetService<ISynchronizationService>();
        public IUserService UserService => ServiceProvider.GetService<IUserService>();
        protected override IQueryDefinition ViewQuery
        {
            get { return new ProjectQueryDefinition(); }
        }
        #endregion
        #region Methods
        private void DisplayLogin()
        {
            if (!this.IsLoginDisplayed)
            {
                this.IsLoginDisplayed = true;
                IViewService viewService = this.GetService<IViewService>();
                if (viewService != null)
                {
                    viewService.RunOnBackgroundThread(() =>
                    {
                        viewService.RunOnUIThread(() =>
                        {
                            this.NavigationService.Navigate<LoginViewModel>(new NavigationParameter(NavigationMode.Modal), async result =>
                            {
                                if (!this.AccountService.IsLoggedIn())
                                {
                                    this.DisplayLogin();
                                    this.ToastPresenter.Show("Please login before using the app.");
                                    this.IsLoginDisplayed = false;
                                }
                                else
                                {
                                    await this.SynchronizationService.SynchronizeDataAsync(SynchronizeAction.LoadLocalDataFollowedWithSyncData);
                                    await this.PushRegistrationService.RegisterPushNotificationAsync();
                                }
                            });
                        });
                    }, 2000);
                }
            }
        }
        protected override void ExecuteAdd(object parameter)
        {
            base.ExecuteAdd(parameter);
            this.DialogPresenter.Show<AddViewModel>(new DialogOptions("Add New Item"), async result =>
            {
                User user = await this.UserService.GetUserAsync(this.AccountService.GetAccount());
                if (user != null)
                {
                    AddViewModel viewModel = result.ViewModel as AddViewModel;
                    if (viewModel != null)
                    {
                        if (string.IsNullOrEmpty(viewModel.Text))
                            this.ToastPresenter.Show("You haven't entered any text.");
                        else
                        {
                            Project project = new Project
                            {
                                Id = Guid.NewGuid(),
                                Text = viewModel.Text,
                                CreatedOn = DateTime.Now,
                                CreatedBy = user.Id,
                                ModifiedOn = DateTime.Now,
                                IsDeleted = false
                            };
                            this.Repository.Insert(project);
                            //Important: call this to refresh the table view
                            this.OnDataInserted(project);
                            this.SaveAndSynchronize();
                        }
                    }
                }
            });
        }
        protected override async void ExecuteEditAction(object parameter)
        {
            EditingParameter editingParameter = parameter as EditingParameter;
            if (editingParameter != null)
            {
                Project project = editingParameter.Item as Project;
                string editAction = editingParameter.CustomAction;
                if (project != null)
                {
                    if (editAction == "Delete")
                    {
                        this.Repository.Delete(project);
                        //Important: call this to refresh the table view
                        this.OnDataRemoved(editingParameter.Item as Project);
                        this.SaveAndSynchronize();
                    }
                    editingParameter.ShouldEndEditing = true;
                }
            }
        }
        public override async void Navigated(NavigatedParameter parameter)
        {
            base.Navigated(parameter);
            bool isSignedIn = this.AccountService.IsLoggedIn();
            if (!isSignedIn)
                this.DisplayLogin();
            else
            {
                User user = await this.UserService.GetCachedUserAsync();
                this.UserService.SetCurrentUser(user);
                await this.SynchronizationService.SynchronizeDataAsync(SynchronizeAction.LoadLocalDataFollowedWithSyncData);
                await this.PushRegistrationService.RegisterPushNotificationAsync();
            }
        }
        private async void SaveAndSynchronize()
        {
            await this.Repository.SaveChangesAsync();
            await this.SynchronizationService.SynchronizeDataAsync();
        }
        #endregion
    }
}

The code is pretty similar to the one in previous ToDoListViewModel, except we're using Project and IProjectRepository this time. Then, proceed by renaming AddToDoViewModel to AddViewModel. We're going to reuse this ViewModel for adding new Project and new ToDo item.

Inside AddViewModel, rename the ToDoText property to Text. Use the following code.

Code Block
titleAddViewModel.cs
languagec#
using Intersoft.Crosslight.ViewModels;
namespace CrosslightToDo.ViewModels
{
    public class AddViewModel : ViewModelBase
    {
        #region Constructors
        public AddViewModel()
        {
        }
        #endregion
        #region Fields
        private string _text;
        #endregion
        #region Properties
        public string Text
        {
            get { return _text; }
            set
            {
                if (_text != value)
                {
                    _text = value;
                    OnPropertyChanged("ToDoText");
                }
            }
        }
        #endregion
    }
}

Don't forget to change the BindingProvider definition as well. Rename AddToDoBindingProvider to AddBindingProvider. Here's the contents.

Code Block
titleAddBindingProvider.cs
languagec#
this.AddBinding("TxtToDo", BindableProperties.TextProperty, new BindingDescription("Text", BindingMode.TwoWay, UpdateSourceTrigger.PropertyChanged));

Also, rename ToDoQueryDefinition inside CrosslightToDo.Core/QueryDefinition folder into ProjectQueryDefinition.

Copy the ProjectQueryDefinition and name the file as ToDoQueryDefinition. Use the following code.

Code Block
titleToDoQueryDefinition.cs
languagec#
using CrosslightToDo.DomainModels.ToDo;
using Intersoft.AppFramework;
using Intersoft.Crosslight.Data.ComponentModel;
namespace CrosslightToDo.Core
{
    public class ToDoQueryDefinition : QueryDefinitionBase
    {
        #region Constructors
        public ToDoQueryDefinition(Project project)
        {
            this.SortExpression = "CreatedOn desc";
            this.Project = project;
        }
        #endregion
        #region Fields
        private Project _project;
        #endregion
        #region Properties
        public Project Project
        {
            get { return _project; }
            set
            {
                if (_project != value)
                {
                    _project = value;
                    OnPropertyChanged("Project");
                }
            }
        }
        #endregion
        #region Methods
        public override QueryDescriptor GetQueryDescriptor()
        {
            QueryDescriptor queryDescriptor = this.GetBaseQueryDescriptor();
            if (this.Project != null)
                this.AddFilter("ProjectId", FilterOperator.IsEqualTo, this.Project.Id);
            return queryDescriptor;
        }
        #endregion
    }
}

Then, set ProjectListViewModel as the root ViewModel in OnStart method of AppService.cs inside CrosslightToDo.Core/Infrastructure folder.

Still in the same file, add the following entry to register the ProjectRepository with the EntityContainer.

Code Block
languagec#
Container.Current.Register<IProjectRepository>((c) => new ProjectRepository(c.Resolve<IEntityContainer>("Default")));

Don't forget to add the website bindings in the applicationhost.config so that your IIS Express instance is exposed to the local network. 

In your web.config, modify the connection string for ToDoEntities.

Code Block
titleweb.config
languagexml
<add name="ToDoEntities" connectionString="metadata=res://*/ToDo.ToDoModel.csdl|res://*/ToDo.ToDoModel.ssdl|res://*/ToDo.ToDoModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=(LocalDb)\MSSQLLocalDB;attachdbfilename=|DataDirectory|\CrosslightDb.mdf;initial catalog=CrosslightDb;integrated security=True;multipleactiveresultsets=True;application name=EntityFramework&quot;" providerName="System.Data.EntityClient" />

Rename SimpleBindingProvider to ToDoListBindingProvider. Then create a new BindingProvider called ProjectListBindingProvider. Use the following code.

Code Block
titleProjectListBindingProvider.cs
languagec#
using CrosslightToDo.ViewModels;
using Intersoft.Crosslight;

namespace CrosslightToDo
{
    public class ProjectListBindingProvider : ToDoListBindingProvider
    {
        #region Constructors
        public ProjectListBindingProvider()
        {
            this.AddBinding("TableView", BindableProperties.DetailNavigationTargetProperty, new NavigationTarget(typeof(ToDoListViewModel), NavigationMode.Push), true);
        }
        #endregion
    }
}

 

Preparing the Android Project

Then, in the Android project, rename AddToDoFragment into AddFragment. Create a new Fragment called ProjectListFragment and use the following code.

Code Block
titleProjectListFragment.cs
languagec#
using System;
using Android.Graphics;
using Android.Runtime;
using CrosslightToDo.ViewModels;
using Intersoft.Crosslight;
using Intersoft.Crosslight.Android;
using Intersoft.Crosslight.Android.v7;
namespace CrosslightToDo.Android.Fragments
{
    [ImportBinding(typeof(ProjectListBindingProvider))]
    public class ProjectListFragment : RecyclerViewFragment<ProjectListViewModel>
    {
        #region Constructors
        /// <summary>
        ///     Initializes a new instance of the <see cref="ProjectListFragment" /> class.
        /// </summary>
        public ProjectListFragment()
        {
        }
        /// <summary>
        ///     Initializes a new instance of the <see cref="ProjectListFragment" /> class.
        /// </summary>
        /// <param name="javaReference">The java reference.</param>
        /// <param name="transfer">The transfer.</param>
        public ProjectListFragment(IntPtr javaReference, JniHandleOwnership transfer)
            : base(javaReference, transfer)
        {
        }
        #endregion
        #region Methods
        /// <summary>
        ///     Initializes this instance.
        /// </summary>
        protected override void Initialize()
        {
            base.Initialize();
            this.IconId = Resource.Drawable.ic_toolbar;
            this.CellStyle = CellStyle.Default;
            this.InteractionMode = ListViewInteraction.Navigation;
            this.EditingOptions = EditingOptions.AllowEditing;
            this.AddBarItem(new BarItem("AddButton", CommandItemType.Add));
            this.EditActions.Add(new Intersoft.Crosslight.Android.v7.ComponentModels.EditAction("Delete", Color.Red));
        }
        #endregion
    }
}

Rename SimpleFragment to ToDoListFragment. Also, open up SimpleActivity.cs inside CrosslightToDo.Android/Activities folder. Change the ViewModel here from ToDoListViewModel to ProjectListViewModel.

Code Block
titleSimpleActivity.cs
languagec#
using Android.App;
using CrosslightToDo.ViewModels;
using Intersoft.Crosslight.Android.v7;
namespace CrosslightToDo.Android.Activities
{
    /// <summary>
    ///     The main activity that acts as the host for ToDoListFragment.
    /// </summary>
    /// <seealso cref="Intersoft.Crosslight.Android.v7.AppCompatActivity{CrosslightToDo.ViewModels.ProjectListViewModel}" />
    [Activity]
    public class SimpleActivity : AppCompatActivity<ProjectListViewModel>
    {
    }
}

Remove this line from ToDoListFragment.

Code Block
titleToDoListFragment.cs
languagec#
this.IconId = Resource.Drawable.ic_toolbar;

You should get the following result.

Video
Autoplayfalse
Sourcehttp://developer.intersoftsolutions.com/download/attachments/27297988/android-result.mp4?api=v2
Width400px

Preparing the iOS Project

Rename the MainViewController inside CrosslightToDo.iOS/ViewControllers folder to ToDoListViewController. Use the following code.

Code Block
titleToDoListViewController.cs
languagec#
using CrosslightToDo.ViewModels;
using Intersoft.Crosslight;
using Intersoft.Crosslight.iOS;
using UIKit;
namespace CrosslightToDo.iOS
{
    [ImportBinding(typeof(ToDoListBindingProvider))]
    public partial class ToDoListViewController : UITableViewController<ToDoListViewModel>
    {
        #region Properties
        public override TableViewCellStyle CellStyle => TableViewCellStyle.Default;
        public override EditingOptions EditingOptions => EditingOptions.AllowEditing;
        protected override string EmptyCellText => "No to-do items.";
        public override TableViewInteraction InteractionMode => TableViewInteraction.None;
        #endregion
        #region Methods
        protected override void InitializeView()
        {
            base.InitializeView();
            var addButton = new UIBarButtonItem(UIBarButtonSystemItem.Add);
            this.NavigationItem.SetRightBarButtonItem(addButton, false);
            this.RegisterViewIdentifier("AddButton", addButton);
            this.EditActions.Add(new UIEditAction("Delete", true));
            this.EditActions.Add(new UIEditAction("Complete", UIColor.DarkGray));
        }
        #endregion
    }
}

Then, add a new Crosslight Table View Controller for iPhone named ProjectListViewController. Use the following code.

Code Block
titleProjectListViewController.cs
languagec#
 using CrosslightToDo.ViewModels;
using Intersoft.Crosslight;
using Intersoft.Crosslight.iOS;
using UIKit;
namespace CrosslightToDo.iOS.ViewControllers
{
    [ImportBinding(typeof(ProjectListBindingProvider))]
    public partial class ProjectListViewController : UITableViewController<ProjectListViewModel>
    {
        #region Properties
        public override TableViewCellStyle CellStyle => TableViewCellStyle.Default;
        public override EditingOptions EditingOptions => EditingOptions.AllowEditing;
        protected override string EmptyCellText => "No projects.";
        public override TableViewInteraction InteractionMode => TableViewInteraction.Navigation;
        #endregion
        #region Methods
        protected override void InitializeView()
        {
            base.InitializeView();
            var addButton = new UIBarButtonItem(UIBarButtonSystemItem.Add);
            this.NavigationItem.SetRightBarButtonItem(addButton, false);
            this.RegisterViewIdentifier("AddButton", addButton);
            this.EditActions.Add(new UIEditAction("Delete", true));
        }
        #endregion
    }
}

Save the files and try to run the iOS app. You should get the following result.

Video
Autoplayfalse
Sourcehttp://developer.intersoftsolutions.com/download/attachments/27297988/ios-result.mp4?api=v2
Width400px

Enabling Multi-Channel Synchronization

So far, we've managed to modify the app to include the Project model and the ToDo model, in which a user can have multiple Projects, and each Project can have multiple ToDo items. Let's finish this app by enabling multi-channel synchronization, we're going to create different channels for Project synchronization, and another for ToDo synchronization.

Open AppService.cs inside CrosslightToDo.Core/Infrastructure folder and add the following snippet lines to ISynchronizationService initialization.

Code Block
titleAppService.cs
languagec#
LocalTypeQueryDefinition masterDataQueryDefinition = new LocalTypeQueryDefinition();
masterDataQueryDefinition.AddType(typeof(TaskPriority));
masterDataQueryDefinition.AddType(typeof(TaskType));
service.RegisterSynchronizationChannel(new SynchronizationChannel("MasterData", SynchronizationPriority.Normal)
{
    Types = new Type[] {typeof(TaskPriority), typeof(TaskType)},
    SynchronizationMode = SynchronizationMode.TwoWay,
    PageSize = 2,
    QueryDefinition = masterDataQueryDefinition,
    AutoRetry = true,
    UserSpecific = false
});
LocalTypeQueryDefinition todoQueryDefinition = new LocalTypeQueryDefinition();
todoQueryDefinition.AddType(typeof(Project));
todoQueryDefinition.AddType(typeof(CrossTask.DomainModels.Task));
service.RegisterSynchronizationChannel(new SynchronizationChannel("ToDo", SynchronizationPriority.High)
{
    Types = new Type[] {typeof(CrossTask.DomainModels.Project), typeof(CrossTask.DomainModels.Task)},
    SynchronizationMode = SynchronizationMode.TwoWay,
    UserSpecific = true,
    QueryDefinition = todoQueryDefinition
});

Which should look like the following image.

Then, open SaveAndSynchronize method inside ProjectListViewModel.cs. Modify the method into the following.

Code Block
titleProjectListViewModel.cs
languagec#
private async void SaveAndSynchronize()
{
    await this.Repository.SaveChangesAsync();
    SynchronizationChannel projectSyncChannel = this.SynchronizationService.GetSynchronizationChannel("Project");
    if (projectSyncChannel != null)
        projectSyncChannel.Start(SynchronizeAction.SyncData);
}

So, instead of calling synchronization service to synchronize everything, we can simply synchronize the required channels, in this case, it's the Project channel defined previously in the AppService.

Similarly, open the ToDoListViewModel.cs and modify the method as well.

Code Block
titleToDoListVieModel.cs
languagec#
private async void SaveAndSynchronize()
{
    await this.Repository.SaveChangesAsync();
    SynchronizationChannel toDoSyncChannel = this.SynchronizationService.GetSynchronizationChannel("ToDo");
    if (toDoSyncChannel != null)
        toDoSyncChannel.Start(SynchronizeAction.SyncData);
}

Save these files and re-run the project. You should get the following result.


Video
Autoplayfalse
Sourcehttp://developer.intersoftsolutions.com/download/attachments/27297988/result.mp4?api=v2
Width500px

Conclusion

In this lesson, you've learned how to utilize multiple sync channels with Crosslight's synchronization framework. Stay tuned for more Crosslight tutorials to come!

Sample

You can also find the resulting sample here: CrosslightToDoMultipleSyncChannels.zip. Simply open this sample and restore the NuGet packages with Xamarin Studio or Visual Studio and run the project. Consult this documentation should you need help on restoring the NuGet packages.

 

Related Topics

Content by Label
spacescrosslight
reversetrue
showLabelsfalse
max5
sortmodified
labelsgetting-started-with-crosslight -walkthrough-create-a-to-do-app-with-data-synchronization-and-multiple-sync-channels
showSpacefalse
typepage