I'm having a small issue modding the code below. It works fine except that I have to set the typeface permanently in the nIcon class. I want to use it for different typefaces from my xaml file.
In the example code below, I want the typeface to change from the default "FontAwesome" to the "Ionicons" as stated in the xaml file.
Since Xaml does not accept parameters when creating the class, I have no idea how to set it.
Any ideas?
Xaml Code:
<controls:nIcon
Text="\nf011"
FontFamily="Ionicons"/>
Shared code:
public class nIcon : Label
{
public const string Typeface = "FontAwesome";
public nIcon()
{
\\ FontFamily = Typeface;
}
}
Android Renderer:
public class IcDroidRenderer : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
Control.Typeface = Typeface.CreateFromAsset(Forms.Context.Assets, nIcon.Typeface + ".ttf");
}
}
}
Related
I've got a Xamarin.Forms WPF application running, but there is a huge title bar.
I have tried the solution of adding NavigationPage.SetHasNavigationBar(this, false); inside my MainPage class's constructor
Here is the code:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
}
}
Still I am getting huge title bar size in WPF application, on the other hand, while running on UWP, it is working fine.
You could try to add below codes in your MainWindow.xaml.cs in wpf project:
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
if (!topBarsRemoved) RemoveTopBars();
}
private bool topBarsRemoved = false;
private void RemoveTopBars()
{
var topAppBar = this.Template.FindName("PART_TopAppBar", this) as FormsAppBar;
if (topAppBar != null)
(topAppBar.Parent as System.Windows.Controls.Grid)?.Children.Remove(topAppBar);
topBarsRemoved = true;
}
I would like to scroll to the first character of the editor control. Currently when new data is imported into the control, the control scrolls to the bottom which isn't the behavior I want. I don't see a clear way to accomplish this.
This needs to be set at load only as the user needs the ability to type without the cursor jumping to the begging during typing.
The following works for me which I've modified from the answer below. This is set in the Custom Rendered for Android:
protected override void OnVisibilityChanged(global::Android.Views.View changedView, [GeneratedEnum] ViewStates visibility)
{
base.OnVisibilityChanged(changedView, visibility);
Control.SetSelection(0);
}
You can custom a CustomEditorRenderer in native solution to achieve that .
Android :
[assembly: ExportRenderer(typeof(Editor), typeof(CustomEditorRenderer))]
namespace AppEntryTest.Droid
{
class CustomEditorRenderer : EditorRenderer
{
public CustomEditorRenderer(Context context) : base(context)
{
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
//set position from 0
Control.SetSelection(0);
}
}
The effect :
iOS :
[assembly: ExportRenderer(typeof(Editor), typeof(CustomEditorRenderer))]
namespace AppEntryTest.iOS
{
class CustomEditorRenderer : EditorRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
{
base.OnElementChanged(e);
Control.BecomeFirstResponder();
NSRange range;
range.Location = 0;
range.Length = 0;
Control.SelectedRange = range;
}
}
The effect :
=============================Update=============================
First , create renderer class in each platform :
Uesd in Xaml as follow :
<Editor Text="{Binding EditorValue}" />
In addition , also can create a custom Editor in Forms :
public class MyEditor : Editor
{
}
Used in Xaml : <local:MyEditor Text="{Binding EditorValue}" />
In rederer class , assembly also need to modify to use the custom Editor .
[assembly: ExportRenderer(typeof(MyEditor), typeof(CustomEditorRenderer))]
I would like to add tooltips in Xamarin for UWP by using a native view and the Windows.UI.Xaml Nuget package. I have added the following reference to the xaml page to get the windows native view:
<ContentPage
xmlns:win="clr-namespace:Windows.UI.Xaml.Controls;assembly=Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime;targetPlatform=Windows"
</ContentPage>
I can successfully access native windows controls, e.g. a TextBlock:
< win: TextBlock Text="S"/>
However, when I try to add the tooltip to the control:
<win:TextBlock Text="S" ToolTipService.ToolTip="Service agreement"/>
I get the following exception during compilation:
"Xamarin.Forms.Xaml.XamlParseException: 'Position 56:45. Type
ToolTipService not found in xmlns
http://xamarin.com/schemas/2014/forms'"
Is the system getting confused between the standard Windows.UI.Xaml.Controls namespace and the extended one from the Nuget package?
ToolTipService is attached property, and it will not find ToolTipService assembly in Forms client, the better way is use Effect to create your own tip service and render it in UWP platform. You could refer the following steps.
Create a subclass of the PlatformEffect class.
Override the OnAttached method and write logic to customize the control.
Override the OnDetached method and write logic to clean up the control customization, if required.
Add a ResolutionGroupName attribute to the effect class. This attribute sets a company wide namespace for effects, preventing collisions with other effects with the same name. Note that this attribute can only be applied once per project.
Add an ExportEffect attribute to the effect class. This attribute registers the effect with a unique ID that's used by Xamarin.Forms, along with the group name, to locate the effect prior to applying it to a control. The attribute takes two parameters – the type name of the effect, and a unique string that will be used to locate the effect prior to applying it to a control.
UWP Code Part
[assembly: ResolutionGroupName("Microsoft")]
[assembly: ExportEffect(typeof(UWPToolTipEffect), nameof(TooltipEffect))]
namespace NativeSwitch.UWP
{
public class UWPToolTipEffect : PlatformEffect
{
protected override void OnAttached()
{
var control = Control ?? Container;
if (control is DependencyObject)
{
ToolTip toolTip = new ToolTip();
toolTip.Content = TooltipEffect.GetText(Element);
switch (TooltipEffect.GetPosition(Element))
{
case TooltipPosition.Bottom:
toolTip.Placement = Windows.UI.Xaml.Controls.Primitives.PlacementMode.Bottom;
break;
case TooltipPosition.Top:
toolTip.Placement = Windows.UI.Xaml.Controls.Primitives.PlacementMode.Top;
break;
case TooltipPosition.Left:
toolTip.Placement = Windows.UI.Xaml.Controls.Primitives.PlacementMode.Left;
break;
case TooltipPosition.Right:
toolTip.Placement = Windows.UI.Xaml.Controls.Primitives.PlacementMode.Right;
break;
default:
return;
}
ToolTipService.SetToolTip(control, toolTip);
}
}
protected override void OnDetached()
{
}
}
}
Forms code part
public static class TooltipEffect
{
public static readonly BindableProperty TextProperty =
BindableProperty.CreateAttached("Text", typeof(string), typeof(TooltipEffect), string.Empty, propertyChanged: OnTextChanged);
public static readonly BindableProperty PositionProperty =
BindableProperty.CreateAttached("Position", typeof(TooltipPosition), typeof(TooltipEffect), TooltipPosition.Bottom);
public static string GetText(BindableObject view)
{
return (string)view.GetValue(TextProperty);
}
public static void SetText(BindableObject view, string value)
{
view.SetValue(TextProperty, value);
}
public static TooltipPosition GetPosition(BindableObject view)
{
return (TooltipPosition)view.GetValue(PositionProperty);
}
public static void SetPosition(BindableObject view, TooltipPosition value)
{
view.SetValue(PositionProperty, value);
}
static void OnTextChanged(BindableObject bindable, object oldValue, object newValue)
{
var view = bindable as View;
if (view == null)
{
return;
}
string text = (string)newValue;
if (!string.IsNullOrEmpty(text))
{
view.Effects.Add(new ControlTooltipEffect());
}
else
{
var toRemove = view.Effects.FirstOrDefault(e => e is ControlTooltipEffect);
if (toRemove != null)
{
view.Effects.Remove(toRemove);
}
}
}
}
public enum TooltipPosition
{
Bottom,
Right,
Left,
Top
}
class ControlTooltipEffect : RoutingEffect
{
public ControlTooltipEffect() : base($"Microsoft.{nameof(TooltipEffect)}")
{
}
}
Usage
// forms project namesapce
xmlns:effects="clr-namespace:ToolTipTestApp"
......
<win:TextBlock
effects:TooltipEffect.Position="Right"
effects:TooltipEffect.Text="Hello"
Text="Hello Wrold"
/>
I am using Xamarin Forms picker control and require setting the text color, however there is no such property. I have tried making a custom renderer which worked out for me in android and ios (I ended up redrawing the control). In the wp8.1 platform there is no Draw event and the control itself in the renderer doesn't seem to have the properties to set the text color. I have also attempted changing the control the picker binds to unsuccessfully.
Currently I have created the bindable property TextColor in the PCL which is working. The code for my renderer is shown below (I have stripped all my test code and am putting only the basic code since I havent found anything useful yet and am putting my code just to keep everyone in context). Also note that the property Picker.TextColorProperty doesnt exist and is what I would like to do...
using Namespace.CustomControls;
using Namespace.WinPhone.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.WinPhone;
[assembly: ExportRendererAttribute(typeof(BindablePicker), typeof(BindablePickerRenderer))]
namespace Namspace.WinPhone.Renderers
{
public class BindablePickerRenderer : PickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
var picker = e.NewElement;
BindablePicker bp = (BindablePicker)this.Element;
if (this.Control != null)
{
var pickerStyle = new Style(typeof(Picker))
{
Setters = {
new Setter {Property = Picker.BackgroundColorProperty, Value = bp.BackgroundColor},
new Setter {Property = Picker.TextColorProperty, Value = bp.TextColor}
}
};
picker.Style = pickerStyle;
}
}
}
}
Anyhow I am wondering if anyone might have a little more knowledge on how to do this and could shed some light on me.
There is no TextColor property available in the Picker like you mention.
Even this being the case, we can still achieve changing the Picker text color for WindowsPhone.
I'm assuming you are inheriting from PickerRenderer as it was missing from your code example and I've added some extra things so this is more helpful to others:-
Define the interface in the PCL:-
public interface ICustomPicker2
{
Xamarin.Forms.Color MyBackgroundColor { get; set; }
Xamarin.Forms.Color MyTextColor { get; set; }
}
Extend the Xamarin.Forms Picker in the PCL:-
public class CustomPicker2
: Xamarin.Forms.Picker
, ICustomPicker2
{
public static readonly BindableProperty MyBackgroundColorProperty = BindableProperty.Create<CustomPicker2, Xamarin.Forms.Color>(p => p.MyBackgroundColor, default(Xamarin.Forms.Color));
public static readonly BindableProperty MyTextColorProperty = BindableProperty.Create<CustomPicker2, Xamarin.Forms.Color>(p => p.MyTextColor, default(Xamarin.Forms.Color));
public Xamarin.Forms.Color MyTextColor
{
get { return (Xamarin.Forms.Color)GetValue(MyTextColorProperty); }
set { SetValue(MyTextColorProperty, value); }
}
public Xamarin.Forms.Color MyBackgroundColor
{
get { return (Xamarin.Forms.Color)GetValue(MyBackgroundColorProperty); }
set { SetValue(MyBackgroundColorProperty, value); }
}
}
Create your WindowsPhone renderer like so in a class library:-
public class CustomPicker2Renderer
: PickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
var picker = e.NewElement;
CustomPicker2 bp = (CustomPicker2)this.Element;
if (this.Control != null)
{
var pickerStyle = new Style(typeof(Picker))
{
Setters = {
new Setter {Property = Picker.BackgroundColorProperty, Value = bp.MyBackgroundColor},
}
};
SetPickerTextColor(bp.MyTextColor);
picker.Style = pickerStyle;
}
}
private void SetPickerTextColor(Xamarin.Forms.Color pobjColor)
{
byte bytR = (byte)(pobjColor.R * 255);
byte bytG = (byte)(pobjColor.G * 255);
byte bytB = (byte)(pobjColor.B * 255);
byte bytA = (byte)(pobjColor.A * 255);
//
((System.Windows.Controls.Control)(((System.Windows.Controls.Panel)this.Control).Children[0])).Foreground = new SolidColorBrush(System.Windows.Media.Color.FromArgb(bytA, bytR, bytG, bytB));
}
Note, the above is all what you need if you just want to set the text color the once.
However if you want to change the color after it has been initially set, then you will need to listen to the property change and act upon it like in the following:-
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
//
if (e.PropertyName == "MyTextColor")
{
SetPickerTextColor((this.Element as CustomPicker2).MyTextColor);
}
}
You will also need to export the renderer from the class library as well:-
[assembly: ExportRendererAttribute(typeof(CustomPicker2), typeof(CustomPicker2Renderer))]
I'm trying to display a list view with cells that are rendered with a custom iOS renderer. When scrolling the list, there are nasty overlays (as shown below). I boiled it down to the following lines of code.
The App contains a ListView with its ItemsSource set to a dummy list of all characters from A to Z. The ItemTemplate is created with a custom ItemCell defined below.
public class App : Application
{
public App()
{
MainPage = new ContentPage {
Content = new ListView {
ItemsSource = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray(),
ItemTemplate = new DataTemplate(typeof(ItemCell)),
},
};
}
}
The ItemCell contains a Label bound to the list item.
public class ItemCell: ViewCell
{
public ItemCell()
{
View = new Label();
View.SetBinding(Label.TextProperty, ".");
}
}
On iOS the Label is rendered with the following FixedLabelRenderer. It sets a native control represented by a UILabel containing the Element's Text.
public class FixedLabelRenderer : ViewRenderer<Label, UILabel>
{
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
SetNativeControl(new UILabel(RectangleF.Empty) { Text = Element.Text });
}
}
Now the problem is that, apparently, when reusing a cell, the control is not removed, but only a new one is created. So I'm getting the overlays shown in the screenshots below.
(Left: before scrolling, Right: after scrolling)
Interestingly this issue doesn't happen with Xamarin.Forms 1.2.3 or 1.3.1, but with 1.3.5 and 1.4.0.
Oh, I found a solution on the Xamarin Forum:
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
{
base.OnElementChanged(e);
if (Control == null)
SetNativeControl(new UILabel());
if (e.NewElement != null)
Control.Text = e.NewElement.Text;
}
So basically you need to make sure to only create one UILabel and reuse it afterwards.