how to map sitecore items using glassmapper class in web froms..? - sitecore

i'm creating demo project there i create Item which contains sub-Item now i want to render these using web controller my code like this
site items created as following image
and my glass mapper code is as:
public static class GlassMapperSc
{
public static void Start()
{
//create the resolver
var resolver = DependencyResolver.CreateStandardResolver();
//install the custom services
GlassMapperScCustom.CastleConfig(resolver.Container);
//create a context
var context = Glass.Mapper.Context.Create(resolver);
context.Load(
GlassMapperScCustom.GlassLoaders()
);
GlassMapperScCustom.PostLoad();
}
public class DesktopHome
{
public virtual string Title { get; set; }
public virtual string Description { get; set; }
public virtual string LeftRotatorTitle { get; set; }
public virtual string RightRotatorTitle { get; set; }
}
public class GlobalsItem
{
public class HeaderTemplateItem
{
public class NavItem
{
public virtual string Title { get; set; }
public virtual string Link { get; set; }
public virtual IEnumerable<NavItem> Children { get; set; }
}
}
}
}
i'm able to get parent items but not able to get child items please anyone help me to figure out this issue

Define your Modal Class as:
[SitecoreClass]
public class Header
{
[SitecoreInfo(SitecoreInfoType.Url)]
public virtual string About{ get; set; }
[SitecoreField]
public virtual string Home{ get; set; }
[SitecoreField]
public virtual string Services{ get; set; }
[SitecoreField]
public virtual IEnumerable<Header> Links { get; set; }
}
Configuring the application
To configure Glass Mapper is really straight forward. Open or create a Global.ascx file in your project and on the application start add the following code:
protected void Application_Start(object sender, EventArgs e)
{
AttributeConfigurationLoader loader = new AttributeConfigurationLoader(
new string[] { "Glass.Sitecore.Mapper.Demo.Application.Domain, Glass.Sitecore.Mapper .Demo" }
);
Persistence.Context context = new Context(loader, null);
}
your view code will be as:
<div>
<h1>
<asp:Literal runat="server" ID="About" />
</h1>
<div class="body">
<asp:Literal runat="server" ID="Home" />
</div>
<div class="links">
<asp:Repeater runat="server" ID="links">
<HeaderTemplate>
<ul>
</HeaderTemplate>
<ItemTemplate>
<li><a href='<%# DataBinder.Eval(Container.DataItem,"Url") %>'>
<%# DataBinder.Eval(Container.DataItem,"Services") %></a> </li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</div>
Next lets look at the code behind page, for simplicity everything is going in the Page_Load method:
protected void Page_Load(object sender, EventArgs e)
{
ISitecoreContext context = new SitecoreContext();
DemoClass item = context.GetCurrentItem<DemoClass>();
title.Text = item.Title;
body.Text = item.Body;
links.DataSource = item.Links;
links.DataBind();
}

Related

UWP - NavigationView with two different Sources

I have an ObservableCollection<Category> binded to a NavigationView, where Category is a custom class that implements INotifyPropertyChanged. I created a DataTemplate to display the element of the collection
<DataTemplate x:Key="CategoryTemplate">
<NavigationViewItem Icon="{Binding Icon}" RightTapped="CategoryItem_RightTapped">
<local:CategoryViewItem CategoryItem="{Binding Mode=TwoWay}"/>
</NavigationViewItem>
</DataTemplate>
Now I want to add some default NavigationViewItem and a NavigationViewItemSeparator at the top of the list with a different DataTemplate keeping the second part "Observable" and "Notifying changes of properties". You can see an example of what I mean in the image below.
For your requirement, you need make MenuItemTemplateSelector for NavigationView. And pass the different DataTemplate base on the data source.
Default NavigationViewItem and NavigationViewItemSeparator Data Model
public class CategoryBase { }
public class DefaultCategory: CategoryBase
{
public string Name { get; set; }
public string Tooltip { get; set; }
public Symbol Glyph { get; set; }
}
public class CustomCategory : CategoryBase
{
public SymbolIcon Icon { get; set; }
public string Title { get; set; }
}
public class Separator : CategoryBase { }
MenuItemTemplateSelector
public class MenuItemTemplateSelector : DataTemplateSelector
{
internal DataTemplate SeparatorTemplate = (DataTemplate)XamlReader.Load(
#"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>
<NavigationViewItemSeparator />
</DataTemplate>");
public DataTemplate DefaultItemTemlate { get; set; }
public DataTemplate CustomItemTemlate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
return item is Separator ? SeparatorTemplate : item is CustomCategory ? CustomItemTemlate : DefaultItemTemlate;
}
}
Xaml Code
<Page.Resources>
<local:MenuItemTemplateSelector x:Key="selector">
<local:MenuItemTemplateSelector.DefaultItemTemlate>
<DataTemplate x:DataType="local:DefaultCategory">
<NavigationViewItem Content="{x:Bind Name}">
<NavigationViewItem.Icon>
<SymbolIcon Symbol="{x:Bind Glyph}" />
</NavigationViewItem.Icon>
</NavigationViewItem>
</DataTemplate>
</local:MenuItemTemplateSelector.DefaultItemTemlate>
<local:MenuItemTemplateSelector.CustomItemTemlate>
<DataTemplate>
<NavigationViewItem Icon="{Binding Icon}">
<TextBlock Text="{Binding Title}" />
</NavigationViewItem>
</DataTemplate>
</local:MenuItemTemplateSelector.CustomItemTemlate>
</local:MenuItemTemplateSelector>
</Page.Resources>
<Grid>
<NavigationView
x:Name="nvSample"
MenuItemTemplateSelector="{StaticResource selector}"
MenuItemsSource="{x:Bind Categories, Mode=OneWay}"
/>
<Button Click="Button_Click" Content="AddItem" />
</Grid>
Usage
public MainPage()
{
this.InitializeComponent();
Categories = new ObservableCollection<CategoryBase>();
Categories.Add(new CustomCategory { Title = "This is Titlte", Icon = new SymbolIcon(Symbol.Play) });
}
public ObservableCollection<CategoryBase> Categories { get; }
private void Button_Click(object sender, RoutedEventArgs e)
{
Categories.Insert(0, new Separator());
Categories.Insert(0, new DefaultCategory { Name = "Category 1", Glyph = Symbol.Home, Tooltip = "This is category 1" });
}
You could find the code sample here, and this NavigationView document that you could refer.

Pass multiple list from controller to view

I MVC c# application which has model
public class lstSearchCriteria
{
public List<lstCampaign> cmpList { get; set; }
public List<lstAgent> agentList { get; set; }
}
public class lstCampaign
{
public string campaignName { get; set; }
}
public class lstAgent
{
public string agentShortName { get; set; }
public string agentFullName { get; set; }
}
& controller which returns lstSearchCriteria. I need to display lstCampaign & lstAgent in dropdown list.
In view I am doing
#using QAApplication.Models
#model QAApplication.Models.lstSearchCriteria
<select id="lstCampaigns" multiple="multiple">
#foreach (var item in Model.cmpList)
{
<option >#item.campaignName</option>
}
</select>
<div id="divlstAgents">
<select id="lstAgents" multiple="multiple">
#foreach (var item in Model.agentList)
{
<option >#item.agentShortName</option>
}
</select>
</div>
I am getting below error :The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[QAApplication.Models.lstSearchCriteria]', but this dictionary requires a model item of type 'QAApplication.Models.lstSearchCriteria'.
what could be the best way to pass multiple list to view from controller. Thanks in advance
You are passing List<lstSearchCriteria>, While Views expected model lstSearchCriteria only.

MVC custom serialization of List<X> parameter for GET request?

I'm wanting to change a request to be GET instead of POST so users can share the generated URLs.
The current system uses a normal form submit and takes advantage of the automatic serialization between the form submit and the MVC ActionResult for a List of custom objects.
e.g.
<form action="/MyPage">
<input type="hidden" id="MyThings_0__Value" name="MyThings[0].Value">
<input type="hidden" id="MyThings_0__Flag" name="MyThings[0].Flag">
<input type="hidden" id="MyThings_1__Value" name="MyThings[1].Value">
<input type="hidden" id="MyThings_1__Flag" name="MyThings[1].Flag">
</form>
However doing it this way causes the GET string generated to be overly long and complicated. This is bad because the MyThings list can be up to 10 items long.
http://myurl.com/MyPage?MyThings%5B0%5D.Value=ThisIsValue1&MyThings%5B0%5D.Flag=1&MyThings%5B1%5D.Value=ThisIsValue2&MyThings%5B1%5D.Flag=2
I was hoping for the string to appear more user-friendly. Something like:
http://myurl.com/MyPage?MyThings=ThisIsValue1-1,ThisIsValue2-2
Can this be done with custom serialization? And if so, how would I go about implementing it?
My Model and ActionResult:
namespace MyNamespace {
public class MyThing {
public string Value { get; set; }
public int Flag { get; set; }
}
public class Filter {
public string CustomAttribute1 { get; set; }
public string CustomAttribute2 { get; set; }
public string CustomAttribute3 { get; set; }
public List<MyThing> MyThings { get; set; } = new List<MyThing>();
}
public ActionResult MyPage(Filter filter) {
MyModel model = StaticMethod.GetMyModel(filter);
return View(model);
}
}
In the end I decided against using custom URL serialization and used helper methods to convert to string/class backward and forwards within the C# model.
public class Filter {
public string MyThing { get; set; }
public List<MyThingClass> MyThings {
get {
if (this._myThings == null) { // Default to Query string
this._myThings = ToQueryList(this.MyThing);
}
return this._myThings;
}
set {
this.MyThing = ToQueryString(value); // Automatically assign QueryString to serialized QueryItems on set
this._myThings = value;
}
}
private List<MyThingClass> _myThings { get; set; }
public static List<MyThingClass> ToQueryList(string queryString) {
return queryString.Split(',').Select(x => MyThingClass.FromString(x)).ToList();
}
public static string ToQueryString(List<MyThingClass> myThings) {
return string.Join(",", myThings.Select(x => x.ToString()));
}
}
public class MyThingClass {
public string Value { get; set; }
public int Flag { get; set; }
/// <summary>Converts a QueryItem object to a serialized object ready for the QueryString.</summary>
public override string ToString() {
return string.Concat(this.Value, "-", this.Flag);
}
public static MyThingClass FromString(string value) {
var v = value.Split('-');
return new MyThingClass() {
Value = v[0],
Flag = Convert.ToInt32(v[1])
};
}
}

Show Name Property on a foreignkey relationship

I have a selectList of foreignkey (like a parent). Currently, the ID are binded for the value and item name. I want to change that for my Name property:
Here's my models:
public class Genus
{
public int GenusID { get; set; }
public EnumCategory Category { get; set; }
public string Name { get; set; }
public List<Species> Species { get; set; }
}
public class Species
{
public int SpeciesID { get; set; }
public int GenusID { get; set; }
public virtual Genus Genus { get; set; }
public string Name { get; set; }
}
On my Create and Edit Species page I have this code:
<select asp-for="Species.GenusID" class ="form-control" asp-items="ViewBag.GenusID"></select>
This code are generated by default when We Add Razor Page Scaffold. Well, the result are on the line 1, and what I want of result on the line 2:
<option selected="selected" value="1">1</option>
<option selected="selected" value="1">NameProperty</option> <!-- Species.Genus.Name -->
Do you have an idea to make that right ?
Thanks per advance
Looking at the code for the NavigationMetadata class in the scaffolding repo (https://github.com/aspnet/Scaffolding) I have found the following commented code which describe the behaviour.
// The default for the display property is the primary key of the navigation.
DisplayPropertyName = PrimaryKeyNames[0];
// If there is a non nullable string property in the navigation's target type, we use that instead.
var displayPropertyCandidate = navigation
.GetTargetType()
.GetProperties()
.FirstOrDefault(p => !p.IsNullable && p.ClrType == typeof(string));
if (displayPropertyCandidate != null)
{
DisplayPropertyName = displayPropertyCandidate.Name;
}
So if you want the Name property to show by default instead of the ID, then ensure it is the first string property in the model (yours already is), and then make sure it's not nullable.
protected override void OnModelCreating(ModelBuilder builder)
{
// ...
builder.Entity<Genus>().Property(l => l.Name).IsRequired();
// ...
}

Sitecore Load all items into an MVC model?

I have created a bunch of custom templates to store items (such as Industries, Subindustries, etc.) in Sitecore. I now want to go about loading these into my Sitecore MVC model.
The lists are located in sitecore > Content > Lists. For example inside the Lists folder there is a folder called Country. I want to get back all the items within the Country folder and populate them as unordered list in my view.
UPDATE: I implemented the Glass.Mapper.Sc method suggested below. It is fully operational now.
This is what my working model looks like now:
using Glass.Mapper.Sc.Configuration;
using Glass.Mapper.Sc.Configuration.Attributes;
using Sitecore.Data.Items;
using Sitecore.Mvc.Presentation;
using System;
using System.Collections.Generic;
namespace Sitecore.Web.Models
{
public class Registration: IRenderingModel
{
public Rendering Rendering { get; set; }
public Item Item { get; set; }
public Item PageItem { get; set; }
public IEnumerable<CountryChildItem> CountryList { get; set; }
[SitecoreType(AutoMap = true)]
public class CountryItem
{
public virtual IEnumerable<CountryChildItem> Children { get; set; }
}
[SitecoreType(AutoMap = true)]
public class CountryChildItem
{
[SitecoreId]
public virtual Guid Id { get; set; }
[SitecoreInfo(SitecoreInfoType.Path)]
public virtual string Path { get; set; }
[SitecoreField]
public virtual string DisplayName { get; set; }
[SitecoreField]
public virtual string Abbreviation { get; set; }
}
public void Initialize(Rendering rendering)
{
Rendering = rendering;
Item = rendering.Item;
PageItem = PageContext.Current.Item;
}
}
}
and this is what my working contoller looks like:
using Glass.Mapper.Sc;
using Sitecore.Web.Models;
using System.Web.Mvc;
namespace Sitecore.Web.Controllers
{
public class RegistrationController : Controller
{
Registration registrationModel = new Registration();
public ActionResult Index()
{
ISitecoreContext sitecoreContext = new SitecoreContext();
ISitecoreService service = new SitecoreService(sitecoreContext.Database);
Registration.CountryItem countryItem = service.GetItem<Registration.CountryItem>("/sitecore/content/Lists/Country");
registrationModel.CountryList = countryItem.Children;
return View(registrationModel);
}
}
}
and a snippet of my working view:
<ul class="select-menu-options dropdown-menu">
#foreach (var country in Model.CountryList)
{
<li>#country.DisplayName</li>
}
</ul>
If I were in your position I'd look into Glassmapper for Sitecore.
It's a fairly lightweight ORM for Sitecore.
http://www.glass.lu/Mapper/Sc
I'd also suggest moving the lists located in
sitecore > Templates > User Defined > Lists > Content
to some where under either
sitecore > Content
or
sitecore > System
(whichever makes more sence)
UPDATE:
Try adding this above your class:
[SitecoreType(AutoMap = true)]
public class CountryItem
{
//...
}
If you change your CountryItem and other model classes to inherit from SearchResultItem like that:
[PredefinedQuery("TemplateID", ComparisonType.Equal, "{ID-OF-CountryItem-TEMPLATE}", typeof(ID))]
public class CountryItem : Sitecore.ContentSearch.SearchTypes.SearchResultItem
{
[IndexField("_displayname")]
public virtual string DisplayName { get; set; }
[IndexField("abbreviation")]
public string Abbreviation { get; set; }
}
You should be able to use Sitecore indexes to retrieve all the countries and other lists like that:
private static string IndexName
{
get
{
return string.Format("sitecore_{0}_index", (Context.ContentDatabase ?? Context.Database).Name);
}
}
private static string Language { get { return Context.Language.Name; } }
public IEnumerable<CountryItem> GetCountries()
{
using (var context = ContentSearchManager.GetIndex(IndexName).CreateSearchContext())
{
IQueryable<CountryItem> queryable = context.GetQueryable<CountryItem>();
queryable = queryable.Where(i => i.Language == Language);
queryable = queryable.Where(i => i.LatestVersion);
// ... maybe excluding standard values or some other filters
var searchResults = queryable.GetResults();
return queryable.ToList();
}
}
Please be aware that this is just an example. You need to test it and most probably adapt to your solution.
And as Dar Brett mentioned, you should not keep any data items under the Templates node.