I'm using the Create Item save action in a web form. I have a checkbox list that points to a folder containing category items. This is mapped to a Multilist field on the item template that it will create when the user submits the form. But it's passing the checkbox text, not the value, so the multilist for each new item created has bad data in it. Does anyone know how to set the checkbox list to pass the values instead? I'm kind of surprised it's doing this in the first place.
I haven't had a chance to test this, but theoretically, you could create a new field type that inherits from CheckboxList, and let's say we call it CheckboxListPipedValues. The code would look something like this:
using System.ComponentModel;
using System.Linq;
using System.Text;
using Sitecore.Form.Core.Controls.Data;
using Sitecore.Form.Web.UI.Controls;
public class CheckboxListPipedValues : Sitecore.Form.Web.UI.Controls.CheckboxList
{
[Browsable(false)]
public override ControlResult Result
{
get
{
StringBuilder stringBuilder1 = new StringBuilder();
var checkedItems = this.InnerListControl.Items.Where(a => a.Selected).ToList();
var values = string.Join("|", checkedItems.Select(c => c.Value));
foreach (var item in checkedItems)
{
stringBuilder1.AppendFormat("{0}, ", item.Text);
}
return new ControlResult(this.ControlName, values, stringBuilder1.ToString(0, (stringBuilder1.Length > 0 ? stringBuilder1.Length - 2 : 0)));
}
}
}
In Sitecore, simply go to /sitecore/system/Modules/Web Forms for Marketers/Settings/Field Types/List Types/Checkbox List and duplicate that item. Then change the assembly and class to the new control. Change your form to use the new field, and ensure that the values are mapped properly. Now the output of the value should be a pipe separated list of the values which should work nicely with the multilist field.
EDIT:
For MVC, it's the same process, but you'll need to update the MVC Type in the field type item to point to your new class. The code for MVC should look something like this:
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Form.Core.Controls.Data;
using Sitecore.Forms.Core.Data;
using Sitecore.Forms.Mvc.Data.TypeConverters;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Web.Mvc;
public class CheckBoxListPipedField : CheckBoxListField
{
public CheckBoxListPipedField(Item item) : base(item)
{
}
public override ControlResult GetResult()
{
var values = new List<string>();
StringBuilder stringBuilder1 = new StringBuilder();
if (this.Items != null)
{
foreach (SelectListItem selectListItem in
from item in this.Items
where item.Selected
select item)
{
values.Add(selectListItem.Value);
stringBuilder1.AppendFormat("{0}, ", selectListItem.Text);
}
}
var results = string.Join("|", values);
return new ControlResult(base.ID.ToString(), base.Title, results, stringBuilder1.ToString(0, (stringBuilder1.Length > 0 ? stringBuilder1.Length - 2 : 0)));
}
}
Related
I'm trying to display several lines into a Text area from a string list. But it's only displaying the last one of the list, and i would like to display them all. Thanks for your help !
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class contenuTexte : MonoBehaviour {
public List <string> montexte;
public GameObject zoneAffichage;
// Update is called once per frame
void Start ()
{
foreach ( string lines in montexte)
zoneAffichage.GetComponent<Text>().text = "\n"+lines;
}
}
Your problem is that you are resetting the string on every loop to the last string. At the end of the loop you are going to only have the last string in the text.
First let's join all the strings together as one (using .ToArray() because of .NET 3.5), and then set them all at once:
var completeText = String.Join("\n", montexte.ToArray());
zoneAffichage.GetComponent<Text>().text = completeText;
I have two sublayouts: Grid-1-2 and Grid-2-1.
The two sublayouts are sharing a single ASCX file (not a good sitecore practice but i need it this way).
The problem is that in the ASCX codebehind, i want to see if the current selected grid is Grid-1-2 or Grid-2-1 ?!
I have tried using both Datasource and RenderingId techniques but to no effect.
EDIT
I was wondering if i can get the "Parameters" field from "Data" section of the sublayout. This would do the trick.
All suggestions are welcomed.
Please Help !!
Can you try with :
Sitecore.Context.Database.GetItem(((Sublayout)Parent).DataSource);
Also other option is:
LayoutDefinition layoutDef = LayoutDefinition.Parse(Sitecore.Context.Item.Fields["__renderings"].Value);
string deviceId = Sitecore.Context.Device.ID.ToString();
DeviceDefinition curDeviceDef = layoutDef.GetDevice(deviceId);
RenderingDefinition renderingDef = curDeviceDef.GetRendering(Sitecore.Context.Database.Items["/sitecore/Layout/SubLayouts/MySublayout"].ID.ToString());
int controlIndex = curDeviceDef.GetIndex(renderingDef.UniqueId);
Control MyDotNetControl = Sitecore.Context.Page.Renderings[controlIndex].GetControl();
We have the following methods on a base class that all our sublayout controls inherit from... you could just pass in a parameter on each sublayout to identify it and retrieve it using the GetParameter method.. e.g. name="Grid-1-2" etc
public string GetParameter(string key, string defaultValue = null)
{
Sublayout s = this.SitecoreSublayout;
if (s != null)
{
if (!String.IsNullOrWhiteSpace(s.Parameters))
{
NameValueCollection pars = HttpUtility.ParseQueryString(s.Parameters);
if (pars != null)
{
return pars[key];
}
}
}
return defaultValue;
}
protected Sublayout SitecoreSublayout
{
get
{
Sublayout parent = this.Parent as Sublayout;
return parent;
}
}
I am trying to implement Sitecore Dictionary items to be edited via PageEditor.
This is my approach.. Just need your thoughts and suggestions.
To make it simple and not to mess up with the pipelines, here is a simple way of what I am doing.
Normally you do a sitecore translate for example,
#Sitecore.Globalization.Translate.Text("SomeKey")
You can encapsulate the Translate to a custom class which might look like
public static class CustomTranslate
{
public static string Text(string key)
{
if (Sitecore.Context.PageMode.IsPageEditorEditing)
{
string val = String.Empty;
Item currentItem = Context.Database.GetItem(ResourcesController.ItemLookUp()[key]);
if (currentItem != null)
{
val = FieldRenderer.Render(currentItem, "Phrase");
}
return val;
}
else
return Sitecore.Globalization.Translate.Text(key);
}
}
The CustomTranslate.Text returns a FieldRenderer in PageEdit mode else returns the Sitecore.Globalization.Translate.Text
Then in your code you can refer the translations as
#CustomTranslate.Text("SomeKey")
The Lookup can be a dictionary of Key and Item ID as shown in below code,
public static class ResourceController
{
public static Dictionary ItemLookUp()
{
///get dictionary path..etc.. code not included
//read all sitecore dictionary Items
Sitecore.Data.Items.Item[] items =
Sitecore.Context.Database.SelectItems("fast:" + dictionaryPath +
"//*[##templateid='{6D1CD897-1936-4A3A-A511-289A94C2A7B1}']");
//build a Dictionary<string,string> using sitecore item key and Guid.
items.All(y => { resourceDictionary.Add(y["Key"], y.ID.Guid.ToString()); return true;}
// Key,Guid dictionary
return resourceDictionary;
}
}
A Simpler and much easier approach ! Thoughts, Comments ?
A 2-sash sashform. A 3-level TreeViewer in one and a TableViewer in the other. When it starts no item is selected in the TreeViewer
and the TableViewer shows a list of all the first level objects available. To achieve this, the TreeViewerContainer instantiates the TableViewerContainer and then calls its showFirstLevelItemList( ) method :
public class TableViewerContainer {
private Table table;
private TableViewer tableViewer;
private TableColumnLayout layout;
public TableViewerContainer(SashForm sashForm) {
Composite composite = new Composite(sashForm, SWT.NONE);
composite.setLayout(new GridLayout(1, false));
tableViewer = new TableViewer(composite, SWT.BORDER
| SWT.FULL_SELECTION);
table = tableViewer.getTable();
table.setHeaderVisible(true);
table.setLinesVisible(true);
// Add TableColumnLayout
layout = new TableColumnLayout();
composite.setLayout(layout);
}
public void showFirstLevelItemList( FirstLevelItemListContainer obj ) {
// Add the only column
TableViewerColumn tableViewerColumn = new TableViewerColumn(
tableViewer, SWT.NONE);
TableColumn tblclmnFirst = tableViewerColumn.getColumn();
layout.setColumnData(tblclmnFirst, new ColumnWeightData(10,
ColumnWeightData.MINIMUM_WIDTH, false));
tblclmnFirst.setText("Description");
// assign providers and show the table
tableViewer.setLabelProvider(new FirstLevelItemLabelProvider());
tableViewer.setContentProvider(new FirstLevelItemContentProvider());
tableViewer.setInput(obj);
}
This works fine.
Next, selecting an item in the TreeViewer causes the tableViewer to update the data accordingly. To effect this I added a SelectionChangedListener():
treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = (IStructuredSelection) event
.getSelection();
Object obj = selection.getFirstElement();
if (obj instanceof firsLevelDetail ) {
FirstLevelDetail fld = (FirstLevelDetail) obj;
tableViewer.showFirstLevelDetail(fld);
} else if (obj instanceof SecondLevelDetail )
SecondLevelDetail sld = (SecondLevelDetail) obj;
tableViewer.showSecondLevelDetail(sld);
else if (obj instanceof ThirdLevelDetail)
ThirdLevelDetail tld = (ThirdLevelDetail) obj;
tableViewer.showSecondLevelDetail(tld);
}
});`
So that when the user selects a firstLevelItem the TableViewer shows the corresponding data. All the methods called follow the following pattern :
private void showFirstLevelDetail( FirstLevelDetailObj obj ) {
Table tbl = tableViewer.getTable();
tbl.setRedraw(false);
// Dispose former columns
while (tbl.getColumnCount() > 0) {
tbl.getColumns()[0].dispose();
}
// add new columns
TableViewerColumn tableViewerColumn = new TableViewerColumn(
tableViewer, SWT.NONE);
TableColumn tblclmn = tableViewerColumn.getColumn();
layout.setColumnData(tblclmn, new ColumnWeightData(1,
ColumnWeightData.MINIMUM_WIDTH, true));
tblclmn.setText("Code FL Item");
tableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
tblclmn = tableViewerColumn.getColumn();
layout.setColumnData(tblclmn, new ColumnWeightData(1,
ColumnWeightData.MINIMUM_WIDTH, true));
tblclmn.setText("Description FL Item");
tbl.setRedraw(true);
// to avoid an Exception
tableViewer.setInput(null);
// Assign new providers and show the data
tableViewer.setLabelProvider(new FirstLevelDetailLabelProvider());
tableViewer.setContentProvider(new FirstLevelDetailContentProvider());
tableViewer.setInput(obj);
}
The ContentProviders' getElements() methods follow the next patern:
public Object[] getElements(Object inputElement) {
return ((FirstLevelDetail)inputElement).getArrayItems();
}
My problem is after this process the table doesn't show a header or any data until it is resized. Then it works normally until another item is selected, no matter what level the item is.
tableViewer.refresh() does not work.
tableViewer.getTable().redraw() does not work.
All the showXxxxLevelDetail () work properly if they are called in the first place, instead of showFirstLevelItemList() method, provided tableViewer.setInput(null) is commented out.
I'm running Eclipse Indigo, jface 3.8, Windows XP.
I would try to call
composite.layout();
after calling any of those showXXXLevelDetail() methods.
I am looking for a way to allow visitors to select what content they want displayed on the site.
Is there a way to programatically trigger a profile in Sitecore DMS?
I've looked at relevant documentation on SDN (http://sdn.sitecore.net/Reference/Sitecore 6/DMS Documentation.aspx), but so far haven't found a way.
EDIT: Raised this on Sitecore Support Portal - will post an answer once I find out more.
I have done something similar on my project. Check out this code sample and let me know if you have any questions. Also, make sure you add profiles to content items too. Call FilterItemByBehavior on a collection of items and it will filter them based on user's past browsing behavior.
private static Dictionary<string, List<string>> AnalyticsFilter()
{
Dictionary<string, List<string>> filter = new Dictionary<string, List<string>>();
if (Tracker.CurrentVisit.Profiles.Count() > 0)
{
foreach (VisitorDataSet.ProfilesRow row in Tracker.CurrentVisit.Profiles)
{
List<string> keys = new List<string>();
foreach (var key in row.Values)
{
if (key.Value >= ResourceHelper.GetInt(new ID(Resources.Settings.AnalyticsProfileSetMinValGuid)))
keys.Add(key.Key);
}
filter.Add(row.ProfileName, keys);
}
}
if(ResourceHelper.IsTurnedOn(new ID(Resources.Settings.AnalyticsUserProfileEnableSwitch)))
filter = ApplyUserProfile(filter);
return filter;
}
public static List<Item> FilterItemByBehavior(List<Item> items, int count)
{
try
{
var filter = AnalyticsFilter();
foreach (var profile in filter)
{
int counter = ResourceHelper.GetInt(new ID(Resources.Settings.AnalyticsProfileTagsFilterMaxGuid));
if (items.Count <= count) break;
foreach (string key in profile.Value)
{
if (items.Count <= count || counter == 0) break;
items = items.Where(i => (((MultilistField)i.Fields[profile.Key]).GetItems().ToList().Select(x => x.Name).Contains(key))).ToList();
counter--;
}
}
return items.Count <= count ? items : items.Take(count).ToList();
}
catch (System.Exception ex)
{
Sitecore.Diagnostics.Log.Error(ex.Message, ex, new AnalyticsHelper());
return items.Count <= count ? items : items.Take(count).ToList();
}
}
I have received a response from Sitecore support on this question. Here it is:
"If you are using pattern cards for personalzation, then you can use the following code as the event handler for "item selected" event for the dropdown list:"
var profile = Sitecore.Analytics.Tracker.CurrentVisit.GetOrCreateProfile("<Profile Name>");
profile.BeginEdit();
profile.Score("<profile key>",<profile key value you want to set>);
profile.Score("<profile key>",<profile key value you want to set>);
profile.UpdatePattern(); //sets the appropriate pattern based on the current profile keys values you have just set.
profile.EndEdit();
This interferes with automatic profile matching, so I am not sure I want to use this approach.