I'm learning Xamarin Data Binding and learning the below code:
<?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:DataBinding"
x:Class="DataBinding.MainPage">
<StackLayout>
<Label x:Name="label" Text="twisting" FontSize="70" HorizontalOptions="Center" VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value}">
</Label>
<Slider x:Name="slider" BackgroundColor="Yellow" Maximum="360" VerticalOptions="CenterAndExpand">
</Slider>
</StackLayout>
</ContentPage>
I want to double the twisting speed so I modify the code:
<Label x:Name="label" Text="twisting" FontSize="70"
HorizontalOptions="Center" VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value*2}">
</Label>
But it doesn't work at all. I know the below solution works but I want a solution relating to the above:
<Slider x:Name="slider" BackgroundColor="Yellow" Maximum="720" VerticalOptions="CenterAndExpand">
</Slider>
How to do it?
UPDATE1
I customize a converter as the below code:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Xamarin.Forms;
namespace DataBinding
{
public class MyValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var speed = value as int?;
return speed * 2;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}
and modify the xaml as the below:
<?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:DataBinding"
x:Class="DataBinding.MainPage">
<StackLayout>
<Label x:Name="label" Text="twisting" FontSize="70" HorizontalOptions="Center" VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path, Converter={StaticResource myCo
nverter}}">
</Label>
<Slider x:Name="slider" BackgroundColor="Yellow" Maximum="360" VerticalOptions="CenterAndExpand">
</Slider>
</StackLayout>
<ContentPage.Resources>
<ResourceDictionary>
<local:MyValueConverter x:Key="myConverter"></local:MyValueConverter>
</ResourceDictionary>
</ContentPage.Resources>
</ContentPage>
But my converter doesn't work properly and what is more, I made a breakpoint and found that the Convert function even not getting triggered.
UPDATE2
I found out the reason, the label in XAML should be the below:
<Label x:Name="label" Text="twisting" FontSize="70" HorizontalOptions="Center" VerticalOptions="CenterAndExpand"
BindingContext="{x:Reference Name=slider}"
Rotation="{Binding Path=Value, Converter={StaticResource myConverter}}">
</Label>
and the type of value inside the Convert function is double instead of string:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var tmp = (Double)value*2;
return tmp;
}
Then it works.
Related
I made a frame on Android Xamarin.Forms using an absoluteLayOut! My goal is to set little space from the device width! But when I try it on two device there was total reduction from the height and and width of the frame..
https://i.stack.imgur.com/8kjzD.jpg
<AbsoluteLayout>
<Frame AbsoluteLayout.LayoutBounds="0.5,0.5,310,340" AbsoluteLayout.LayoutFlags="PositionProportional" CornerRadius="15" Padding="0">
<AbsoluteLayout BackgroundColor="Black">
<Label Text="mos.Softs" FontAttributes="Bold" FontSize="16" TextColor="Wheat"
AbsoluteLayout.LayoutBounds="0.5,0.011" AbsoluteLayout.LayoutFlags="PositionProportional"></Label>
<Label x:Name="lblWidth" FontAttributes="Bold" FontSize="16" TextColor="Wheat"
AbsoluteLayout.LayoutBounds="0.5,0.5" AbsoluteLayout.LayoutFlags="PositionProportional"></Label>
<Button Padding="0" CornerRadius="5" Text="Click me" TextTransform="None"
AbsoluteLayout.LayoutBounds="0.5,0.98, 100,40" AbsoluteLayout.LayoutFlags="PositionProportional"></Button>
</AbsoluteLayout>
</Frame>
</AbsoluteLayout>
You could use the converter to fit the size instead of AbsoluteLayout.
Set the name to your Frame first.
<Frame
…………
x:Name="frame"/>
Create the MyConverter: MyConverter.cs
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value / 3.0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Set the StaticResource:
<ContentPage.Resources>
<ResourceDictionary>
<local:MyConverter x:Key="MyConverter" />
</ResourceDictionary>
</ContentPage.Resources>
Binding for the frame value:
<Frame x:Name="frame" >
<StackLayout BackgroundColor="Gray" VerticalOptions="CenterAndExpand" WidthRequest="{Binding Source={x:Reference frame},Path=Width,Converter={StaticResource MyConverter}}"
HeightRequest="{Binding Source={x:Reference frame},Path=Height,Converter={StaticResource MyConverter}}" >
<Label Text="mos.Softs" FontAttributes="Bold" FontSize="16" TextColor="Wheat"
HorizontalOptions="CenterAndExpand" VerticalOptions="StartAndExpand" ></Label>
<Label Text="Device Height" x:Name="lblWidth" FontAttributes="Bold" FontSize="16" TextColor="Wheat"
HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"></Label>
<Button Padding="0" CornerRadius="5" Text="Click me" TextTransform="None"
HorizontalOptions="CenterAndExpand" VerticalOptions="EndAndExpand" ></Button>
</StackLayout>
</Frame>
I have to create a frame like in the attached photo ,the thing is that it has to be adaptable as it will contain labels/texts , also it should have elevation and shadow .
All that is easily doable with a frame , the problem is the little speech thing , i can't find a way to make it .
maybe someone has an idea to start with .
thanks
You can binding the Height and Width of the frame with its child element (like label).
in code behind
public class SizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((double)value + 20.0); // you can set the logic of height and width here
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return 0;
}
}
in xaml
<ContentPage.Resources>
<ResourceDictionary>
<local:SizeConverter x:Key="SizeConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Frame CornerRadius="10" WidthRequest="{Binding Source={x:Reference contentLabel}, Path=Width,Converter={StaticResource SizeConverter} ,Mode=OneWay}" MinimumHeightRequest="100" HeightRequest="{Binding Source={x:Reference contentLabel}, Path=Height,Converter={StaticResource SizeConverter} ,Mode=OneWay}" BackgroundColor="LightBlue" Padding="10" >
<!-- Place new controls here -->
<Label x:Name="contentLabel" BackgroundColor="LightGray" Text="xxx"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</Frame>
</StackLayout>
In my content page (XAML), let's say I have this:
<StackLayout>
<Entry x:Name="courseScore" Placeholder="Course Score" Keyboard="Numeric" />
<Entry x:Name="courseGrade" Placeholder="Course Grade" Keyboard="Text" IsReadOnly="True" />
</StackLayout>
How do I create event handler (example, onKeyup) for courseScore? I want to auto populate course grade based on course score from code behind?
Solution provided by Lucas:
<?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:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Xamarin_SQLite.AppFunctions"
mc:Ignorable="d"
x:Class="Xamarin_SQLite.Views.StudentCourseResult_Add">
<ContentPage.Resources>
<ResourceDictionary>
<local:ScoreConverter x:Key="ScoreConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<Picker Title="Select a course" x:Name="courseName">
<Picker.Items>
<x:String>Web Design</x:String>
<x:String>Database Design</x:String>
<x:String>Web Programming</x:String>
</Picker.Items>
</Picker>
<Entry x:Name="courseScore" Placeholder="Course Score" Keyboard="Numeric" />
<Entry x:Name="courseGrade" Placeholder="Course Grade" Keyboard="Text" IsReadOnly="True" />
<Button x:Name="btnAdd" Clicked="btnAdd_Clicked" Text="Add"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
You can implement it by using Converter .
using System;
using System.Globalization;
using Xamarin.Forms;
namespace xxxx
{
public class ScoreConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value!=null&& value.ToString().Length!=0)
{
int score = int.Parse(value.ToString());
if (score < 60)
{
return "E";
}
else if (score >= 60 && score < 70)
{
return "D";
}
else if (score >= 70 && score < 80)
{
return "C";
}
else if (score >= 80 && score < 90)
{
return "B";
}
else
{
return "A";
}
}
return "";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return "";
}
}
}
in xaml
<ContentPage.Resources>
<ResourceDictionary>
<local:ScoreConverter x:Key="ScoreConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Entry x:Name="courseScore" Placeholder="Course Score" Keyboard="Numeric" />
<Entry x:Name="courseGrade" Placeholder="Course Grade" Keyboard="Text" IsReadOnly="True" Text="{Binding Source={x:Reference courseScore}, Path=Text,Converter={StaticResource ScoreConverter} ,Mode=OneWay}"/>
</StackLayout>
Here is the method that I have come up with so far. However it seems like not such a clean solution.
Does anyone have any suggestions how I could come up with a better solution for doing this?
<?xml version="1.0" encoding="utf-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Japanese;assembly=Japanese"
x:Class="Japanese.Templates.HeaderTemplate"
x:Name="this" HorizontalOptions="FillAndExpand" Orientation="Vertical" Spacing="0" Margin="0">
<StackLayout IsVisible="{Binding HeaderType, Converter={StaticResource HeaderType1BoolConverter}, Source={x:Reference this} }" >
<!-- code -->
</StackLayout>
<StackLayout IsVisible="{Binding HeaderType, Converter={StaticResource HeaderType2BoolConverter}, Source={x:Reference this} }" >
<!-- code -->
</StackLayout>
</StackLayout>
In my bank end CS:
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace Japanese.Templates
{
public partial class HeaderTemplate : StackLayout
{
public HeaderTemplate()
{
InitializeComponent();
}
public static readonly BindableProperty HeaderTypeProperty =
BindableProperty.Create(
nameof(HeaderType),
typeof(string),
typeof(DataViewCellTemplate),
default(string));
public string HeaderType
{
get { return (string)GetValue(HeaderTypeProperty); }
set { SetValue(HeaderTypeProperty, value); }
}
}
}
Converter Code:
public class HeaderType1BoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return object.Equals(value, "1");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class HeaderType2BoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return object.Equals(value, "2");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
In the calling code:
<template:HeaderTemplate Header="Application" HeaderType="1" />
Using triggers is an option.
For e.g.: You can add property-triggers to check the value on HeaderType and accordingly update the Content (or layout) in your custom control HeaderView.
Please note in this case we are extending from ContentView not StackLayout on the assumption that only one layout/control is visible at a time.
XAML
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:SampleApp"
x:Class="SampleApp.HeaderView">
<ContentView.Triggers>
<!-- if header type is 1, use header1 layout -->
<Trigger TargetType="local:HeaderView" Property="HeaderType" Value="1">
<Setter Property="Content">
<Setter.Value>
<Label Text="Header1" />
</Setter.Value>
</Setter>
</Trigger>
<!-- if header type is 2, use header2 layout -->
<Trigger TargetType="local:HeaderView" Property="HeaderType" Value="2">
<Setter Property="Content">
<Setter.Value>
<StackLayout>
<Label Text="Header2" />
<BoxView HeightRequest="1" BackgroundColor="Gray" />
</StackLayout>
</Setter.Value>
</Setter>
</Trigger>
<!-- you can add more layouts here if you need -->
</ContentView.Triggers>
<!-- add default content that can be displayed in case of no match -->
<StackLayout>
<Label Text="DefaultHeader" />
<BoxView HeightRequest="1" BackgroundColor="Gray" />
</StackLayout>
</ContentView>
Code-behind
public partial class HeaderView : ContentView
{
public HeaderView()
{
InitializeComponent();
}
public static readonly BindableProperty HeaderTypeProperty =
BindableProperty.Create(
nameof(HeaderType), typeof(string), typeof(HeaderView),
defaultValue: default(string));
public string HeaderType
{
get { return (string)GetValue(HeaderTypeProperty); }
set { SetValue(HeaderTypeProperty, value); }
}
}
Usage
<local:HeaderView HeaderType="1" />
I believe that what you are looking is a ControlTemplate here is an implementation.
App.xaml
<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleTheme.App">
<Application.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="Header1Template">
<StackLayout>
<!-- code -->
</StackLayout>
</ControlTemplate>
<ControlTemplate x:Key="Header2Template">
<StackLayout>
<!-- code -->
</StackLayout>
</ControlTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
Usage (This will make header1 your default, you can pick any of the both)
<ContentView x:Name="contentView" ControlTemplate="{StaticResource Header1Template}">
Now there are many ways to change the header, either by defining as the default code above or with an action which can be a button click like the example given on the link or with a propertyChange event, if you want to depend on a property to choose the header like:
public int HeaderNumber { get; set; }
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == "HeaderNumber")
{
contentView.ControlTemplate = (HeaderNumber == 1) ? Header1Template : Header2Template;
}
}
Note that i never implemented a ControlTemplate but i think this solves your problem.
Hi everyone I'm developing a xamarin app and I have a problem.
I have the next code in xaml:
<ListView x:Name="listName">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical">
<Image Source="{Binding imageName}"></Image>
<Label Text="{Binding name}" TextColor="Black"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I need to change the image source property adding a string. For example:
<Image Source="{Binding imageName} + mystring.png"></Image>
<Image Source="{Binding imageName + mystring.png}"></Image>
Can I do this in xaml?
any idea? is possible?
You could use a converter to do this.
public class ImagePostfixValueConverter
: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var path = value as string;
var postfix = parameter as string;
if (string.IsNullOrEmpty(postfix) || string.IsNullOrEmpty(path))
return value;
return path + postfix;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then on your page add:
<ContentPage.Resources>
<ResourceDictionary>
<local:ImagePostfixValueConverter x:Key="PostfixConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
And then in your binding:
<Image Source="{Binding imageName, Converter={StaticResouce PostfixConverter}, ConverterParameter=mystring.png}"></Image>
You could do this in a much simpler way:
<Image Source="{Binding imageName, StringFormat='{0}mystring.png'}"></Image>