Silverlight 4 Overriding the DataForm Autogenerate to insert Combo Boxes bound to Converters - silverlight-4.0

I've been working towards a solution for some time and could use a little help. I know I've seen an example of this before, but tonight I cannot find anything close to what I need.
I have a service that provides me all my DropDownLists, either from Cache or from the DomainService. They are presented as IEnumerable, and are requested from the a repository with GetLookup(LookupId).
I have created a custom attribute that I have decorated my MetaDataClass that looks something like this:
[Lookup(Lookup.Products)]
public Guid ProductId
I have created a custom Data Form that is set to AutoGenerateFields and I am intercepting the autogenerate fields.
I am checking for my CustomAttribute and that works.
Given this code in my CustomDataForm (standard comments removed for brevity), what is the next step to override the field generation and place a bound combobox in its place?
public class CustomDataForm : DataForm
{
private Dictionary<string, DataField> fields = new Dictionary<string, DataField>();
public Dictionary<string, DataField> Fields
{
get { return this.fields; }
}
protected override void OnAutoGeneratingField(DataFormAutoGeneratingFieldEventArgs e)
{
PropertyInfo propertyInfo = this.CurrentItem.GetType().GetProperty(e.PropertyName);
foreach (Attribute attribute in propertyInfo.GetCustomAttributes(true))
{
LookupFieldAttribute lookupFieldAttribute = attribute as LookupFieldAttribute;
if (lookupFieldAttribute != null)
{
// Create a combo box.
// Bind it to my Lookup IEnumerable
// Set the selected item to my Field's Value
// Set the binding two way
}
}
this.fields[e.PropertyName] = e.Field;
base.OnAutoGeneratingField(e);
}
}
Any cited working examples for SL4/VS2010 would be appreciated.
Thanks
Update - Here's where I am at. I get my combo now, but it's always empty even though itemsSource is not.
if (lookupFieldAttribute != null)
{
ComboBox comboBox = new ComboBox();
Binding newBinding = e.Field.Content.GetBindingExpression(TextBox.TextProperty).ParentBinding.CreateCopy();
newBinding.Mode = BindingMode.TwoWay;
newBinding.Converter = new LookupConverter(lookupRepository);
newBinding.ConverterParameter = lookupFieldAttribute.Lookup.ToString();
comboBox.SetBinding(ComboBox.SelectedItemProperty,newBinding);
comboBox.ItemsSource = lookupRepository.GetLookup(lookupFieldAttribute.Lookup);
e.Field.Content = comboBox;
}

I found a solution.
if (lookupFieldAttribute != null)
{
ComboBox comboBox = new ComboBox();
Binding newBinding = e.Field.Content.GetBindingExpression(TextBox.TextProperty).ParentBinding.CreateCopy();
var itemsSource = lookupRepository.GetLookup(lookupFieldAttribute.Lookup);
var itemsSourceBinding = new Binding { Source = itemsSource };
comboBox.SetBinding(ItemsControl.ItemsSourceProperty, itemsSourceBinding);
newBinding.Mode = BindingMode.TwoWay;
newBinding.Converter = new LookupConverter(lookupRepository);
newBinding.ConverterParameter = lookupFieldAttribute.Lookup.ToString();
comboBox.SetBinding(ComboBox.SelectedItemProperty,newBinding);
e.Field.Content = comboBox;
}

Related

Make object sent useable in xamarin.forms cs file

I have a list of news, when a news is clicked it sends the user to a new page with the specific newsitem.
On the news item page I want to manipulate the object sent so I can change values within this object.
My ItemTappedEvent looks like this
public void goToEvent(object sender, ItemTappedEventArgs e)
{
if (e.Item == null)
{
return;
}
var selectedItem = e.Item; // model
Navigation.PushAsync(new eventItem(selectedItem)); // pass the selected whole item from list to DetaiPage 'selectedItem' using constructor
((ListView)sender).SelectedItem = null;
}
My NewsItem page handles this as a c# object like this
public eventItem(object selectedItem)
{
this.BindingContext = selectedItem;
InitializeComponent();
}
Within my "selectedItem" is a value named "product_wheelchair"
If this has the value "true"
Do I wan't to change it to "Ja". How can i convert my object "selectedItem" so this is possible.
Thanks in advance!
You need to cast the object to your class like:
var mySelectedItem = selectedItem as myClass
After that you can access the properties/fields available in myClass. Obviously if those are private you need to make them public to be accessible.

TableViewer with EMF databinding and cell editing - close but not quite

I am going through Tom Shindl's instructions on how to add EMF databinding on to tables, here is my code for the data binding:
protected DataBindingContext initDataBindings() {
//going to use this person instead
Person p = ProjectFactory.eINSTANCE.createPerson();
p.setFirstName("tony");
Committership c = ProjectFactory.eINSTANCE.createCommittership();
c.setName("HELP");
Committership anotherC = ProjectFactory.eINSTANCE.createCommittership();
anotherC.setName("PELASE");
Committership yetAnotherC = ProjectFactory.eINSTANCE.createCommittership();
yetAnotherC.setName("EMERGENCY");
p.getCommittership().add(c);
p.getCommittership().add(anotherC);
p.getCommittership().add(yetAnotherC);
CommandStack cs = new BasicCommandStack();
AdapterFactory af = new ProjectItemProviderAdapterFactory();
EditingDomain editingDomain = new AdapterFactoryEditingDomain(af, cs);
//data binding context
DataBindingContext bindingContext = new DataBindingContext();
//
ObservableListContentProvider listContentProvider = new ObservableListContentProvider();
IObservableMap[] attributeMap = new IObservableMap[1];
attributeMap[0] = EMFEditProperties.value(
editingDomain,
FeaturePath.fromList(ProjectPackage.Literals.COMMITTERSHIP__NAME)
).observeDetail(listContentProvider.getKnownElements());
TableViewerColumn column = new TableViewerColumn(tableViewer, SWT.NONE);
column.getColumn().setText("First Name");
column.getColumn().setWidth(200);
column.setLabelProvider(new GenericMapCellLabelProvider("{0}", attributeMap));
//tableViewer.setLabelProvider(new ObservableMapLabelProvider(attributeMap)); -- no need for this anymore
tableViewer.setContentProvider(listContentProvider);
//instead of giving it this list and doing it the non-EMF way
IObservableList selfList = Properties.selfList(Person.class).observe(p.getCommittership());
//property that you are looking for
IListProperty prop = EMFEditProperties.list(editingDomain, ProjectPackage.Literals.PERSON__COMMITTERSHIP);
IObservableValue master = EMFEditProperties.value(editingDomain, ProjectPackage.Literals.COMMITTERSHIP__NAME)
.observe(p);
/**this should not be returning null, instead it should be a
* list of the values from the person committership EList
*/
IObservableList someList = prop.observeDetail(master);
//set input requires and IObservableList!!
tableViewer.setInput(someList);
//
return bindingContext;
}
ok, now just to talk through what is happening and where I am stuck.
this line here would work for JFace data binding:
IObservableList selfList = Properties.selfList(Person.class).observe(p.getCommittership());
it populates the table happily, it is a list containing the three people I added, nice.
now making it work with EMF databinding, I am trying this:
//property that you are looking for
IListProperty prop = EMFEditProperties.list(editingDomain, ProjectPackage.Literals.PERSON__COMMITTERSHIP);
IObservableValue master = EMFEditProperties.value(editingDomain, ProjectPackage.Literals.COMMITTERSHIP__NAME)
.observe(p);
/**this should not be returning null, instead it should be a
* list of the values from the person committership EList
*/
IObservableList someList = prop.observeDetail(master);
the problem is that someList is empty and hence he table won't populate, could someone explain why?
It is definitely those three line that have some logic problem in there.
What I really want is an IObservableList of observed EMF objects...
help would be really appreciated, since Shindl's tutorial doesn't explain where he go the master from...I thought I would create a master:
IObservableValue master = EMFEditProperties.value(editingDomain, ProjectPackage.Literals.COMMITTERSHIP__NAME)
.observe(p);
and do prop.observeDetail(master)
but it is returning an empty list as I mentioned above...if only I could at least get it do display the data, the closest I have come is having three cells but not data in them.
IObservableList listObservable = prop.observe(p);
tableViewer.setInput(listObservable);
That fixed it for me in terms of viewing the data.
As for editing the cells, I did this in the end:
public class CommittershipNameEditingSupport extends EditingSupport {
private static TableViewer tableViewer;
private final CellEditor editor;
public CommittershipNameEditingSupport(TableViewer tableViewer) {
super(tableViewer);
this.tableViewer = tableViewer;
this.editor = new TextCellEditor(tableViewer.getTable());
}
#Override
protected CellEditor getCellEditor(Object element) {
return editor;
}
#Override
protected boolean canEdit(Object element) {
return true;
}
#Override
protected Object getValue(Object element) {
return ((Committership) element).getName();
}
#Override
protected void setValue(Object element, Object value) {
((Committership) element).setName(String.valueOf(value));
tableViewer.update(element, null);
}
}
and in the main view where I craeted the column I just added the method for cell editing support...it works nicely now :)

Copying sitecore rendering to new template programmatically using renderingDefinition.ItemId?

I have a custom sitecore button which changes the template of the current item, simple enough.
However as part of this I'm trying to also migrate the renderings of the old layout to a new layout if it's of a certain sublayout type by ItemId. However the ItemId that is returned is always null, the only value I get back from the RenderingDefinition is the UniqueId.
What am I doing wrong?
I have used this blog post as a guide.
The Code
public class ConvertToNewTemplateCommand : Command
{
protected void Run(ClientPipelineArgs args)
{
if (!SheerResponse.CheckModified())
return;
Item item = Context.ContentDatabase.Items[args.Parameters["id"]];
if (args.IsPostBack)
{
if (args.Result == "yes")
{
//Get current layout details
var originalLayoutXml = item[FieldIDs.LayoutField];
//Get new template
TemplateItem hubTemplate = Context.ContentDatabase.GetTemplate("some guid...");
//Change template
item.ChangeTemplate(hubTemplate);
//Reset laytout
ResetLayout(item);
//Get reset layout
var newLayoutXml = item[FieldIDs.LayoutField];
//Add all the module containers to the new layout in the central column
MoveModuleContainers(item, originalLayoutXml, newLayoutXml);
}
}
}
private void MoveModuleContainers(Item item, string oldXml, string newXml)
{
var oldLayout = LayoutDefinition.Parse(oldXml);
var newLayout = LayoutDefinition.Parse(newXml);
bool updated = false;
var oldRenderings = (oldLayout.Devices[0] as DeviceDefinition).Renderings;
var newRenderings = (newLayout.Devices[0] as DeviceDefinition).Renderings;
foreach (RenderingDefinition rendering in oldRenderings)
{
// Here is where the rendering.ItemID is always null
if (rendering != null && !String.IsNullOrEmpty(rendering.ItemID) && new Guid(rendering.ItemID) == new Guid("matching guid..."))
{
rendering.Placeholder = "middlecolumn";
newRenderings.Add(rendering);
updated = true;
}
}
if (updated)
{
// Save item...
}
}
}
I got onto Sitecore support in the end which informed me that I should use:
Sitecore.Data.Fields.LayoutField.GetFieldValue(item.Fields[Sitecore.FieldIDs.LayoutField])
instead of:
item[FieldIDs.LayoutField]
to get the items layoutField correctly. This results in the rendering values being parsed correctly and as they say the rest is history.

Telerik Mail Merge - Friendly Names (using RadRichTextBox)

I think i'm missing something obvious...
I'm using the Telerik Rad controls for WPF but i assume that the Rich text box uses some similar implementation for the mail merge functionality.
I want to have some friendly names on my mail merge fields. (namely spaces in the field names)
So i have a class for instance
Public Class someclass
{
<DisplayName("This is the complex description of the field")>
Public property thisfieldnamehasacomplexdescription as string
Public property anothercomplexfield as string
}
This is the only way i know to get "Friendly" names in the dropdown that is the mail merge.
So the two fields turn up okay as :
"This is the complex description of the field"
"anothercomplexfield"
but only anothercomplexfield actually populates with data when you do the merge.
Am i going to have to template the raddropdownbutton that holds the mail merge fields?
Is there an example of this somewhere?
Also a sub question. How do i add a scroll bar on these things?
(also i know this board is not a TELERIK specific board (duh!) but this might be useful to someone in the future. So i'll copy the answer i get from Telerik into here!
http://www.telerik.com/community/forums/wpf/richtextbox/558428-radrichtextbox-mailmerge---using-displayname-to-create-a-friendly-name-with-spaces.aspx )
This is what telerik gave me:
With the default MergeFields, it is not possible to change the display name fragment of the field in order to achieve a more friendly look. This should be possible if you implement a custom MergeField by deriving from the MergeField class. Here is a sample implementation that shows how this can be done:
public class CustomMergeField : MergeField
{
private const string CustomFieldName = "CustomField";
static CustomMergeField()
{
CodeBasedFieldFactory.RegisterFieldType(CustomMergeField.CustomFieldName, () => { return new CustomMergeField(); });
}
public override string FieldTypeName
{
get
{
return CustomMergeField.CustomFieldName;
}
}
public override Field CreateInstance()
{
return new CustomMergeField();
}
protected override DocumentFragment GetDisplayNameFragment()
{
return base.CreateFragmentFromText(string.Format(Field.DisplayNameFragmentFormat, this.GetFriendlyFieldName(this.PropertyPath)));
}
private string GetFriendlyFieldName(string fieldName)
{
int lettersInEnglishAlphabet = 26;
List<char> separators = new List<char>(lettersInEnglishAlphabet);
for (int i = 0; i < lettersInEnglishAlphabet; i++)
{
separators.Add((char)('A' + i));
}
StringBuilder newFieldName = new StringBuilder();
int previousIndex = 0;
for (int i = 1; i < fieldName.Length; i++)
{
if (separators.Contains(fieldName[i]))
{
if (previousIndex > 0)
{
newFieldName.Append(" ");
}
newFieldName.Append(fieldName.Substring(previousIndex, i - previousIndex));
previousIndex = i;
}
}
newFieldName.Append(" " + fieldName.Substring(previousIndex));
return newFieldName.ToString();
}
}
Note that the fragment that is shown when the DisplayMode is Code cannot be changed.
As for your other question, you can change the content of the dropdown button to show the friendly name of the fields and to include a scrollbar in the following way:
1. First, remove the binding of the button to the InsertMergeFieldEmptyCommand from XAML and give it a name (e.g. insertMergeField).
2. Next, add the following code in code-behind:
AddMergeFieldsInDropDownContent(this.insertMergeFieldButton);
private void AddMergeFieldsInDropDownContent(RadRibbonDropDownButton radRibbonDropDownButton)
{
Grid grid = new Grid();
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(100, GridUnitType.Pixel) });
ScrollViewer scrollViewer = new ScrollViewer();
scrollViewer.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
StackPanel stackPanel = new StackPanel();
foreach (string fieldName in this.editor.Document.MailMergeDataSource.GetColumnNames())
{
RadRibbonButton fieldButton = new RadRibbonButton()
{
Text = this.GetFriendlyFieldName(fieldName),
Size = ButtonSize.Medium,
HorizontalAlignment = HorizontalAlignment.Stretch,
HorizontalContentAlignment = HorizontalAlignment.Left
};
fieldButton.Command = this.editor.Commands.InsertFieldCommand;
fieldButton.CommandParameter = new MergeField() { PropertyPath = fieldName };
//or
//fieldButton.CommandParameter = new CustomMergeField() { PropertyPath = fieldName };
stackPanel.Children.Add(fieldButton);
}
stackPanel.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
scrollViewer.Content = stackPanel;
grid.Children.Add(scrollViewer);
radRibbonDropDownButton.DropDownContent = grid;
}
You can, of course optimize the code of the GetFriendlyName method and add it in a way that will be available by both classes.

How to get the selected value of a dynamically created selectlist component

I am not sure whether this is even possible, but I am trying to get the values of dynamically created selectlists in a VisualForce Apex controller class.
I am dynamically creating a selectlist for each field in a particular object (e.g. Contact) using the code below, but now I do not know how to get the selected value back. I have tried setting the value of each in the constructor and on a separate line (not in code sample below), but this does not seem to work.
VisualForce page:
<apex:dynamicComponent componentValue="{!contactPageBlockSection}" />
Apex controller:
public Component.Apex.PageBlockSection GetContactPageBlockSection(string objectName)
{
Map<string, Schema.SObjectField> FieldMap;
FieldMap = Schema.SObjectType.Contact.fields.getMap();
Set<string> FieldSet = FieldMap.keySet();
List<string> FieldList = new List<string>();
FieldList.addAll(FieldSet);
FieldList.sort();
Component.Apex.PageBlockSection pbs = new Component.Apex.PageBlockSection(columns = 2);
for (string fieldName : FieldList)
{
Component.Apex.PageBlockSectionItem pbsi = new Component.Apex.PageBlockSectionItem();
Schema.DescribeFieldResult field = (FieldMap.get(fieldName)).getDescribe();
if (field.isUpdateable() && field.IsAccessible())
{
Schema.DisplayType dt = field.getType();
Component.Apex.OutputLabel lblText = new Component.Apex.OutputLabel(escape = false);
lblText.value = field.getLabel();
pbsi.childComponents.add(lblText);
Component.Apex.SelectList selList = new Component.Apex.SelectList(id = field.getName(), multiselect = false, size = 1, style = 'width:200px;');
if (dt == Schema.DisplayType.Integer || dt == Schema.DisplayType.Double || dt == Schema.DisplayType.Currency || dt == Schema.DisplayType.Percent)
{
AddSelectOption(selList, 'Keep highest value');
AddSelectOption(selList, 'Keep lowest value');
AddSelectOption(selList, 'Keep master value');
pbsi.childComponents.add(selList);
pbs.childComponents.add(pbsi);
}
}
}
return pbs;
}
private void AddSelectOption(Component.Apex.SelectList selList, string option)
{
Component.Apex.SelectOption selOption = new Component.Apex.SelectOption();
selOption.itemLabel = option;
selOption.itemValue = option;
selList.childComponents.add(selOption);
}
Many thanks in advance
just bind the value attribute of the dynamically created select list to a string property using expression syntax like:
String selectedValue {get; set;}
...
setList.expressions.value = '{!selectedValue}';
the property should then store the selected value just as it would in a static declarative definition of the select list.
You could try and use dynamic visualforce binding. I.E.
map<String,String> FieldToString {get; set;}
...
selList.expressions.value = '{!FieldToString[\'' + fieldname + '\']}';
However, I have never used dynamic visualforce bindings within dynamic visualforce so caveat emptor.