Remeber User Update MasterDetail - xamarin

I have a master detail VievModel where I am updating the menuEntries once user is logged in, now i have added remember me functionality which works fine. But i have issue with updating the entries, I will explain the steps
Users details are remembered
User starts the application and is logged in automatically
User opens the master detail menu and must click on the SignIn label once he goes through (not signung in) just displays the page and presses the close button then the label Profile is displayed.
The update is very simple and I debbuged the whole process and once user start the application with hist details remembered the
bool LoggedIn = true
Do you have any idea?
private void UpdateData()
{
if (LoggedUser.LoggedIn)
{
MainMenuEntries.Add(new MenuEntry
{
Name = AppResources.A_StringCategoryUserProfile,
Icon = IconsFont.User,
CreatePage = () => new UserProfile()
});
}
else if (LoggedUser.LoggedOffline)
{
MainMenuEntries.Add(new MenuEntry
{
Name = AppResources.A_StringCategoryUserProfile,
Icon = IconsFont.User,
CreatePage = () => new UserProfile()
});
}
else
{
MainMenuEntries.Add(new MenuEntry
{
Name = AppResources.A_StringCategoryLoginSignUp,
Icon = IconsFont.User,
CreatePage = () => new Login()
});
}
}

Related

MasterDetail Visible if loggedin

I am using Master Detail navigation and I want some menu entries to be visible and some not depending on the user logged in status.
I created bool in my model
public bool VisibleWhenLoggedIn { get; set; }
public bool VisibleWhenLoggedIn(User loggedUser, bool loggedIn = true)
{
if (loggedIn)
{
MainMenuEntries = new List<MenuEntry>();
var login = MainMenuEntries.ElementAt(2).VisibleWhenLoggedIn == false;
}
return false;
}
and then in my entry i use this
VisibleWhenLoggedIn = false,
But this doesnt workd. Do you have any suggestions?
According to your description, you just want to display different menu for MasterDetailPage when different user login, am I right?
If yes, I agree with Jason's opinion, the menu is the ListView, you can change ItemSource based on different user.
I do one sample that you can take a look:
This is the sample at github:
https://github.com/CherryBu/MasterAPP

ReactiveUI ReactiveCommand and Xamarin 4.0 Shell Navigation

Using Xamarin Forms 4.0 with the new Shell feature, I have a button on a page .Let's call this page the Start Page.
When I press the button the user is navigated to a Second Page using Shell.Current.GoToAsync.
When the user later navigates back to the Start Page the button is now deactiviated. But why?
Here is the code in the view model:
public class SomeViewModel : ReactiveObject
{
private ReactiveCommand<Unit, Unit> _someCommand;
public ReactiveCommand<Unit, Unit> SomeCommand
{
get => _someCommand;
set => this.RaiseAndSetIfChanged(ref _someCommand, value);
}
public SomeViewModel
{
SomeCommand = ReactiveCommand.CreateFromTask<Unit>(async x =>
{
await Shell.Current.GoToAsync("//Root/SomePage");
}).Subscribe();
}
By trial and error, I found a solution.
Specifically, by making the following change to the definition of SomeCommand, the button will no longer be disabled when the user returns to the Start Page:
[...]
SomeCommand = ReactiveCommand.CreateFromTask<Unit>(async x =>
{
await Task.CompletedTask;
})
.Select(_ => Observable.FromAsync(() => Shell.Current.GoToAsync("//Root/SomePage")}")))
.Concat()
.Subscribe();
[...]
Can anyone expain what is going on here? Why does the first approach not work, and why does the second approach work? To me the two approaches look more or less identical.
I'm using ReactiveUI version v9.17.4. So far I've only tested this on iOS.
UPDATE: Turned out to be a threading issue.
Use Interactions
public static class Interactions
{
public static readonly Interaction<string, Unit> Navigate = new Interaction<string, Unit>();
}
then, in AppShell constructor:
Interactions.Navigate.RegisterHandler(async context =>
{
await Current.GoToAsync(context.Input);
context.SetOutput(Unit.Default);
}
and in your ViewModel constructor:
ReactiveCommand<Unit, Unit> NavigateToSettingsCommand = ReactiveCommand.CreateFromObservable(() => Interactions.Navigate.Handle("settings"))

How to load view page before executing functions in Xamarin Forms?

How to load the view page before executing any functions?
App Process:
1. User will click login button
2. I will navigate to sync page
3. sync page will execute six (6) functions after executing 6 functions it will redirect to my main menu page
The problem is with my number 1 and 2 process. When the user click the login button it will be stuck in my login page then go directly to my main menu page. How can I see the sync page before redirecting to main menu page.
public SyncPage (string host, string database, string contactID)
{
InitializeComponent();
new Task(SyncSetup).Start();
}
async void SyncSetup()
{
Deletedata();
InsertUserData(host, database, contactID);
InsertCAFData(host, database, contactID);
InsertContactsData(host, database, contactID);
InsertActivityData(host, database, contactID);
Device.BeginInvokeOnMainThread(() =>
{
// Assuming this function needs to use Main/UI thread to move to your "Main Menu" Page
OnSyncComplete(host, database, contactID);
});
}
I would move those functions/processes to a separate thread/task, a super easy way is to use a fire & forget Task and have that task handle those setup processes and then move back to the UI thread in order to move your "Main Menu" page.
Something like this:
string contactID; string host; string database;
public SyncPage (string contactID, string host, string database)
{
InitializeComponent();
this.contectID = contactID; this.host = host; this.database = database;
new Task(SyncSetup).Start(); // Or do this in OnAppearing override
}
protected override void OnAppearing()
{
base.OnAppearing();
new Task(SyncSetup).Start(); // This could be an await'd task if need be
}
async void SyncSetup()
{
Deletedata();
InsertUserData(host, database, contactID);
InsertCAFData(host, database, contactID);
InsertContactsData(host, database, contactID);
InsertActivityData(host, database, contactID);
Device.BeginInvokeOnMainThread(() =>
{
// Assuming this function needs to use Main/UI thread to move to your "Main Menu" Page
OnSyncComplete(host, database, contactID);
});
}

UI gets stuck while loading lot of data from realm

I am trying to show 10,000 contacts on listview in xamarin forms using realm. But whenever user traverse to contact listing screen
it gets freezed and loads after a while.
Moreover , i have provided an option to search from list as well and that too gets stuck as search if performing on UI thread.
Following is the code to load data from realm
public override async Task Initialize(Object data )
{
private Realm _realmInstance = getRealm();
if (contactList != null)
{
contactList.Clear();
}
contactList = _realmInstance.All<Contact>().OrderByDescending(d => d.contactId).ToList();
// here the binding happens with realm data
contacts = new ObservableCollectionFast<Contact>(contactList);
}
public ObservableCollectionFast<Contact> contacts
{
get { return items; }
set
{
items = value;
OnPropertyChanged("contacts");
}
}
as it was taking time in loading i thought to fetch realm data in background and bind it on UI thread as follows
but that is throwing error
realm accessed from incorrect thread
await Task.Run(() => {
contactList = _realmInstance.All<Contact>().OrderByDescending(d => d.contactId).ToList();
});
if (contactList.Count() > 0)
{
ContactListView = true;
AddContactMsg = false;
}
else
{
AddContactMsg = true;
}
Device.BeginInvokeOnMainThread(() =>
{
contacts = new ObservableCollectionFast<Contact>(contactList);
});
i wanted to try limiting the results by using TAKE function of LINQ but unfortunately its not supported by realm yet. not sure how i can smoothly load records from realm to listview.
EDIT
as per the SushiHangover i have changed things from IList to IQueryable
public IQueryable<Contact> contacts
{
get { return items; }
set
{
items = value;
OnPropertyChanged("contacts");
}
}
public override async Task Initialize(Object data )
{
_realmInstance = getRealm();
contacts = dbContactList= _realmInstance.All<Contact>();
}
so far search is working pretty smoothly but IQueryable change leads to another issue. on repeatedly performing following steps results in app crash
tap on list item
detail page gets open then press back
scroll down to few records
perform step 1 and repeat
this results into stackoverflow error
04-19 06:05:13.980 F/art ( 3943): art/runtime/runtime.cc:289]
Pending exception java.lang.StackOverflowError thrown by 'void
md5b60ffeb829f638581ab2bb9b1a7f4f3f.CellAdapter.n_onItemClick(android.widget.AdapterView,
android.view.View, int, long):-2' 04-19 06:05:13.980 F/art (
3943): art/runtime/runtime.cc:289] java.lang.StackOverflowError: stack
size 8MB
Link to entire log file
code to fire item click command is
public ICommand OnContactSelectCommand => new Command<Contact>(OnContactSelect);
following code will open ups a detail page
private async void OnContactSelect(Contact contact)
{
if (contact != null)
{
await NavigationService.NavigateToAsync<ContactDetailViewModel>(contact.mContactId);
}
}
Note:
when i replace IQueryable with List i do not face any error
somehow my issue is related to realm github thread where user is getting exception on listView.SelectedItem = null while using IQueryable
here is my code of list view item tap
private static void ListViewOnItemTapped(object sender, ItemTappedEventArgs e)
{
var listView = sender as ListView;
if (listView != null && listView.IsEnabled && !listView.IsRefreshing)
{
// have commented this line because it was crashing the app
//listView.SelectedItem = null;
var command = GetItemTappedCommand(listView);
if (command != null && command.CanExecute(e.Item))
{
command.Execute(e.Item);
}
}
}

Create New Form not reload after save

working good in crm 2011 but not in crm 2013 online
On opportunity Entity create New record form i show only:
1.Some attributes(all other fields/Section/Tabs are hide on form)
2.and an Html button like
function OnFormLoad(){
if(Xrm.Page.ui.getFormType() == 1 ) {
SetRequiredLevelToNone();
createHtmlButton("Save");
HideTabsAndSections()
}
else {
}
}
On click of Html button following function is triggered.
function showWholeForm() {
Xrm.Page.data.entity.save();
}
I want to show all the fields of form after save, means want to reload whole form.
As working in crm 2011
The save method in CRM 2013 will not refresh the page anymore. The new refresh method should be used in this case, as follows:
Xrm.Page.data.refresh(save).then(successCallback, errorCallback);
save: Boolean value to be passed as true if data should be saved
after it is refreshed.
successCallback: Function to call when the operation succeeds
errorCallbak: Function to call when the operation fails, that will be passed an object with 2 properties - error code (number) and localized error message (string)
You could find the method documented here: http://msdn.microsoft.com/en-us/library/dn481607(v=crm.6).aspx
I think you should first disable the auto-save if you want consistency with CRM 2011.
function OnSaveDisableAutoSave(eventArgs) {
var saveType = eventArgs.getEventArgs().getSaveMode();
if (saveType == 70 ||saveType == 2)
{ //Disable AutoSave
eventArgs.preventDefault();
}
}
and then
function showWholeForm() {
Xrm.Page.data.refresh(true).then(successCallback, errorCallback);
}
To fix this you can do:
var saved = false;
function onLoad(){
checkIfFormShouldBeReadOnly();
attachEvent();
}
function attachEvent() {
Xrm.Page.data.entity.addOnSave(executeOnSave);
}
function executeOnSave(saveExecution) {
if (!saved) {
saved = true;
Xrm.Page.data.save().then(
function () {
checkIfFormShouldBeReadOnly();
},
function (errorCode, message) {
Xrm.Page.data.refresh();
}
);
}
}

Resources