FontAwesome / Xamarin - Setting Glyph not working from code behind - c#

I missing something here when using FontAwesome on Xamarin... the buttons work fine when setting from xaml file but when I try to set from code behind it doesn't show the icon, here is the scenario:
button working fine:
<Button Grid.Row="0" Grid.Column="4" x:Name="btnIdDav" Padding="10" Margin="3" TextColor="#FFF" BackgroundColor="#565C5A" Clicked="btnIdDav_Clicked" WidthRequest="45">
<Button.ImageSource>
<FontImageSource FontFamily="{StaticResource FontAwesomeSolidOTF}" Glyph="" Color="#fff"/>
</Button.ImageSource>
</Button>
Last time I had to set Glyph from code, I had to do a bad 'workaround' with converter in order to show it, and it worked (icon is showing) in the end:
public const string _dollarGlyph = "\uf155";
public const string _percGlyph = "\uf541";
public class DescGlyphConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Glyph="{Binding DescImage, Converter={StaticResource Key=desconto}}
NOW I want to create a custom button and set the Glyph but the icon is not appearing (tested with both OTF and TTF files):
public static FontImageSource GetImgSource()
{
FontImageSource source = new FontImageSource();
source.FontFamily = Application.Current.Resources["FontAwesomeSolidTTF"].ToString();
source.Glyph = "\uf3e5";
source.Color = Color.FromHex("#fff");
return source;
}
public static Style BtnBack() {
return new Style(typeof(Button))
{
Setters = {
new Setter { Property = Button.ContentLayoutProperty, Value = new ButtonContentLayout(ButtonContentLayout.ImagePosition.Top, 5) },
new Setter { Property = Button.TextProperty, Value = "Back" },
new Setter { Property = Button.ImageSourceProperty, Value = GetImgSource()},
}
};
}
Any sugestions?
Thanks!

Here is the sample code, please change accordingly. I am using the FontFile name directly:
FontImageSource fontImageSource = new FontImageSource()
{
Glyph = "\uf15c",
Color = Color.Black,
Size = 18,
FontFamily = Device.RuntimePlatform == Device.Android ? "FontAwesome.otf#Regular" : null
};
this.IconImageSource = fontImageSource;

Related

Item to Display for Picker don't show up on load

This is Xamarin Forms app. I'm using Fresh MVVM. I have Modification Page, where i can change boolean value with picker (true, false, null).
I have list of boolean values (for each picker - one value and in ViewModel list filled from DB).Bool converts (using converter) to object with two values: Text(string) and Value(bool?) which is class - CheckListValue written below.
The logic - i'm putting some values with picker, saving it to DB and after i can modify it, so on load, i should see chosen value. But picker field - empty.
Here is result, what i see. I should see Binded Item in ItemDisplayBinding, and its Text (Negative, Positive or Empty).
I thought that the problem in Binding, but it seems okay.
<Picker Grid.Row="1" Grid.Column="0" ItemsSource="{Binding CheckListValueList, Mode=TwoWay}"
ItemDisplayBinding="{Binding Text}" SelectedItem="{Binding CheckListProperties.SomeBooleanValue, Mode=TwoWay, Converter={StaticResource BoolToCheckListConverter}}"/>
here is CheckListValue
public static CheckListValue Positive=> new CheckListValue
{
Text = "Positive",
Value = true
};
public static CheckListValue Negative=> new CheckListValue
{
Text = "Negative",
Value = false
};
public static CheckListValue Empty=> new CheckListValue
{
Text = "Empty",
Value = null
};
public static List<CheckListValue> All => new List<CheckListValue>
{
Positive, Negative, Empty
};
}
public class CheckListValue
{
public string Text { get; set; }
public bool? Value { get; set; }
}
And converter:
public class BoolNullableToCheckListValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var boolValue = value as bool?;
if (!boolValue.HasValue)
return CheckListValues.Empty;
return boolValue.Value ? CheckListValues.Positive : CheckListValues.Negative;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var checkListValue = value as CheckListValue;
return checkListValue?.Value;
}
}
ViewModel:
public List<CheckListValue> CheckListValueList => CheckListValues.All;
public CheckListProperties CheckListProperties { get; set; }
public override void Init(object initData)
{
//Here CheckListProperties takes from DB on every load of Page
}
public class CheckListProperties
{
public bool? PickerBool1 { get; set; }
public bool? PickerBool2 { get; set; }
public bool? PickerBool3 { get; set; }
}
When i'm choosing from picker it works good, changes bool correctly and displays text, but this is modification page and on load, i should see already chosen before values, but its not. Its empty.
Do you know why it could be? Because i have no idea.
Thank you in advance, guys!

How to programmatically create WPF scrollable StackPanel list in C#

My Situation:
I'm developing a C# WPF Application (on Windows) where I need to dynamically create a lot of my controls at runtime. Because of the nature of the application, I'm not able to use standard XAML (with Templates) for many aspects of my WPF windows. This is a very unique case, and no, I'm not going to reconsider the format of my application.
What I want to accomplish:
I would like to programmatically create a control that displays a scrollable list of StackPanels (or any other effecient control group) which, for one use case, will each consist of an Image control (picture) on top of a TextBlock control (title/caption):
I would prefer to do all this without any data bindings (See below for reasoning). Because the items are being defined at runtime, I should be able to do this without them via iteration.
The control/viewer should be able to have multiple columns/rows, so it's not one dimensional (like a typical ListBox control).
It should also interchangeable so that you can modify (add, remove, etc.) the items in the control.
I've included a picture (below) to give you an example of a possible use case.
In the past, I have been able to accomplish all this by using a ListView with an ItemTemplate (wrapped in a ScrollViewer) using XAML. However, doing this entirely with C# code makes it a bit more difficult. I've recently made ControlTemplates in plain c# code (with FrameworkElementFactorys. It can get a bit complicated, and I'm not sure it's really the best practice. Should I try to go the same route (using a ListView with a template)? If so, how? Or is there a simpler, more elegant option to implement with C# code?
Edit: I would really prefer not to use any data bindings. I just want to create a (scrollable) 'list' of StackPanels that I can easily modify/tweak. Using data bindings feels like a backwards implementation and defeats the purpose of the dynamic nature of runtime.
Edit 2 (1/25/2018): Not much response. I simply need a uniform, scrollable list of stackpanels. I can tweak it to suit my needs, but it needs to be all in C# (code-behind). If anyone needs more information/clarification, please let me know. Thanks.
LINK TO XAML POST
Here's a way to do it in code using a ListBox with UniformGrid as ItemsPanelTemplate. Alternatively, you can only use a UniformGrid and put it inside a ScrollViewer, but as the ListBox already handles selection and all that stuff, you probably better stick with that one. This code will automatically adjust the number of items in a row depending on the available width.
MoviePresenter.cs :
public class MoviePresenter : ListBox
{
public MoviePresenter()
{
FrameworkElementFactory factory = new FrameworkElementFactory(typeof(UniformGrid));
factory.SetBinding(
UniformGrid.ColumnsProperty,
new Binding(nameof(ActualWidth))
{
Source = this,
Mode = BindingMode.OneWay,
Converter = new WidthToColumnsConverter()
{
ItemMinWidth = 100
}
});
ItemsPanel = new ItemsPanelTemplate()
{
VisualTree = factory
};
}
}
internal class WidthToColumnsConverter : IValueConverter
{
public double ItemMinWidth { get; set; } = 1;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double? actualWidth = value as double?;
if (!actualWidth.HasValue)
return Binding.DoNothing;
return Math.Max(1, Math.Floor(actualWidth.Value / ItemMinWidth));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
MovieItem.cs :
public class MovieItem : Grid
{
public MovieItem()
{
RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
Image image = new Image();
image.Stretch = Stretch.UniformToFill;
image.SetBinding(Image.SourceProperty, new Binding(nameof(ImageSource)) { Source = this });
Children.Add(image);
TextBlock title = new TextBlock();
title.FontSize += 1;
title.FontWeight = FontWeights.Bold;
title.Foreground = Brushes.Beige;
title.TextTrimming = TextTrimming.CharacterEllipsis;
title.SetBinding(TextBlock.TextProperty, new Binding(nameof(Title)) { Source = this });
Grid.SetRow(title, 1);
Children.Add(title);
TextBlock year = new TextBlock();
year.Foreground = Brushes.LightGray;
year.TextTrimming = TextTrimming.CharacterEllipsis;
year.SetBinding(TextBlock.TextProperty, new Binding(nameof(Year)) { Source = this });
Grid.SetRow(year, 2);
Children.Add(year);
TextBlock releaseDate = new TextBlock();
releaseDate.Foreground = Brushes.LightGray;
releaseDate.TextTrimming = TextTrimming.CharacterEllipsis;
releaseDate.SetBinding(TextBlock.TextProperty, new Binding(nameof(ReleaseDate)) { Source = this });
Grid.SetRow(releaseDate, 3);
Children.Add(releaseDate);
}
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource", typeof(string), typeof(MovieItem), new PropertyMetadata(null));
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(MovieItem), new PropertyMetadata(null));
public static readonly DependencyProperty YearProperty =
DependencyProperty.Register("Year", typeof(string), typeof(MovieItem), new PropertyMetadata(null));
public static readonly DependencyProperty ReleaseDateProperty =
DependencyProperty.Register("ReleaseDate", typeof(string), typeof(MovieItem), new PropertyMetadata(null));
public string ImageSource
{
get { return (string)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public string Year
{
get { return (string)GetValue(YearProperty); }
set { SetValue(YearProperty, value); }
}
public string ReleaseDate
{
get { return (string)GetValue(ReleaseDateProperty); }
set { SetValue(ReleaseDateProperty, value); }
}
}
MainWindow.xaml :
<Grid>
<local:MoviePresenter x:Name="moviePresenter"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"/>
</Grid>
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 20; i++)
{
DateTime dummyDate = DateTime.Now.AddMonths(-i).AddDays(-(i * i));
MovieItem item = new MovieItem()
{
ImageSource = $"http://fakeimg.pl/100x200/?text=Image_{i}",
Title = $"Dummy movie {i}",
Year = $"{dummyDate.Year}",
ReleaseDate = $"{dummyDate.ToLongDateString()}"
};
moviePresenter.Items.Add(item);
}
}
}

Display label text in uppercase using xaml in Xamarin.Forms

I have an username label and need to view this as uppercase but this should only relate to the UI. The data (string) should be saved in the db as actual case whatever it is. Could anyone tell me if there is anyway to convert it to uppercase without doing so through the code behind?
You can use Label.TextTransform with TextTransform.Uppercase.
XAML
<Label TextTransform="Uppercase" />
C#
var label = new Label
{
TextTransform = TextTransform.Uppercase
};
As you're aware you can do this from the code behind as such:
string data = "my data";
UILabel myLabel = new UILabel();
myLabel.Text = data.ToUpper();
So bearing in mind that you don't want to do it this way you would need to derive from UILabel and create your own, then simply add the ToUpper() onto the end of the get;set; values of the Text property.
using CoreGraphics;
using System;
using UIKit;
namespace MyApp.Controls
{
partial class Control_UpperLabel : UILabel
{
public Control_UpperLabel IntPtr handle) : base(handle)
{
//
}
public Control_UpperLabel()
{
//
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
}
public override string Text { get => base.Text.ToUpper(); set => base.Text = value.ToUpper(); }
}
}
EDIT: As per comments below, here is an alternative solution for Xamarin.Forms
This uses a value converter as part of a binding solution. It's also been slightly amended to use the suggestion by clint in the comments below. Thanks.
public class StringCaseConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch ((parameter as string).ToUpper()[0])
{
case 'U':
return ((string)value).ToUpper();
case 'L':
return ((string)value).ToLower();
default:
return ((string)value);
};
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
It would be used in the XAML as such:
Text="{Binding Text, Converter={StaticResource caseConverter}, ConverterParameter=u}}"
Or you can use Bindable property then format the text on the getter :
e.g.:
public static readonly BindableProperty ItemLabelProperty =
BindableProperty.Create(nameof(ItemLabel), typeof(string),
typeof(DetailsLineItemControl), default(string), BindingMode.OneWay);
public string ItemLabel
{
get
{
var value = (string)GetValue(ItemLabelProperty);
return !string.IsNullOrEmpty(value) ? value.ToUpper() : value;
}
set
{
SetValue(ItemLabelProperty, value);
}
}

Xamarin Forms Custom ViewCell, don't add to grid if empty?

I've created a Custom Viewcell, where i bind text to a label and then insert it in a grid. However, how do I avoid empty rows, if the text I pass to the Viewcell is empty? This is just some of the code, but is there somekind of binding I am missing if the text is empty?
public RouteElementsCustomCell()
{
Label NameLbl = new Label()
{
TextColor = Color.Black,
HorizontalTextAlignment = TextAlignment.Center,
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
};
NameLbl.SetBinding(Label.TextProperty, "StopName");
Grid grid = new Grid()
{
Padding = 10,
RowDefinitions =
{
new RowDefinition
{
Height = GridLength.Auto
},
}
};
grid.Children.Add(NameLbl,0,1,0,1);
}
Alright, so this is how I solved this issue with help from #irreal.
This is probably introducing unneeded complexity to your viewmodel. Consider using a xaml value converter which would convert string to boolean. You would then just bind IsVisible="{Binding StopName, Converter={}}" It is super useful, and would allow you to do lots of things, including control visibility based on string not being null or empty - #irreal
Added the Label.IsVisibleProperty to the label, then used an IValueConverter, to check if the string was empty, null or whitespace.
Label
Label NameLbl = new Label()
{
TextColor = Color.Black,
HorizontalTextAlignment = TextAlignment.Center,
VerticalOptions = LayoutOptions.Start,
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label))
};
NameLbl.SetBinding(Label.TextProperty, "StopName");
NameLbl.SetBinding(Label.IsVisibleProperty, "StopName",BindingMode.Default,new StringToBoolConverter(), null);
ValueConverter
public class StringToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string valueAsString = value.ToString();
if (string.IsNullOrWhiteSpace(valueAsString))
{
return false;
}
else
{
return true;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
What I would do is add a public property to my object:
public bool ShowItem { get{return !string.IsNullOrEmpty(StopName)};}
Then bind the IsVisibleProperty to ShowItem

How is [DataMember] used with Image?

I have the following code in a WCF service:
[DataContract]
[KnownType(typeof(Bitmap))]
[KnownType(typeof(Image))]
public class CompositeType {
Image FImg = null;
public Image Picture {
get {
return FImg;
}
set {
FImg = value;
}
}
If I add [DataMember] to the public Image, then the Service Reference gets broken in another solution.
[DataMember]
public Image Picture{
get {
return FImg;
}
set {
FImg = value;
}
}
My question is how do I use [DataMember] and Image at the same time? I know I can use a byte array and am currently doing so and then formatting / converting it in the client that calls my service, but I'd rather bind to the Image instead of having to convert a byte array.
I've found that using the AutoGeneratingColumn event handle on the clientside (the Silverlight application calling my WCF service) works also. Not necessarily an answer to my question, but I think it's useful to know. I would've added as comment, but code is too long.
private void dgResults_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) {
if (e.PropertyType == typeof(byte[])) {
e.Column.Header = e.Column.Header + "_D";
// Create a new template column.
DataGridTemplateColumn templateColumn = new DataGridTemplateColumn();
templateColumn.Header = e.Column.Header + "_E";
templateColumn.CellTemplate = (DataTemplate)Resources["imgTemplate"];
templateColumn.CellEditingTemplate = (DataTemplate)Resources["imgTemplate"];
// ...
// Replace the auto-generated column with the templateColumn.
e.Column = templateColumn;
}
}
The Resources["imgTemplate"] are created in the .XAML file in Silverlight and this code is in its code-behind.
<UserControl.Resources>
<local:BinaryArrayToURIConverter x:Key="binaryArrayToURIConverter" />
<DataTemplate x:Key="imgTemplate">
<Image x:Name="img" Source="{Binding GraphicBytes,Converter={StaticResource binaryArrayToURIConverter}}"/>
</DataTemplate>
</UserControl.Resources>
The local: refers to part of the main XAML declaration:
xmlns:local="clr-namespace:<your namespace here>"
The code for BinaryArrayToURIConverter:
public class BinaryArrayToURIConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
MemoryStream ms = new MemoryStream((byte[])value);
BitmapImage image = new BitmapImage();
image.SetSource(ms);
return image;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}

Categories