MasterDetail Visible if loggedin - xamarin

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

Related

Xamarin Android: Dynamic update UI based on Viewmodel

In my android project, the webview url is dynamic. I am using mvvmcros binding on view side but its not being dynamic. If the url content on view model is changing its not being updated on view. Can anyone help me out?
View
public string WebContentUrll { get; set; }
protected override void OnCreate(Android.OS.Bundle bundle)
{
var bindingSet = this.CreateBindingSet<view, ViewModel>();
bindingSet.Bind(this).For(v => v.WebContentUrll).To(vm => vm.WebContentUrl).TwoWay();
}
ViewModel
private string webContentUrl;
public string WebContentUrl
{
get
{
return webContentUrl;
}
set
{
webContentUrl = value;
RaisePropertyChanged(() => webContentUrl);
}
}
public void Init()
{
webContentUrl = "https://.."'
}
The value of web content url in the view model changes after the page is loaded but the android view is not able to get the new updated url.
Can anyone please advise. Thank you.
Update
The web view is opened on a button click and the url is updated after the page loads and before the button is clicked
From you description in the opening post. In your Activity you have defined a property WebContentUrll. You want to bind this and update something when it is changed.
The definition of WebContentUrll is:
public string WebContentUrll { get; set; }
This is not wrong and you should see the value reflected in WebContentUrll when it changes from the ViewModel through your binding. However, there is no code updating any visual states, views or anything based on that property.
If you have a WebView you want to change content for, you could modify your property to something like:
private string _webContentUrll;
public string WebContentUrll
{
get => _webContentUrll;
set
{
_webContentUrll = value;
_webView.LoadUrl(_webContentUrll);
}
}
Given that _webView is your instance of a WebView.

What is the proper way to have a ListView show a LINQ query and update dynamically?

I'm new to Xamarin and C#, so apologies in advance for any mistakes I make.
In my app, I have a list of plants. When a plant is selected, I have a detail view of info about the plant. In the detail view, I have a button that adds or removes the plant from a shopping list.
To implement this, I have a class named MyPlant, with a field called InCart, and a method ToggleInCart that the button calls.
(note that I didn't paste in some code to simplify this question as much as possible)
public class MyPlant : INotifyPropertyChanged
{
string name;
bool inCart;
...
public bool InCart
{
set
{
if (inCart != value)
{
inCart = value;
OnPropertyChanged("InCart");
}
}
get { return inCart; }
}
public ICommand ToggleCartStatus
{
get
{
if (_toggleCartStatus == null)
{
_toggleCartStatus = new Command(() => InCart = !InCart);
}
return _toggleCartStatus;
}
I have another class called PlantList, which has a method PlantsInCart that uses LINQ to return an ObservableCollection of MyPlant where InCart is true.
public class PlantList : INotifyPropertyChanged
{
public ObservableCollection PlantsInCart
{
private set { }
get
{
ObservableCollection list = new ObservableCollection(myPlants.Where(i => i.InCart));
return list;
}
}
In my XAML, I have a ListView bound to PlantsInCart.
Everything works as I want EXCEPT when I remove the selected plant, the list doesn't update to show the plant is missing even though the data underneath it is correctly updated. If I refresh the list by going to a different page and coming back, then the list shows the right plants.
I suspect this doesn't work because the change in the InCart field isn't bubbling up high enough to that the ListView hears that it is supposed to update.
Can anybody advise me on the proper way to implement this kind of feature? In other words, how should you implement a scenario where you have a list that should update when a property of an item in the list changes?

UI action in middle of MvxCommand

I am using MvvmCross, but this may be general command binding.
When user click a button, the application require an extra input data before proceed to what I want to do in the actual command. The problem that I cannot call an UI action in middle of ViewModel, so just binding MvxCommand (or any ICommand) would not work.
One may ask why:
1) I don't put an input on the UI and user can enter data before click button -> I don't have space.
2) Make default data, and let user change it later -> This my first though, but user tend to forget to change it later!!
So can someone come up with a solution? The only thing I can think of is forgetting command binding, and have code behind pop the ui for extra data, then call a method in view model!
Thanks
There are several ways to do this.
My personal preferred way is to use an "Interaction Request" - something that I learnt from the Prism framework from Microsoft patterns and practices.
In Mvx, you can do this using an IMvxInteraction property on your ViewModel. An example of this is shown in https://github.com/slodge/BindingTalk/blob/master/BindingTalk.Core/ViewModels/QuestionViewModel.cs
Each time an interaction is requested, the ViewModel provides an object to the View - in this case a YesNoQuestion:
public class YesNoQuestion
{
public Action YesAction { get; set; }
public Action NoAction { get; set; }
public string QuestionText { get; set; }
public YesNoQuestion()
{
YesAction = () => { };
NoAction = () => { };
}
}
The ViewModel exposes the requester using an IMvxInteraction<TQuestion> property:
public class QuestionViewModel
: MvxViewModel
{
private MvxInteraction<YesNoQuestion> _confirm = new MvxInteraction<YesNoQuestion>();
public IMvxInteraction<YesNoQuestion> Confirm
{
get { return _confirm; }
}
public IMvxCommand GoCommand
{
get
{
return new MvxCommand(() =>
{
var question = new YesNoQuestion()
{
QuestionText = "Close me now?",
YesAction = () => Close(this),
};
_confirm.Raise(question);
});
}
}
}
The view on each platform can then bind and subscribe to the interaction request property. This is a little fiddly - because it uses weak references to prevent memory leaks - especially on iOS, but also possible on other platforms too.
Some example Droid code for this is in:
https://github.com/slodge/BindingTalk/blob/master/BindingTalk.Droid/Views/2%20%20More%20Controls/QuestionView.cs
with AXML in https://github.com/slodge/BindingTalk/blob/master/BindingTalk.Droid/Resources/Layout/QuestionView.axml
Sorry for the confusing ConfirmationView and QuestionView names here - the first is an Android View, the second is an Mvvm View and an Android Activity.
Also, please note that when implementing Dialogs in Android, then you need to be careful about screen rotation - as Android's Activity lifecycle can very much confuse things here - easiest mecahnism (I find) is to just handle screen rotation yourself rather than allowing Android to handle it.

Prism Shell buttons shared by modules

I am using Prism 2, trying to add four navigation buttons (First Record, Last Record, Previous Record, Next Record) in shell to be used by modules. I also want these buttons to be disable if active View/ViewModel does not provide these functions.
I tried using events but didn't know how to achieve my second goal regarding disabling buttons. It seems I need to check current active View/ViewModel to see if they subscribed the click event during View switch. But I think publisher should be unaware of subscriber...
Somehow I tried my own way. I create an IDocNavigation interface which has four method corresponding to my four buttons. At runtime I check modules' ViewModel if they implemented that interface or not, and change the ICommand on fly. Below is my code. I include one LastRecordCommand only:
public ShellViewModel(Views.Shell shell)
{
this.Shell = shell;
shell.DataContext = this;
shell.MainDocking.ActivePaneChanged += (s, e) =>
{
if (e.NewPane.Content is UserControl &&
((UserControl)e.NewPane.Content).DataContext is IDocumentNavigate)
{
IDocumentNavigate vm = ((UserControl)e.NewPane.Content).DataContext as IDocumentNavigate;
LastRecordCommand = new RelayCommand(x => vm.GotoLastRecord(), x => true);
}
else
{
LastRecordCommand = new RelayCommand(x => { }, x => false);
}
};
//...
I feel these are quite ugly. Creating an empty RelayCommand is also stupid. How can I improve ? or how can I achieve disabling command if event is more suitable in my case ?
You can make use of CompositeCommand in prism.
Define a globally available CompositeCommand
public static readonly CompositeCommand FirstRecord= new CompositeCommand(true);
Then in your your module view models
class Module1
{
public DelegateCommand Module1Firstrecord{ get; set; }
Module1()
{
Module1Firstrecord = new DelegateCommand(this.FirstRecord, CanExecute);
}
private void FirstRecord()
{
//do whatever you want
}
private bool CanExecute()
{
return true;
}
private void Module1_IsActiveChanged(object sender, EventArgs e)
{
//Find if your window is acive
// if it is active Module1Firstrecord.IsActive = true
//else false.
}
}
With IActiveAware you can handle the active window scenario easily. According to whether your active module have a handler for the command on not the buttons will enable/disable.

MVC3 shared-search model confusion

(couldn't think of a better title, sorry)
So I've got my layout page, on this page there is a searchbar + options. Choosing whatever, should take you through to the search page, with the results etc. Fairly standard. What I've done to get this working is to create a MasterModel class, with a SearchDataModel class member on it. This SearchDataModel contains the various parameters for the search (search term, what fields to search on etc).
I've then strongly typed my layout page to the MasterModel class, and using a Html.BeginForm... I've constructed the search form for it. However all the checkboxes relating to the fields aren't checked by default, even though the default value for all the fields is true (via a private getter/setter setup).
Yet when I submit the form to the SearchController, all the checkboxes are set to true. So I'm a bit confused as to why it knows they should be true, yet not set the checkboxes to be checked?
Putting breakpoints in key places seems to show that the model isn't insantiated on the get requests, only the post to the Search controller?
I may be going about this all wrong, so if so, pointers as to the right way always appreciated.
public class MasterModel {
public SearchDataModel SearchModel { get; set; }
}
public class SearchDataModel{
private bool _OnTags = true;
private bool _OnManufacturers = true;
private bool _OnCountries = true;
[Display(Name= "Tags")]
public bool OnTags {
get { return _OnTags; }
set { _OnTags = value; }
}
[Display(Name= "Manufacturers")]
public bool OnManufacturers {
get { return _OnManufacturers; }
set { _OnManufacturers = value; }
}
[Display(Name= "Countries")]
public bool OnCountries {
get { return _OnCountries; }
set { _OnCountries = value; }
}
[Required]
[Display(Name="Search Term:")]
public string SearchTerm { get; set; }
}
Then in the _layout page:
#Html.CheckBoxFor(m => m.SearchModel.OnTags, new { #class="ddlCheckbox", #id="inpCheckboxTag" })
#Html.LabelFor(m =>m.SearchModel.OnTags)
Make sure you return a MasterModel with initialized SearchModel from your views:
public ActionResult Index()
{
var model = new MasterModel
{
SearchModel = new SearchDataModel()
};
return View(model);
}
Another possibility to implement this functionality than strongly typing your master layout to a view model is yo use Html.Action as shown by Phil Haack in his blog post.

Resources