How to access control on current TabbedPage? - xaml

I have a tabbed page with a stacklayout that I populate with some child controls. The page originally had no navigation but now I've added the tabbed page (created programmatically in the app.cs) it means that the method below is unable to populate the selected tabbed page's stacklayout.
I need to know how to access the current tabbed page and then add the items to the stacklayout.
public static void addToReadout(string name, string time, string inout)
{
try
{
Label label1 = new Label { Text = name + " Successfully clocked " + inout + " # " + time, TextColor = Color.Black };
StackLayout sl = new StackLayout();
var mp = (MainPage)App.Current.MainPage;
if (mp.readOut.Children.Count() < 7)
{
mp.readOut.Children.Add(label1);
mp.readOut.Children.Count();
}
else
{
mp.readOut.Children.RemoveAt(0);
mp.readOut.Children.Add(label1);
mp.readOut.Children.Count();
}
}
catch (Exception ex)
{
ErrorRepository.InsertError(ex.ToString());
}
}
This issue is with this row since changing to a tabbed page setup:
var mp = (MainPage)App.Current.MainPage;

TabbedPage has a CurrentPage property that will return a reference to the current active page.
If your MainPage inherits from TabbedPage, you can do this
var mp = (MainPage)App.Current.MainPage;
var current = mp.CurrentPage;
Edit: based on the code you pasted in the comments
var mp = (TabbedPage)App.Current.MainPage;
var main = mp.CurrentPage;

Related

How can I access programmatically created UI Elements in Xamarin.Forms : timepicker

I got a method which is creating UI Element programmatically. Example:
Label label1 = new Label();
label1.Text = "Testlabel";
TimePicker timepicker1 = new TimePicker();
timepicker1.Time = new TimeSpan(07, 00, 00);
After that I add both of them in an already existing StackLayout.
stacklayout1.Children.Add(label1);
stacklayout1.Children.Add(timepicker1);
A user of my app can create this multiple times.
Now my question is, how can I access, for example, the second/ better all of TimePickers which were created?
Some suggestions:
Use ID:
var id = label1.Id;
var text = (stacklayout1.Children.Where(x => x.Id == id).FirstOrDefault() as myLabel).Text;
Use index:
Label labelOne = stacklayout1.Children[0] as Label;
Use tag:
Create a custom property tag to the label:
public class myLabel : Label{
public int tag { get; set; }
}
And find label by the tag:
var labels = stacklayout1.Children.Where(x => x is myLabel).ToList();
foreach (myLabel childLabel in labels)
{
if (childLabel.tag == 0)
{
}
}
BTW, if you create the label in xaml, you can use findbyname:
Label label = stacklayout1.FindByName("labelA") as Label;
var timepickers = stacklayout1.Children.Where(child => child is TimePicker);
Will return an IEnumerable of all of the timepickers added to your StackLayout. You will have to also add using System.Linq to your usings at the top of the page.

FastObjectListView UpdateObject() randomly reorders rows within primary sort

Data is a generic List of domain objects.
I click the "Deploy Status" column header to sort on that column.
I have a button that does nothing more than folv.UpdateObject(someObject) .
Every time I press that button, the Deploy Status column maintains its sort, but all rows within the sorted blocks are randomly reordered, as per screenshot.
I have commented out everything in the form's code beyond loading the data, the test button, and the FastObjectListView's column.Add() and .SetObjects(). There are no event handlers wired up for the FastObjectListView. I am not setting PrimarySort or SecondarySort in code; only by clicking with the mouse.
You should be able to fix this problem by either calling Sort after your button's call to UpdateObject or changing your usage of UpdateObject to RefreshObject
Reproducing the problem (C# Repro for the issue in the API)
This seems to reproduce the problem you are having. Run the code, sort the Other column ascending. Click the update button.
public class MainForm : Form
{
public MainForm()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
//
// MainForm
//
this.ClientSize = new System.Drawing.Size(300, 300);
this.Name = "MainForm";
this.ResumeLayout(false);
this.PerformLayout();
var OLVa = new FastObjectListView();
OLVa.Width = 250;
OLVa.Height = 250;
OLVa.Columns.Add(new OLVColumn("ID", "ID"));
OLVa.Columns.Add(new OLVColumn("Other", "Other"));
var l1 = new lolz(1, 3);
OLVa.AddObject(l1);
OLVa.AddObject(new lolz(2,3));
this.Controls.Add(OLVa);
var btn = new Button()
{
Text = "Update",
Top = OLVa.Bottom
};
btn.Click += (s,e)=>OLVa.UpdateObject(l1);
this.Controls.Add(btn);
}
private class lolz
{
public int ID;
public int Other;
public lolz(int id, int other)
{
ID = id;
Other = other;
}
}
}
Fixing the problem
The following would fix it for the above example:
btn.Click += (s,e)=>
{
OLVa.BeginUpdate();
try
{
OLVa.UpdateObject(l1);
OLVa.Sort();
}
finally
{
OLVa.EndUpdate();
}
};

Unable to scroll from tabbed pages in ios

I have created four tabs
Current
Upcoming
Archived
Cancelled
Each page contains a listview.
Onclick of 1.current is able to scroll list but onclick of other tabs are not able to scroll
Expecting to scroll list onclick of each bottom tab in ios
I tried scrollTO method
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TrainBookingPage : TabbedPage
{
public TrainBookingPage()
{
InitializeComponent();
var navCurrentBooking = new NavigationPage(new CurrentTrainBooking());
navCurrentBooking.Title = " Current";
var navUpcomingBooking = new NavigationPage(new UpcomingTrainBooking());
navUpcomingBooking.Title = "Upcoming";
var navArchivedBooking = new NavigationPage(new ArchivedTrainBooking());
navArchievedBooking.Title = "Archived";
var navCancelledBooking = new NavigationPage(new CancelledTrainBooking());
navCancelledBooking.Title = "Cancelled";
Children.Add(navCurrentBooking);
Children.Add(navUpcomingBooking);
Children.Add(navArchivedBooking);
Children.Add(navCancelledBooking);
}
}

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.