I want to apply Montserrat-Light font style in all the label and entry, I am doing it by making a renderer of controls. EntryRenderer is working fine but LabelRenderer is giving ArgumentNullException with message: Value can not be null.
[assembly: ExportRenderer(typeof(Label), typeof(ExtendedLabelRenderer))]
namespace NewApp.iOS.Renderer
{
public class ExtendedLabelRenderer : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
Control.Font = UIFont.FromName("Montserrat-Light", 10f);
}
}
}
}
Try below code. It will update if you haven't specified font-family and size in your XAML. Now you can set in your XAML also.
public class CustomLabelRender : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (Control != null)
{
if (e.NewElement != null)
{
if (!String.IsNullOrEmpty(Element.FontFamily))
Control.Font = UIFont.FromName(this.Element.FontFamily, (nfloat)e.NewElement.FontSize);
}
}
}
}
As an easier approach to this issue, I would like to recommend the Label element and/or the CustomFontEffect of the free, open source Forms9Patch NuGet package. It allows you to store your custom font as an Embedded Resource in your Xamarin.Forms application's cross platform project (.NetStandard, PCL, or Shared Library) and then set that font's Embedded Resource ID as the FontFamily for any Xamarin.Forms element that has the FontFamily property.
var entry = new Xamarin.Forms.Entry {
Text = "Xamarin.Forms.Entry element",
FontFamily = "Forms9PatchDemo.Resources.Fonts.Pacifico.ttf"
};
entry.Effects.Add(Effect.Resolve("Forms9Patch.CustomFontEffect"));
var label = new Forms9Patch.Label
{
Text = "Custom Font Text",
FontFamily = "Forms9PatchDemo.Resources.Fonts.Pacifico.ttf"
}
Full disclosure: I am the author of this package.
Related
I wanted to create a page render with ContentPage type. I created so in android and it is working but in IOS there has custom page renderer with same type (ContentPage). It can be removed as this was from nuget package and working on different context.
Here is my code
[assembly: ExportRenderer(typeof(ContentPage), typeof(CustomPageRenderer))]
namespace AlwinInvoiceGenerator.IOS
{
using CoreGraphics;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
public class CustomPageRenderer : PageRenderer
{
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
if (Element == null || !(Element is ContentPage basePage) || basePage.BindingContext == null ||
!(basePage.BindingContext is BaseViewModel baseViewModel))
{
return;
}
SetCustomBackButton(baseViewModel);
}
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
OverrideUserInterfaceStyle = UIUserInterfaceStyle.Light;
}
private void SetCustomBackButton(BaseViewModel baseViewModel)
{
var fakeButton = new UIButton {Frame = new CGRect(0, 0, 50, 40), BackgroundColor = UIColor.Clear};
fakeButton.TouchDown += (sender, e) =>
{
baseViewModel.OnBackButtonClicked();
};
NavigationController?.NavigationBar.AddSubview(fakeButton);
}
}
It seems it not registering and that is why not calling.
I have another page renderer that is register in assembly
[assembly: ExportRenderer(typeof(ContentPage), typeof(IOSToolbarExtensions.iOS.Renderers.IOSToolbarExtensionsContentPageRenderer), Priority = short.MaxValue)]
If I removed this line then above code is working but not two in the same time.
Please help
Same type seems not working for multiple renderer.
I have created sub type of my custom renderer and override the methods which needed to. It is working well
I need to add borders for captions in my application, what's the best way to do it?
I've tried using outline fonts (examples) but they are transparent and I need white text with black border.
You could use custom renderer to achieve this effect.
For ios:
create a custom OutLineLabel which extends UILabel in ios project.
public class OutLineLabel:UILabel
{
public OutLineLabel(string text)
{
this.Text = text;
}
public override void DrawText(CGRect rect)
{
CGSize shadowOffset = this.ShadowOffset;
UIColor textColor = UIColor.White; //the text color
CGContext c = UIGraphics.GetCurrentContext();
c.SetLineWidth(2);
c.SetLineJoin(CGLineJoin.Round);
c.SetTextDrawingMode(CGTextDrawingMode.Stroke);
this.TextColor = UIColor.Black; //the outline border color
base.DrawText(rect);
c.SetTextDrawingMode(CGTextDrawingMode.Fill);
this.TextColor = textColor;
this.ShadowOffset = new CGSize(0, 0);
base.DrawText(rect);
this.ShadowOffset = shadowOffset;
}
}
create custom renderer OutLineLabelRenderer in ios project
[assembly: ExportRenderer(typeof(Label), typeof(OutLineLabelRenderer))]
namespace your namespace
{
class OutLineLabelRenderer:LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
OutLineLabel outLineLabel = new OutLineLabel(Element.Text);
SetNativeControl(outLineLabel);
}
}
}
For android
You could refer to this link.
I'm new in Xamarin and i'm trying to create a simple page with some components.
One of these component is a Switch it works fine by itself but i would like to change the basic text "inactive/active" by "male/female"
I've seen that in Xaml for windows phone there is a ToggleSwitch Component with a On/OffContent property but i can't seems to find an equivalent in XAML for Xamarin Forms
any idea ?
Thank you!
The lack of built in switch options, or at least the lack of being able to rename the switch options, has been asked a few times.
You could go with custom renders, modify the text at the OS level or do like I chose to do, just build your own switch.
This switch is two buttons laid out horizontally with the text Yes and No. The selected button gets a red border, and the unselected a transparent border.
class CustomSwitch : Grid
{
public event EventHandler<SelectedItemChangedEventArgs> ItemSelected;
private Button negative;
private Button positive;
public static readonly BindableProperty SelectedItemProperty = BindableProperty.Create<CustomSwitch, Object>(t => t.SelectedItem, null, BindingMode.TwoWay, propertyChanged: OnSelectedItemChanged);
public CustomSwitch()
{
try
{
this.HorizontalOptions = LayoutOptions.Center;
this.VerticalOptions = LayoutOptions.Center;
negative = new Button();
negative.Text = "No";
negative.Style = <YourNameSpace>.AppStyling.Style_Button_Switch;
negative.Clicked += (o,s) => OnSelectedItemChanged(this, ItemSelected, (int)Classes.Collections.Enums.SelectionStatus.False);
positive = new Button();
positive.Text = "Yes";
positive.Style = <YourNameSpace>.AppStyling.Style_Button_Switch;
positive.Clicked += (o, s) => OnSelectedItemChanged(this, ItemSelected, (int)Classes.Collections.Enums.SelectionStatus.True);
this.Children.Add(negative, 0,0);
this.Children.Add(positive, 1,0);
}
catch(System.Exception ex)
{
<YourNameSpace>.Classes.Helpers.Helper_ErrorHandling.SendErrorToServer(ex, this.GetType().Name, System.Reflection.MethodBase.GetCurrentMethod().Name);
}
}
public Object SelectedItem
{
get
{
return base.GetValue(SelectedItemProperty);
}
set
{
if (SelectedItem != value)
{
base.SetValue(SelectedItemProperty, value);
InternalUpdateSelected();
}
}
}
private void InternalUpdateSelected()
{
if((int)SelectedItem == (int)Classes.Collections.Enums.SelectionStatus.False)
{
negative.BorderColor = <YourNameSpace>.AppStyling.Color_Selected;
positive.BorderColor = <YourNameSpace>.AppStyling.Color_UnSelected;
positive.Opacity = <YourNameSpace>.AppStyling.Opaque_High;
}
else if ((int)SelectedItem == (int)Classes.Collections.Enums.SelectionStatus.True)
{
negative.BorderColor = <YourNameSpace>.AppStyling.Color_UnSelected;
negative.Opacity = <YourNameSpace>.AppStyling.Opaque_High;
positive.BorderColor = <YourNameSpace>.AppStyling.Color_Selected;
}
else
{
negative.BorderColor = <YourNameSpace>.AppStyling.Color_UnSelected;
negative.Opacity = <YourNameSpace>.AppStyling.Opaque_High;
positive.BorderColor = <YourNameSpace>.AppStyling.Color_UnSelected;
positive.Opacity = <YourNameSpace>.AppStyling.Opaque_High;
}
}
private static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
{
CustomSwitch boundSwitch = (CustomSwitch)bindable;
if((int)newValue != (int)Classes.Collections.Enums.SelectionStatus.Unselected)
{
boundSwitch.SelectedItem = (int)newValue == (int)Classes.Collections.Enums.SelectionStatus.False ? (int)Classes.Collections.Enums.SelectionStatus.False : (int)Classes.Collections.Enums.SelectionStatus.True;
}
if (boundSwitch.ItemSelected != null)
{
boundSwitch.ItemSelected(boundSwitch, new SelectedItemChangedEventArgs(newValue));
}
boundSwitch.InternalUpdateSelected();
}
}
Goal
I want to display the text that I put in the Label's "Error on ErrorProvider1" attribute whenever I get an error. See the following label's attributes below.
I try to display the text in the red rectangle into my ErrorProvider1 SetError(control, value) function.
If TextBox1.Text.Trim.Contains("'") Then
ErrorProvider1.SetError(lblErr, ErrorProvider1.GetError(lblErr))
Else
ErrorProvider1.SetError(lblErr, "")
End If
How can I retrieve the 'Error on ErrorProvider1' text from the lblErr to display it in the ErrorProvider1 SetError value?
The ErrorProvider component is very awkward to use effectively. It is fixable however, I'll give an example in C# that extends the component with some new capabilities:
ShowError(Control ctl, bool enable) displays the text that you entered at design-time when the enable argument is true. The easier-to-use version of SetError().
HasErrors returns true if the any active warning icons are displayed. Handy in your OK button's Click event handler.
FocusError() sets the focus to the first control that has a warning icon, if any. It returns false if no warnings are remaining.
SetError() is a replacement of ErrorProvider.SetError(). You only need it if you add any controls after the form's Load event fired or if you need to modify the warning text.
Add a new class to your project and paste the code shown below. Compile. Drop it from the top of the toolbox onto the form. The design-time behavior is identical. Modestly tested.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.ComponentModel.Design;
class MyErrorProvider : ErrorProvider {
public void ShowError(Control ctl, bool enable) {
// Easy to use version of SetError(), uses design-time text
if (!enable) base.SetError(ctl, "");
else {
if (errors.ContainsKey(ctl)) base.SetError(ctl, errors[ctl]);
else base.SetError(ctl, "No error text available");
}
}
public bool HasErrors {
// True if any errors are present
get {
foreach (var err in errors)
if (!string.IsNullOrEmpty(base.GetError(err.Key))) return true;
return false;
}
}
public bool FocusError() {
// Set the focus to the first control with an active error
foreach (var err in errors) {
if (!string.IsNullOrEmpty(base.GetError(err.Key))) {
err.Key.Focus();
return true;
}
}
return false;
}
public new void SetError(Control ctl, string text) {
// Use this only to add/modify error text after the form's Load event
if (!string.IsNullOrEmpty(text)) {
if (errors.ContainsKey(ctl)) errors[ctl] = text;
else errors.Add(ctl, text);
}
base.SetError(ctl, text);
}
private void initialize(object sender, EventArgs e) {
// Preserve error text
copyErrors(((Form)sender).Controls);
}
private void copyErrors(Control.ControlCollection ctls) {
foreach (Control ctl in ctls) {
var text = this.GetError(ctl);
if (!string.IsNullOrEmpty(text)) {
errors.Add(ctl, text);
base.SetError(ctl, "");
}
copyErrors(ctl.Controls);
}
}
private Dictionary<Control, string> errors = new Dictionary<Control, string>();
// Plumbing to hook the form's Load event
[Browsable(false)]
public new ContainerControl ContainerControl {
get { return base.ContainerControl; }
set {
if (base.ContainerControl == null) {
var form = value.FindForm();
if (form != null) form.Load += initialize;
}
base.ContainerControl = value;
}
}
public override ISite Site {
set {
// Runs at design time, ensures designer initializes ContainerControl
base.Site = value;
if (value == null) return;
IDesignerHost service = value.GetService(typeof(IDesignerHost)) as IDesignerHost;
if (service == null) return;
IComponent rootComponent = service.RootComponent;
this.ContainerControl = rootComponent as ContainerControl;
}
}
}
Your issue is that you are replacing the error message when nothing is wrong. As noted in your comment below, you are storing the localized error message in the label's Tag, so you can do the following:
If TextBox1.Text.Trim.Contains("'") Then
ErrorProvider1.SetError(lblErr, lblErr.Tag)
Else
ErrorProvider1.SetError(lblErr, "")
End If
You were correct to use ErrorProvider1.GetError(Control) to get the value. It's just that you're more than likely replacing it with an empty string before you were retrieving it.
I'm using dataexporter to create a pdf of a data table, in my data table the header of the columns is centralized, however the pdf version of the same columns is align to the left. how can I make the columns of the pdf be centralized like the data table.
I use the solution to customize the PDFExporter, it work very well, thank you for your attention. Below is how i've done:
My custom class:
public class CustomPDFExporter extends PDFExporter {
#Override
protected void addColumnFacets(DataTable table, PdfPTable pdfTable, ColumnType columnType) {
for(UIColumn col : table.getColumns()) {
if(!col.isRendered()) {
continue;
}
if(col instanceof DynamicColumn) {
((DynamicColumn) col).applyModel();
}
if(col.isExportable()) {
addHeaderValue(pdfTable, col.getFacet(columnType.facet()), FontFactory.getFont(FontFactory.TIMES, "iso-8859-1", Font.DEFAULTSIZE, Font.BOLD));
}
}
}
protected void addHeaderValue(PdfPTable pdfTable, UIComponent component, Font font) {
String value = component == null ? "" : exportValue(FacesContext.getCurrentInstance(), component);
PdfPCell cell = new PdfPCell(new Paragraph(value, font));
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
pdfTable.addCell(cell);
}
}
bean:
public void exportPDF(DataTable table, String filename) throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
Exporter exporter = new CustomPDFExporter();
exporter.export(context, table, filename, false, false, "iso-8859-1", null, null);
context.responseComplete();
}
In my page I added:
<h:commandLink action="#{boxBean.exportPDF(boxTable, 'relatorio_caixas')}" >
<p:graphicImage value="/resources/img/pdf.png"/>
</h:commandLink>
Well your answer is already on stackoverflow: changing style on generating pdf with Primefaces dataExporter
Also take a look here: http://www.primefaces.org/showcase/ui/exporterProcessor.jsf how to use the exportProcessor of Primefaces.
In short you need to create your own processor to create an custom PDF