Documentation : Conflicts - Windows Phone 7

This example presents conflicts arise when two users modify the same data.

Application consists of only one model, which has two fields. In order to show conflicts, one of the field will be modified by both users and then synchronized. Records, which are conflicted, will be marked with red background color. Main screen of application contains list of model entities and two buttons. User can add new entity, edit it's value and synchronize with mobeelizer cloud. There are two users in the system and there's a possibility to switch them on application life time.

Design Your App

First thing we have to do is create new application in Mobeelizer App Designer, called 'Conflicts'.


This example is focused on conflicts so set conflict resolving to 'manual' mode.


Next we will configure model. We have to go to 'Models' section, create new one and call it 'ConflictsEntity'.


Last thing to finish this step is to create two fields. Fields properties are specified in table below. Note that you shoud use default model credentials (CRUD operations avaliable for everyone).

NameRequired propertyTypeDefault value propertyAdditional propertiesCredentials
titleyestext--default
scoreyesinteger1min: 1, max: 5default

Next section to configure is 'Groups & Roles', by default there is one group called 'users' and one device category 'mobile' and this two together create role 'users-mobile'. This default configuration is perfect for our example and you don't have to change it. 
When everything is done in Create mode, deploy our application to test environment, and create two users with passwords:

  • a - usera
  • b - userb

Last thing to do in App Designer is download configured template with default settings.

Use the Mobeelizer SDK

Open downloaded project in Microsoft Visual Studio (Windows Phone SDK 7.1 must be installed on your computer). There is a few files generated in our project, applicatiom.xml, app.config (read more) and 'Model/File.cs' - our model class.

Create app skeleton

In our example we will use MVVM pattern. To make it, create two folders in solution explorer - 'View' and 'ViewModel'. Next move 'MainPage.xaml' file to 'View' folder and change path to navigation page in 'WMAppManifet.xml' file - DefaultTask node - to 'View/MainPage.xaml'.

You also need to add this files into project:

  • userAIcon.fw.png - User a icon, will be displayed in entities list item. Add it into project root folder and set build action property to Content.
  • userBIcon.fw.png - User b icon, will be displayed in entities list item. Add it into project root folder and set build action property to Content.
  • OwnerNameToIconConverter.cs - Converter which converts owner name into path to user icon. Add it into ViewModel folder. 
  • movies.xml - Generated list of movies, put it in the project and set build action value to 'content'.

Prepare main screen

Now we have already created skeleton of our project, next things to do is creating View and ViewModel. As described before our main screen contains list of model entities and two buttons to add new entity and synchronize data. There will be also possibility to edit entities. Lets create it in our MainPage.xaml file. 
First of all we need to create grid with 3 rows, first row will contain control to switch between users, second will contain list of entities and last one will contain 'sync' and 'add' buttons. 
In code below you can see that ListBox items are bind to Entities list, and buttons are bind to commands responsible for synchronization and adding new entities.

View/MainPage.xaml
...
<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <!--TitlePanel contains the name of the application and page title-->
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
        <TextBlock x:Name="ApplicationTitle" Text="MOBEELIZER TUTORIAL" Style="{StaticResource PhoneTextNormalStyle}"/>
        <TextBlock x:Name="PageTitle" Text="Conflicts" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>
    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <Grid.RowDefinitions>
            <RowDefinition Height="100" />
            <RowDefinition Height="*" />
            <RowDefinition Height="100"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0">
            <!-- Place for switch user control -->
        </Grid>
        <ListBox Grid.Row="1" ItemsSource="{Binding Entities}" SelectionMode="Single" SelectionChanged="EditSelectedEntity">
           <!-- Item template -->
        </ListBox>
        <StackPanel Grid.Row="2" Orientation="Horizontal">
            <Button Content="Add" Width="230" Command="{Binding AddEntityCommand}" CommandParameter="{Binding Entities}"/>
            <Button Content="Sync" Width="230" Command="{Binding SyncCommand}" CommandParameter="{Binding Entities}"/>
        </StackPanel>
    </Grid>
</Grid>
...

Ok, let's create ViewModel for our xaml code. In ViewModel folder we need to create MainPageViewModel class. This class will contains properties which we already bind to our View.

ViewModel/MainPageViewModel.cs
public class MainPageViewModel
{
	 	public MainPageViewModel()
 		{
            Entities = new ObservableCollection<ConflictsEntity>(); 		
		}
		public ICommand AddEntityCommand { get; set; }
 		public ICommand SyncCommand { get; set; }
 		
		public ObservableCollection<ConflictsEntity> Entities { get; set; }
}

It is time now to connect View and ViewModel of our MainPage, and to declare method to edit entity when is selected on list.(You can see that we already have added EditSelectedEntity method to SelectionChanged event of our list.).

View/MainPage.xaml.cs
...
public MainPage()
{
    InitializeComponent();
    DataContext = new MainPageViewModel();
}
private void EditSelectedEntity(object sender, SelectionChangedEventArgs e)
{
    // TODO: Open edit entity page. 
}
...

Create switch user control

Before we start implementing add entity command and sync command we have to complete switching users things. We will create separated control for that. (If you already created previous example you can just copy it). In View folder create new Windows Phone User Control and name it SwitchUserControl. This control will contains grid with two columns, first column will present information which user is currently loged in and second will contains button to switch user.

View/SwitchUserControl.xaml
...
	<Grid x:Name="LayoutRoot">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="150"/>
        </Grid.ColumnDefinitions>
        <TextBlock Text="{Binding CurrentUser, StringFormat='Current user is: {0}'}" Style="{StaticResource PhoneTextLargeStyle}" VerticalAlignment="Center"/>
        <Button Grid.Column="1" Content="Switch" Command="{Binding SwitchUser}"/>
    </Grid> 
...

Code below is ViewModel definition for just created control. There are two properties, first one contains information about currently logged in user and second one is a command to switch users. Class implements INotifyPropertyChanged interface to support notification about value changes of properties.

ViewModel/SwitchUserControlViewModel.cs
   	public class SwitchUserControlViewModel : INotifyPropertyChanged
    {
	    public static String CurrentlyLoggendInUser;
        public SwitchUserControlViewModel()
        {
            // TODO 
        }
        public String CurrentUser
        {
            get
            {
                return CurrentlyLoggendInUser;
            }
        }

        public ICommand SwitchUser { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

And again remember to connect ViewModel and View. You need to also create our new control in MainPage grid row. 

SwitchUserControl.xaml.cs
...
        public SwitchUserControl()
        {
            this.DataContext = new SwitchUserControlViewModel();
            InitializeComponent();
        }
...
View/MainPage.xaml
...
<Grid Grid.Row="0">
	<localControls:SwitchUserControl />
</Grid>
... 

While View and ViewModel are almost done it is time to write some buisness logic. We will start with SwitchUserCommand, this command will be responsible for switching between users and also have to notify other classes that user was switched. Create new class in Model folder and implement it like in code below. You can see that there are two events UserSwitched and CanExecuteChanged, first one notify about switching user, second will notify View that execution lock may change. There are also four methods: 'CanExecute' which returns execution lock value, 'Execute' which contains logging in code, 'RaiseCanExecuteChanged' to rise 'CanExecuteChanged' event and 'Mobeelizer_SyncStatusChanged' which is triggered when synchronization status change.

Model/SwitchUserCommand.cs
public class SwitchUserCommand : ICommand
{
    private bool canSwitchUser = true;
    private const String USER_A_PASSWORD = "usera";
    private const String USER_B_PASSWORD = "userb";
    private const String USER_A_LOGIN = "a";
    private const String USER_B_LOGIN = "b";

    public event EventHandler CanExecuteChanged;
    public static event EventHandler UserSwitched;

	public SwitchUserCommand()
    {
        Mobeelizer.SyncStatusChanged += new MobeelizerSyncStatusChangedEventHandler(Mobeelizer_SyncStatusChanged);
    }

    public bool CanExecute(object parameter)
    {
        return canSwitchUser;
    }

    public void Execute(object parameter)
    {
       canSwitchUser = false;
       RaiseCanExecuteChanged();
       switch (SwitchUserControlViewModel.CurrentlyLoggendInUser)
       {
          case USER_A_LOGIN:
               Mobeelizer.Login(USER_B_LOGIN, USER_B_PASSWORD, error =>
               {
                    if (error == null)
                    {
                        SwitchUserControlViewModel.CurrentlyLoggendInUser = USER_B_LOGIN;
                    }
                    else
                    {
                        SwitchUserControlViewModel.CurrentlyLoggendInUser = String.Empty;
                    }
                    EventHandler handler = UserSwitched;
                    if (handler != null)
                    {
                        handler(this, EventArgs.Empty);
                    }
                    Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        canSwitchUser = true;
                        RaiseCanExecuteChanged();
                    }));
                });
                break;
            default:
            case USER_B_LOGIN:
                    Mobeelizer.Login(USER_A_LOGIN, USER_A_PASSWORD, error =>
                    {
                        if (error == null)
                        {
                            SwitchUserControlViewModel.CurrentlyLoggendInUser = USER_A_LOGIN;
                        }
                        else
                        {
                            SwitchUserControlViewModel.CurrentlyLoggendInUser = String.Empty;
                        }
                        EventHandler handler = UserSwitched;
                        if (handler != null)
                        {
                            handler(this, EventArgs.Empty);
                        }
                        Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
                        {
                            canSwitchUser = true;
                            RaiseCanExecuteChanged();
                        }));
                    });
                break;
        }
     }

    public void RaiseCanExecuteChanged()
    {
       EventHandler handler = CanExecuteChanged;
       if (handler != null)
       {
            handler(this, EventArgs.Empty);
       }
    }

    void Mobeelizer_SyncStatusChanged(MobeelizerSyncStatus status)
    {
        if (status == MobeelizerSyncStatus.FINISHED_WITH_SUCCESS || status == MobeelizerSyncStatus.FINISHED_WITH_FAILURE
           || status == MobeelizerSyncStatus.NONE)
        {
           canSwitchUser = true;
        }
        else
        {
            canSwitchUser = false;
        }
        Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
        {
            RaiseCanExecuteChanged();
        }));
    }
}

This code is pretty simple, when user click on switch user button, Execute method will be invoked, while method is executing, execution lock is set, when loging in is finished 'UserSwitched' event will be raised. User can't change while synchronization process is in progress, this functionality is implemented in 'Mobeelizer_SyncStatusChanged' method - when synchronization is in progress, lock flag is up. 

Last thing to do in switching user code is implementing SwichUserControlViewModel constructor. 

ViewModel/SwitchUserControlViewModel.cs
...
 		public SwitchUserControlViewModel()
        {
            SwitchUserCommand command = new SwitchUserCommand();
            SwitchUserCommand.UserSwitched += (object sender, EventArgs e) =>
                {
                    Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        RaisePropertyChanged("CurrentUser");
                    }));
                };
            this.SwitchUser = command;
            this.SwitchUser.Execute(null);
        }
...

Get current user entities

Nice, we can login to mobeelizer and switch between users. It is time to get current user entities. Go back to MainPageViewModel class, in constructor add new method to UserSwitched event and fill entities list when user will be switched.

ViewModel/MainPageViewModel.cs
...
public MainPageViewModel()
{
    Entities = new ObservableCollection<ConflictsEntity>();
    SwitchUserCommand.UserSwitched += new EventHandler(OnUserSwitched);
}

void OnUserSwitched(object sender, EventArgs e)
{
    Deployment.Current.Dispatcher.BeginInvoke(new Action(()=>
    {
        RefreshUserEntities();
    }));
}

public void RefreshUserEntities()
{
    Entities.Clear();
    using (IMobeelizerTransaction transaction = Mobeelizer.GetDatabase().BeginTransaction())
    {
        foreach (ConflictsEntity entity in transaction.GetModelSet<ConflictsEntity>())
        {
            Entities.Add(entity);
        }
    }
}
...

 

Add entity into database

Our entities list is now visible, it is time to implement AddEntityCommand. We will use predefined values to generate new entities. This is an xml file with list of movie titles, download it, put in the project and set build action value to 'content'. Create new class in Model folder, called AddEntityCommand and take a look on code below. There is one thing more, XDocument class is in System.Xml.Linq namespace, remember to add this component to project references. 

Model/AddEntityCommand.cs
public class AddEntityCommand : ICommand
{
    private List<String> movieTitles;
    private Random rand = new Random();
    public AddEntityCommand()
    {
        XDocument movies = XDocument.Load("movies.xml");
        this.movieTitles = new List<string>();
        foreach (XElement title in movies.Root.Element("movieTitles").Elements("item"))
        {
            movieTitles.Add(title.Value);
        }
    }
    public bool CanExecute(object parameter)
    {
        return Mobeelizer.IsLoggedIn;
    }
    public event EventHandler CanExecuteChanged;
    public void Execute(object parameter)
    {
        ObservableCollection<ConflictsEntity> entities = (ObservableCollection<ConflictsEntity>)parameter;
        using (IMobeelizerTransaction transaction = Mobeelizer.GetDatabase().BeginTransaction())
        {
            ConflictsEntity entity = new ConflictsEntity();
            entity.Title = movieTitles[rand.Next(0, movieTitles.Count - 1)];
            entity.Score = rand.Next(1, 5);
            transaction.GetModelSet<ConflictsEntity>().InsertOnSubmit(entity);
            transaction.SubmitChanges();
            Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                entities.Add(entity);
            }));
        }
    }
    public void RaiseCanExecuteChanged()
    {
        EventHandler handler = CanExecuteChanged;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}

It is easy, right? In constructor we are loading movie titles from xml file and storing them in list. When Execute method is triggered we are getting random value from list, creating new entity and saving it in database. Take a look at CanExecute method, it returns true only if user is loged in to Mobeelizer, this is because there is no access to database for not authorized users. 

Edit entities

Ok if we can add new entity it is time to edit it value. We will edit only score value of each entity. We will use seperated page for that. Create new Windows Phone Portrait Page and call it EditEntityPage, remove LaourRoot content and repace it with:

View/EditEntityPage.xaml
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock Text="{Binding Title, StringFormat='Set {1} movie score:'}" />
        <Button Content="1" Grid.Row="1" Command="{Binding SetScoreCommand}" CommandParameter="1"/>
        <Button Content="2" Grid.Row="2" Command="{Binding SetScoreCommand}" CommandParameter="2"/>
        <Button Content="3" Grid.Row="3" Command="{Binding SetScoreCommand}" CommandParameter="3"/>
        <Button Content="4" Grid.Row="4" Command="{Binding SetScoreCommand}" CommandParameter="4"/>
        <Button Content="5" Grid.Row="5" Command="{Binding SetScoreCommand}" CommandParameter="5"/>
    </Grid>

Our new page contains five buttons and one label to show information about currently edited entity. ViewModel of this page is preaty simple and should look like this. 

EditEntityPageViewModel.cs
public class EditEntityPageViewModel
{
    public EditEntityPageViewModel(String entityTitle, String entityGuid)
    {
        Title = entityTitle;
        // TODO : Create SetScoreControl here. 
    }
    public String Title { get; set; }
    public ICommand SetScoreCommand { get; set; }
}

Next step is creating command to set each score value. Create new class SetScoreCommand in Model folder and implement it like this.

Model/SetScoreCommand.cs
public class SetScoreCommand : ICommand
{
    private String entityGuid;
    public SetScoreCommand(String entityGuid)
    {
        this.entityGuid = entityGuid;
    }
    public bool CanExecute(object parameter)
    {
        return Mobeelizer.IsLoggedIn;
    }
    public event EventHandler CanExecuteChanged;
    public void Execute(object parameter)
    {
        int score = Int32.Parse(parameter.ToString());
        using (IMobeelizerTransaction transaction = Mobeelizer.GetDatabase().BeginTransaction())
        {
            var query = from ConflictsEntity e in transaction.GetModelSet<ConflictsEntity>() where e.Guid == entityGuid select e;
            ConflictsEntity entity = query.Single();
            if (entity != null)
            {
                entity.Score = score;
            }
            transaction.SubmitChanges();
        }
        ((PhoneApplicationFrame)Application.Current.RootVisual).GoBack();
    }
}

When you creates our new control you have to specify which entity will be edited, because of that, constructor gets guid value. We also want to use this command in all buttons, so Execute method need to get score value. When Execute method is triggered we are opening new transaction, finding entity and changing it value. On the end of this method we are initializing go back to previous page method.

Let's go back to edit page ViewModel to create new command.

ViewModel/EditEntityPageViewModel.cs
...
public EditEntityPageViewModel(String entityTitle, String entityGuid)
{
    Title = entityTitle;
    SetScoreCommand = new SetScoreCommand(entityGuid);
}
...

Next, connect View and ViewModel. This time we can't do it in page constructor because we have to know title and guid to create ViewModel object. We will use OnNavigatedTo method where we get values sent from previos page. 

EditEntityPage.xaml.cs
...
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    if (this.NavigationContext.QueryString.ContainsKey("guid") && this.NavigationContext.QueryString.ContainsKey("title"))
    {
        String guid = this.NavigationContext.QueryString["guid"];
        String title = this.NavigationContext.QueryString["title"];
        this.DataContext = new EditEntityPageViewModel(title, guid);
    }
    base.OnNavigatedTo(e);
}
...

To complete editing process go back to MainPage.xaml.cs file and implement EditSelectedEntity method. There is also necessity to create method which will refresh entities list when user goes back to this page because some entity value may change. 

View/MainPage.xaml.cs
...
private bool back = false;

private void EditSelectedEntity(object sender, SelectionChangedEventArgs e)
{
    foreach(Object item in e.AddedItems)
    {
        back = true;
        this.NavigationService.Navigate(new Uri(String.Format("/View/EditEntityPage.xaml?guid={0}&title={1}", (item as ConflictsEntity).Guid, (item as ConflictsEntity).Title), UriKind.Relative));
        break;
    }
}

protected override void  OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    if (back)
    {
        (DataContext as MainPageViewModel).RefreshUserEntities();
    }
    back = false;
 	base.OnNavigatedTo(e);
}
...

Synchronize with mobeelizer

It is time for synchronization now. Create new class SyncCommand in Model folder and implement it like this:

Model/SyncCommand.cs
public class SyncCommand : ICommand
{
    private bool canSyncFlag = true;
    public bool CanExecute(object parameter)
    {
        return Mobeelizer.IsLoggedIn && canSyncFlag;
    }
    public event EventHandler CanExecuteChanged;
    public void Execute(object parameter)
    {
        ObservableCollection<ConflictsEntity> entities = (ObservableCollection<ConflictsEntity>)parameter;
        canSyncFlag = false;
        RaiseCanExecuteChanged();
        Mobeelizer.Sync(error =>
        {
            Deployment.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                if (error == null)
                {
                    entities.Clear();
                    if (Mobeelizer.IsLoggedIn)
                    {
                        using (IMobeelizerTransaction transaction = Mobeelizer.GetDatabase().BeginTransaction())
                        {
                            foreach (ConflictsEntity entity in transaction.GetModelSet<ConflictsEntity>())
                            {
                                entities.Add(entity);
                            }
                        }
                    }
                }
                canSyncFlag = true;
                RaiseCanExecuteChanged();
            }));
        });
    }
    public void RaiseCanExecuteChanged()
    {
        EventHandler handler = CanExecuteChanged;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}

You can synchronize your data only if user is logged in and if other sync process is not in progress. This condition is defined in CanExecute method. Let's take a look at Execute method. It is actually just calling Mobeelizer sync method. When synchronization finished without any errors given entities list is refreshed, and that is all. 


Now create our new classes in MainPageViewModel constructor, and raise CanExecuteChange events when user change.

 

ViewModel/MainPageViewModel.cs
...
public MainPageViewModel()
{
    Entities = new ObservableCollection<ConflictsEntity>();
    AddEntityCommand = new AddEntityCommand();
    SyncCommand = new SyncCommand();
    SwitchUserCommand.UserSwitched += new EventHandler(OnUserSwitched);
}
void OnUserSwitched(object sender, EventArgs e)
{
    Deployment.Current.Dispatcher.BeginInvoke(new Action(()=>
    {
        (AddEntityCommand as AddEntityCommand).RaiseCanExecuteChanged();
        (SyncCommand as SyncCommand).RaiseCanExecuteChanged();
        RefreshUserEntities();
    }));
}
...

Display models on the list

Great application is almost ready, and you can test it now. List of entities is visible but there is only information about entites class name. Let's create some xaml code to show added movies and theirs owners. To see if entity is edited, in conflict or synchronized we will create value converter which will convert our entity to concrete color.

Create new class EntityStateToColorConverter in ViewModel folder.

ViewModel/EntityStateToColorConverter.cs
public class EntityStateToColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        MobeelizerWp7Model entity = value as MobeelizerWp7Model;
        if (entity != null)
        {
            if (entity.Conflicted)
                return "red";
            else if (entity.Modified)
                return "blue";
        }
        return "black";
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

 

While converter is ready let's take a look at MainPage.xaml file. First of all we need to add our converter to page resources (Remember to add ViewModel namespace in page root attribute). 
View/MainPage.xaml
<phone:PhoneApplicationPage 
    ...
    xmlns:mobeelizerConverters="clr-namespace:MobeelizerConverters"
    xmlns:converters="clr-namespace:...ViewModel" >
 
    <phone:PhoneApplicationPage.Resources>
        <mobeelizerConverters:OwnerNameToIconConverter x:Key="OwnerConverter"/>
        <converters:EntityStateToColorConverter x:Key="EntityStateToColorConverter"/>
    </phone:PhoneApplicationPage.Resources>
    ...
</phone:PhoneApplicationPage>

 

Secondly, create ListBox items template using our converter.
View/MainPage.xaml
...
<ListBox.ItemTemplate>
    <DataTemplate >
        <Grid Margin="1" Background="{Binding Converter={StaticResource EntityStateToColorConverter}}">
            <Grid Margin="2" Height="55" Width="430">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition Width="40"/>
                </Grid.ColumnDefinitions>
                <Grid >
                    <Grid.RowDefinitions>
                        <RowDefinition />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <TextBlock Text="{Binding Title}" FontSize="26"/>
                    <TextBlock Height="25" Text="{Binding Score, StringFormat='Score is: {0}' }" Grid.Row="1" HorizontalAlignment="Left" Margin="10,0,0,0"/>
                </Grid>
                <Image Source="{Binding Owner, Converter={StaticResource OwnerConverter}}" Grid.Column="1" VerticalAlignment="Center" HorizontalAlignment="Right" />
            </Grid>
        </Grid>
    </DataTemplate>
</ListBox.ItemTemplate>
...

Conflicts example is ready, you can test it now on as many devices as you can find. The easiest scenario is:

  • Add entity, sync, switch user and syc again
  • Choose one movie title that all users have. Now change score and synchronize updated data.
  • Switch user but do not sync yet.
  • Modify the same movie with another user and then synchronize.

Try other scenarios to understand how mobeeliser conflicts works. You can change conflicts resolving properties to see differences between them. You can also browse your data in App Designer using Data Browser tool.

Conclusion

To conclude, this is the simple example of conflict detecting with Mobeelizer. Our model consists of two fields. We can create sample records, edit them and synchronize with Mobeelizer cloud.


Attachments: