How to translate Xamarin Xaml IValueConverter into C#? - xaml

Can you please help me translate this Xamarin xaml into c#?
BackgroundColor="{Binding IconColor, Converter={StaticResource LocalHexColorFromStringConverter}}"/>
Thanks!

You can translate it by MyBtn.SetBinding(Button.BackgroundColorProperty, "IconColor", BindingMode.OneTime, new LocalHexColorFromStringConverter()) ;
I make a test with Button's background color.
Button MyBtn = new Button();
MyBtn.Text = "test";
MyBtn.SetBinding(Button.BackgroundColorProperty, "IconColor", BindingMode.OneTime, new LocalHexColorFromStringConverter()) ;
Content = MyBtn;
Here is LocalHexColorFromStringConverter.cs
public class LocalHexColorFromStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Color.FromHex((string)value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
Can I ask what the difference is between "new LocalHexColorFromStringConverter()" and "converter: LocalHexColorFromStringConverter()" ?
Do you mean "new LocalHexColorFromStringConverter()" and "converter: LocalHexColorFromStringConverter"?
If so, they are same, converter: LocalHexColorFromStringConverter is wirte type in Xaml , converter: is prefix, it explains the specific path of this class, If you want to call it from any pages, you need to write it in the App.xaml.
For example, you add add it in the App.xaml.
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:converters="clr-namespace:OAuthGoogleDemo"
x:Class="OAuthGoogleDemo.App">
<Application.Resources>
<ResourceDictionary>
<converters:LocalHexColorFromStringConverter x:Key="HexColorFromStringConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>
Then use it in the Mainpage.xaml with Converter={StaticResource HexColorFromStringConverter}}"

Related

How to set default value to false when using converter with Label's visibility Xamarin forms

I am using converter with Label's IsVisible property.
<Label IsVisible="{Binding products, Converter={StaticResource EmptyCollectionToBoolConverter}}" Text="No data found">
If products is empty EmptyCollectionToBoolConverter returns true otherwise false. When screen is loading first time "No data found" message appears for fraction of seconds and then data is getting loaded.
I want to fix it, I need to show Label only if when products is empty. How can I do it?
You can overwrite IsVisible value in the code behind.
<Label x:Name="MyLabel" IsVisible="{Binding products, Converter={StaticResource EmptyCollectionToBoolConverter}}" Text="No data found">
Code behind
// probably ctor
MyLabel.IsVisible = false;
Second option can be to use a DataTrigger
<Label Text="No data found" IsVisible="false">
<Label.Triggers>
<DataTrigger TargetType="Label" Binding="{Binding products, Converter={StaticResource EmptyCollectionToBoolConverter}}" Value="True">
<Setter Property="IsVisible" Value="True" />
</DataTrigger>
</Label.Triggers>
</Label>
If you are using a CollectionView you can use the EmptyView , it will display whatever you put in that XAML when the collection is empty.
Or you can implement bindablelayout that also implements the emptyViewTemplate.
Or you will have to create another binding or another converter.
Something like public bool MyBinding{get=> myList!=null | myList.Count != | isLoadingFlag } . But you will have to call the propertychanged event if you modify your collection
I am not sure if this could be your problem, but i would check a couple of things:
You could set the binding not in XAML but in code behind, after data is loaded.
You might need to set the BindingContext to products, if not yet done so.
Also, maybe it is better if you set the binding path of the label to Count property of your collection.
Finally, set IsVisible to false (default) in XAML. This hard code will be overriden by the binding that is set when the data is loaded.
Anyway it is, i worked out a minimal complete working sample that does the job.
It works bassically as follows: Application starts and displays nothing... then goes on to load the data. When data is loaded label appears showing the number of items in collection. Two buttons are also available in Toolbar: Add Item and Remove Item. If you remove all items, No data found label appears.
See comments in code
Page1.xaml.cs
using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace scrollviewPrompt
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Page1 : ContentPage
{
// products is an observable collection so that
// it notifies when it changes.
public ObservableCollection<string> products { get; set; }
public Page1()
{
InitializeComponent();
}
protected override async void OnAppearing()
{
// Initialize your products collection
products = new ObservableCollection<string>();
// Set binding context of the whole Page1
// to your products collection
BindingContext = products;
// Load data asynchronously.
// At this point the data is already bound to
// our collection, so when data is loaded
// "No data found" label will dissapear.
await LoadDataAsync();
base.OnAppearing();
}
private async Task LoadDataAsync()
{
await Task.Delay(4000);
products.Add("Toks");
noDataLabel.SetBinding(Label.IsVisibleProperty, new Binding()
{
Path="Count",
Converter = new EmptyCollectionToBoolConverter()
});
}
// Add items to collection.
private void AddClicked(object sender, EventArgs e)
{
products.Add("locs");
}
// If collection not empty, remove first item.
private void RemoveClicked(object sender, EventArgs e)
{
if (products.Count>0)
products.RemoveAt(0);
}
}
public class EmptyCollectionToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var count = (int)value;
return count==0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class Not_EmptyCollectionToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var count = (int)value;
return count > 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Page1.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:scrollviewPrompt"
x:Class="scrollviewPrompt.Page1">
<ContentPage.Resources>
<ResourceDictionary>
<local:EmptyCollectionToBoolConverter x:Key="EmptyCollectionToBoolConverter"/>
<local:Not_EmptyCollectionToBoolConverter x:Key="Not_EmptyCollectionToBoolConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add Item"
Clicked="AddClicked"/>
<ToolbarItem Text="Remove Item"
Clicked="RemoveClicked"/>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout>
<!--No data found is bound to Count property of BindingContext (products).
when products change, Count changes and IsVisible is updated.-->
<Label x:Name="noDataLabel"
Text="No data found"
IsVisible="false"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
<Label Text="{Binding Path=Count, StringFormat='{0} items'}"
IsVisible="{Binding Path=Count, Converter={StaticResource Not_EmptyCollectionToBoolConverter}}"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
Consider using binding fallbacks, which allow you to specify "default" values when either the binding context is not set, or the binding target is null.
<Label IsVisible="{Binding products, Converter={StaticResource EmptyCollectionToBoolConverter}, FallbackValue='False', TargetNullValue='False'}" Text="No data found">
You may not need both, but it will ensure that the Label is always hidden until both the binding context (ViewModel) can be resolved and the binding target (products) is not null so the converter can properly evaluate whether to show the Label.

Xamarin Forms conditonal formatting based on data with DataTrigger

I am developing a chat application in Xamarin Forms and I am trying to add conditional formatting depending on whether it is an incoming or outgoing message.
This is my XAML:
<Frame
Margin="1"
Padding="0"
x:Name="FrameRef"
x:DataType="model:ChatMessage">
<Frame
CornerRadius="10"
Padding="7"
BackgroundColor="LightBlue"
HasShadow="false"
Margin="10,10,80,0">
<Frame.Triggers>
<DataTrigger
TargetType="Frame"
Binding="{Binding Source={x:Reference FrameRef}, Path=x:DataType.From}" Value="+1456456456">
<Setter Property="BackgroundColor" Value="Yellow"/>
</DataTrigger>
</Frame.Triggers>
When I use Path="Margin" and Value="1" it works.
I am now trying to make it work with the Path being x:DataType="model:ChatMessage" and checking the 'from'-field (indicating if the message was incoming or outgoing).
I'm not sure the Data Trigger is quite right for this application, since you're really depending on a data type and not really the content per se of another field. From the documentation:
The DataTrigger class is suitable for checking values on other controls, as well as any property on the control to which it has been added.
What you probably want instead is a Value Converter that handles locating a StaticResource and applying a style for you based on the message type. Full Microsoft Documentation here.
On your XAML element, you'd do something like this:
<Frame Style="{Binding foo, Converter={StaticResource FooToStyleConverter}}"/>
Your converter would work something like this:
public class FooToStyleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var someValue = (DataTye)value; // Convert 'object' to whatever type you are expecting
// evaluate the converted value
if (someValue.From != null && someValue.From == Enum.SomeoneElse)
return (Style)App.Current.Resources["StyleReceived"]; // return the desired style indicating the message is from someone else
return (Style)App.Current.Resources["StyleSent"]; // return a style indicating the message is from the sender
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// Usually unused, but inverse the above logic if needed
throw new NotImplementedException();
}
}
Lastly, set up your converter as a Static Resource in App.xaml (or as a local resource on the page) so your page can properly reference it
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos">
<ContentPage.Resources>
<ResourceDictionary>
<local:FooToStyleConverter x:Key="FooToStyleConverter" />
....

Type not found on XAML namespace

I am trying to access to method class from XAML file.
My class is on folder: project.Utils.
Adding on xaml Content Page:
xmlns:local="project.Utils"
I try to use myConverterMethod class inside Utils folder and use it as:
Converter={StaticResource myConverterMethod}
but error Type myConverterMethod not found in xmlns project.Utils.
Where is my fault?
You can use
xmlns:local="clr-namespace:project.Utils;assembly=project"
It is not possible to refer to a Method within a specific class but to a IValueConverter.
In order to achieve what you want, you need to define a class that implements IValueConverter:
public class IntToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value != 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? 1 : 0;
}
}
Define the created converter in accessible scope: Page/View or Application. By scope I mean resources:
<ContentPage.Resources>
<ResourceDictionary>
<local:IntToBoolConverter x:Key="intToBool" />
</ResourceDictionary>
</ContentPage.Resources>
and finally consume the converter in the next way:
<Button Text="Search"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand"
IsEnabled="{Binding Source={x:Reference entry1},
Path=Text.Length,
Converter={StaticResource intToBool}}" />
Xamarin has a very nice documentation that will answer all your questions and it usually has a good code samples.

Xamarin Style staticresource binding

would it be possible to databind a static resource in Xamarin Forms?
Something like
Style="{StaticResource {Binding foo, StringFormat='SomeStyle{0}'}}"
Thanks
What you probably want is a Value Converter that handles locating the StaticResource for you. Full Microsoft Documentation here.
On your XAML element, you'd do something like this:
<Entry Style="{Binding foo, Converter={StaticResource FooToStyleConverter}}"/>
Your converter would work something like this:
public class FooToStyleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var someValue = (string)value; // Convert 'object' to whatever type you are expecting
// evaluate the converted value
if (someValue != null && someValue == "bar")
return (Style)App.Current.Resources["StyleOne"]; // return the desired style
return (Style)App.Current.Resources["StyleTwo"];
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// Usually unused, but inverse the above logic if needed
throw new NotImplementedException();
}
}
Lastly, set up your converter as a Static Resource in App.xaml (or as a local resource on the page) so your page can properly reference it
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos">
<ContentPage.Resources>
<ResourceDictionary>
<local:FooToStyleConverter x:Key="FooToStyleConverter" />
....

Adding additional string to {x:Bind} in XAML Universal Windows Platform

I am new to XAML. I would like to add additional string to x:bind
I have tried
<AppBarToggleButton Icon="Phone" Label="E-Mail To {x:Bind e_mail}" />
<AppBarToggleButton Icon="Phone" Label="{"E-Mail To" + x:Bind e_mail}" />
I would like to get "E-Mail to email#email.com"
But no success. Thanks for help.
Create a converter for this:
public sealed class StringFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
return null;
if (parameter == null)
return value;
return string.Format(parameter.ToString(), value);
}
public object ConvertBack(object value, Type targetType, object parameter,
string language)
{
throw new NotImplementedException();
}
}
Add this to yor page/control/app resources:
<converters:StringFormatConverter x:Key="StringFormatConverter" />
And then use it like this:
<TextBlock Text="{x:Bind e_mail}"
Converter="{StaticResource StringFormatConverter}"
ConverterParameter="E-Mail To {0}!" />
Instead of creating your own StringFormatConverter you can use the builtin converter from Microsoft:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:converter="using:Microsoft.Toolkit.Uwp.UI.Converters"
mc:Ignorable="d">
<converter:StringFormatConverter x:Key="StringFormatConverter"/>
</ResourceDictionary>
There are also some other useful builtin converters, check them out:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.toolkit.uwp.ui.converters?view=win-comm-toolkit-dotnet-7.0