What purpose does [QueryProperty("Name", "name")] serve in a Xamarin Shell app? - xamarin

Looking at the Xamarin shell samples I see this:
namespace Xaminals.Views
{
[QueryProperty("Name", "name")]
public partial class CatDetailPage : ContentPage
{
public string Name
{
set
{
BindingContext = CatData.Cats.FirstOrDefault(m => m.Name == Uri.UnescapeDataString(value));
}
}
public CatDetailPage()
{
InitializeComponent();
}
protected override bool OnBackButtonPressed()
{
return base.OnBackButtonPressed();
}
}
}
Does anyone know the purpose of: [QueryProperty("Name", "name")]

It allows you to pass parameters to a page when using url navigation
It is discussed here

For pages to receive data when navigating, the page class must be decorated with a QueryPropertyAttribute.
When you set
[QueryProperty("Name", "name")]
The first argument - "Name" refers to the name of the property that will be receiving the data.
The second argument - "name" refers to the parameter id that will be passed in the query
You can read more in the official documentation

Related

Navigation does not exist in current context Xamarin Comunity Toolkit Extensions

I want to open a pop up window using xamarin comunity toolkit extensions but when i try to call
Navigation it says that it does not exist even if i have included xct.extensions. There is NavigationExtensions but I don't know what I'm supposed to pass as first parameter and it says that my FilterPopup is of incorect type
using Xamarin.CommunityToolkit.Extensions;
namespace Appointments.ViewModels
{
public class WallViewModel
{
public ObservableCollection<Stylist> Stylists { get; set; }
public AsyncCommand OpenModalFiltersComand;
public WallViewModel()
{
OpenModalFiltersComand = new AsyncCommand(OpenModalFilters);
}
async Task OpenModalFilters()
{
NavigationExtensions.ShowPopup(AppShell, FilterPopup);
Navigation // error
}
}
}
My FilterPopup
namespace Appointments.Popups
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FilterPopup : Popup
{
public FilterPopup()
{
InitializeComponent();
}
}
}
EDIT---------
I'm using shell navigation
ShowPopup takes an INavigation and an instance of a PopupBase. Navigation is a property of Page types, so your VM does not have a reference to it.
var nav = App.Current.MainPage.Navigation;
var filter = new FilterPopup();
NavigationExtensions.ShowPopup(nav, filter);

Xamarin FOrms routing with passing parameters in Shell

In my codeBehind of my Page1 I have:
{
//do not select item
((ListView)sender).SelectedItem = null;
//go to stockDetailsPage
await Shell.Current.GoToAsync("postlogin/stockdetails?tickerSymbol=AAPL.NASDAQ");
}
As you can see I hardcoded the value in order to test it.
Earlier it was without param, and it work, now I need to pass param tickerSymbol.
And in my stockDetailsPage in my ViewModel I added
[QueryProperty("TickerSymbol", "tickerSymbol")] above my class
and in my class I declared properties:
public string TickerSymbol
{
set { SetProperty(ref tickerSymbol, Uri.UnescapeDataString(value)); }
get { return tickerSymbol; }
}
So in my constructor of that vm, I now want to call method with input argument of that param, but Im getting null all the time.
Can you suggest me where Im wrong?
As Xamarin doc said it should be able to pass param to the class for the page's BindingContext, I tried the following and it works:
in code behind, set BindingContext to your ViewModel:
TestParamViewModel testParamViewModel;
public TestPage()
{
InitializeComponent();
testParamViewModel = new TestParamViewModel();
this.BindingContext = testParamViewModel;
}
Add QueryPropertyAttribute to your ViewModel:
[QueryProperty("Name", "name")]
class TestParamViewModel
{
string name;
public string Name
{
set
{
name = Uri.UnescapeDataString(value);
}
}
}
call navigation:
await Shell.Current.GoToAsync("testpage?name=Abyssinian");
Hope it helps.

Dynamic ViewModel navigation

I am trying to find a way to be able to set from the View to what ViewModel I have to navigate. This is to be able to change the navigation flow without changing the core project.
I thought the easier way would be creating an interface, setting the target ViewModel there and injecting the interface into the ViewModel to then perform the navigation.
public interface IModelMapping
{
MvxViewModel ViewModelToNavigate();
}
public class MyViewModel : MvxViewModel
{
readonly IMvxNavigationService navigationService;
readonly IModelMapping modelMapping;
public MyViewModel(IMvxNavigationService navigationService, IModelMapping modelMapping)
{
this.navigationService = navigationService;
this.modelMapping = modelMapping;
}
public IMvxAsyncCommand GoContent
{
get
{
IMvxViewModel vm = modelMapping.ViewModelToNavigate();
IMvxAsyncCommand navigateCommand = new MvxAsyncCommand(() => navigationService.Navigate<vm>());
return navigteCommand;
}
}
}
The problem with this code is I am getting an error setting the navigationService.Navigate(). The error is 'vm is a variable but it is used like a type'
What about using the URI navigation together with the facade? See also https://www.mvvmcross.com/documentation/fundamentals/navigation#uri-navigation
Say you are building a task app and depending on the type of task you want to show a different view. This is where NavigationFacades come in handy (there is only so much regular expressions can do for you).
mvx://task/?id=00 <– this task is done, show read-only view (ViewModelA)
mvx://task/?id=01 <– this task isn’t, go straight to edit view (ViewModelB)
[assembly: MvxRouting(typeof(SimpleNavigationFacade), #"mvx://task/\?id=(?<id>[A-Z0-9]{32})$")]
namespace *.NavigationFacades
{
public class SimpleNavigationFacade
: IMvxNavigationFacade
{
public Task<MvxViewModelRequest> BuildViewModelRequest(string url,
IDictionary<string, string> currentParameters, MvxRequestedBy requestedBy)
{
// you can load data from a database etc.
// try not to do a lot of work here, as the user is waiting for the UI to do something ;)
var viewModelType = currentParameters["id"] == Guid.Empty.ToString("N") ? typeof(ViewModelA) : typeof(ViewModelB);
return Task.FromResult(new MvxViewModelRequest(viewModelType, new MvxBundle(), null, requestedBy));
}
}
}

Queryable Attribute allow to get some properties not all of them

I have a web api 2 application, and in my controller , I have this code :
[Queryable]
public IQueryable<Title> GetTitles()
{
return db.Titles;
}
and here is the Title entity :
public partial class Title
{
public Title()
{
this.People = new HashSet<Person>();
}
public short Id { get; set; }
public string NameT { get; set; }
public virtual ICollection<Person> People { get; set; }
}
When people query the Titles, they must get only "NameT" property. but now they get all of the properties. and yes, I know about $select, but I want another way. means even they use $select, they should not able to get "Id" property for example. if I have to bring more information, please tell me. thanks.
There are two ways to solve your problem when you use ODataController. However, they won't affect ApiController non-query part.
In that condition, you can try what Zoe suggested.
1.Ignore those properties while building your model with model builder.
builder.EntityType<Title>().Ignore(title => title.Id);
2.Add ignore member attributes on those properties.
[IgnoreDataMember]
public short Id { get; set; }
More than these, we provide support for limiting the set of allowed queries in Web API 2.2 for OData v4.0.
http://blogs.msdn.com/b/webdev/archive/2014/03/13/getting-started-with-asp-net-web-api-2-2-for-odata-v4-0.aspx
We can use attributes like Unsortable, NonFilterable, NotExpandable or NotNavigable on the properties of the types in our model, or we can configure this explicitly in the model builder.
Maybe you can have filter in your action GetTitles(), like:
[Queryable]
public IQueryable<Title> GetTitles()
{
return db.Titles.Select(t=>t.Name);
}
Use the ODataModelBuilder class as opposed to the ODataConventionModelBuilder class.
var modelBuilder = new ODataModelBuilder();
var titles = modelBuilder.EntitySet<Title>("titles");
var title = titles.EntityType;
title.HasKey(x => x.Id);
title.Ignore(x => x.Id);
title.Property(x => x.TName);
titles.HasIdLink(x => { return x.GenerateSelfLink(true); }, true);
config.Routes.MapODataRoute("odata", "odata", modelBuilder.GetEdmModel());

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