Binding FontSize Not working Xamarin Forms? - xamarin

XAML:
<Button Text="Submit" FontSize="{Binding BtnFontSize,Mode=Twoway}"/>
ViewModel:
string _btnFontSize;
public string BtnFontSize
{
get { return _saveBtnFontSize; }
set
{
_saveBtnFontSize = value;
OnPropertyChanged();
}
}
while setting first time its works = > BtnFontSize="Large"
after it not working => BtnFontSize="Small"

Do the following changes and it should work:
Remove two-way binding as it is not needed
<Button Text="Submit" FontSize="{Binding BtnFontSize}"/>
In the OnPropertyChanged method pass the property name
private double _btnFontSize;
public double BtnFontSize
{
get { return _saveBtnFontSize; }
set
{
_saveBtnFontSize = value;
OnPropertyChanged(nameof(BtnFontSize));
}
}
And to get the default xamarin forms label font sizes you will use the NamedSize enum:
which should be something like below for eg to set the size to Medium you will do the following
BtnFontSize= Device.GetNamedSize (NamedSize.Medium, typeof(Label)),
Where typeof(Label) signifies the control you are using so when you need to set button font size you will pass button here

Related

Bind value for "Maximum' property not working on Slider Xamarin

I am trying to use a ViewModel property on Slider Maximum value, but when I use Binding the slider always show the current value as 0.
With fixed values, it works:
<Slider Minimum="0" Maximum="16" Value="{Binding SliderStep, Mode=OneWay}" HorizontalOptions="CenterAndExpand" />
But the Maximum value is variable, so I need to Bind it from ViewModel, when I try do it something goes wrong:
<Slider Minimum="0" Maximum="{Binding SliderMax}" Value="{Binding SliderStep, Mode=OneWay}" HorizontalOptions="CenterAndExpand" />
ViewModel Piece Code:
double sliderStep;
public double SliderStep
{
get
{
return sliderStep;
}
set { sliderStep = value;
OnPropertyChanged("SliderStep");
}
}
double sliderMax;
public double SliderMax
{
get
{
return sliderMax;
}
set {
sliderMax = value;
OnPropertyChanged();
}
}
public SectionGraphicViewModel(INavigation navigation)
{
this.Navigation = navigation;
sectionRep = new SectionRepository();
this.Sections = sectionRep.GetSections().ToList();
Items = new List<SectionGraphicModel>();
foreach (var item in this.Sections)
{
var SectionView = new SectionModel(item);
Items.Add(new SectionGraphicModel(){ Source = SectionView.CachedImageUsed.Source, Desc = SectionView.Desc, Id = SectionView.Id });
}
SliderMax = items.Count();
if (sectionId.HasValue)
{
SliderStep = items.FindIndex(x => x.Id == sectionId);
}
else
{
SliderStep = 0;
}
}
The Maximum value on this example is 16, I tested with different values and the result is the same.
I tested only on Android simulator. I don't know if it happens on iOS.
PS: Just to avoid misunderstanding, I need to make the Maximum property Bind a value from VM, and OneWay, the control will be disabled from UI, just showing the value from VM.
You should set properties in an order that ensures that Maximum is always greater than Minimum, Maximum should be set before Minimum in xaml:
<Slider BackgroundColor="Aquamarine" Maximum="{Binding SliderMax}" Minimum="0" Value="{Binding SliderStep}" IsEnabled="False" VerticalOptions="EndAndExpand" ></Slider>
If you want to disable the UI, set:
IsEnabled="False"
Refer: slider#precautions
I did not read the question correctly. The issue is just binding mode
Value="{Binding SliderStep, Mode=TwoWay}
This should do it.
PS: Whenever you upload a sample repo remove all your bin/obj files from all shared and target projects. Your project is less than 2 MB but the zip I downloaded because of bin/obj was 50+ MB.

What is the property in control to be set to get the value from AppResult.Text in Xamarin.UITest?

I am trying to create custom control in Xamarin.Forms which has the unique id for automation. So, i have set the android renderer's contentDescription property. So, i can get the AppResult.Label property to identify the control. But, my requirements is that how to get the control's text property? What property i have to set in control level with the corresponding text to get it in AppResult.Text property.
[Test]
[Description("SampleTest")]
public void WelcomeTextIsDisplayed()
{
App.Repl();
AppResult[] results = App.WaitForElement("myControl");
Assert.IsTrue(results[0].Text == "My Control Text", results[0].Text + "\n" + results[0].Description + "\n" + results[0].Id + "\n" + results[0].Label);
}
For more information, I have prepared the simple example to explain better about my case. Here, i have derived my custom control from Grid and i introduced the Text property. When i try to view the element using Repl() method, it does not show the Text property but it shows the text properties for Label & Entry controls.
<StackLayout >
<Label Text="Hello, Custom Renderer!" />
<local:MyEntry Text="In Shared Code" AutomationId="myEntry" />
<local1:CustomView Text="Sample" BackgroundColor="Red" HeightRequest="500" AutomationId="customControl" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"/>
</StackLayout>
public class CustomView : Grid
{
public CustomView()
{
}
public static readonly BindableProperty TextProperty = BindableProperty.Create("Text", typeof(string), typeof(string),string.Empty);
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
Result while calling App.Repl() ,
I'm not sure how different Xamarin.Forms are to Xamarin.Android (which is mostly what my experience is in.)
What happens if you try
app.Query(c => c.Id("NoResourceEntry-2").Property("Text")).SingleOrDefault();
or some variation of the above? Can you then do something with this? I Hope this helps or points you in the right direction.
Try to use with index position like this:
app.Query(c=>c.Id("NoResourceEntry-2"))[0].Text
similarly you can use class for same:
app.Query(c=>c.Class("LabelRenderer"))[0].Text
Query for Class("LabelRenderer") gave 2 results. So in above example, you can see it gave you 2 results but you have to use index for particular result.

How can I make a template binding that accepts a string for a color?

I am using a template like this:
    
<template:ButtonTemplate ButtonType="2" Grid.Column="0" Text="{Binding FBtnText}"
     LabelTextColor="{Binding FBtnLabelTextColor, Converter={StaticResource StringToColorConverter}"
     TapCommand="{Binding FBtnCmd }" />
So the value of the color is entered as "#FF0000" and the converter then converts this into a color.
Is there a way that I could do this conversion in the binding itself so that I would not need to use the StringToColor converter?
Here's my binding that I am using right now:
public static readonly BindableProperty LabelTextColorProperty =
            BindableProperty.Create(
                nameof(LabelTextColor),
                typeof(Color),
                typeof(ButtonTemplate),
                Color.FromHex("C9C9C9"));
public Color LabelTextColor
{
get { return (Color)GetValue(LabelTextColorProperty); }
    set { SetValue(LabelTextColorProperty, value); }
}
You don't need to use a Converter, Xamarin Forms accepts by default a string as a Color, you just have to use like this: "#XXXXXX". You could just pass "#FF0000" and it would be accepted.

Change Label Value on button click in Xamarin MVVM

I'm facing an issue in Xamarin forms Mvvm. I have 2 different layouts say Layout1 and Layout2 which are bounded with a common ViewModel. Layout1 contains multiple Labels which I'm generating dynamically using for loop in xaml.cs file and bind each Label'sTextProperty using SetBinding. Layout2 contain a button.
Now I want to change Text of a particular Label when button clicked.
Layout1.xaml
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Layout1">
<StackLayout x:Name="ParentStack">
// dynamic Labels to be added here..
</StackLayout>
</StackLayout>
Layout1.xaml.cs
public partial class Layout1: StackLayout
{
public Label dummyLabel;
public Layout1()
{
InitializeComponent();
for (int i = 0; i < 3; i++)
{
dummyLabel= new Label
{
Text = " ",
};
dummyLabel.SetBinding (Label.TextProperty,"PhaseValue");
parentRowCells.Children.Add(dummyLabel);
var tapGestureRecognizer_1 = new TapGestureRecognizer();
tapGestureRecognizer_1.SetBinding(TapGestureRecognizer.CommandProperty,"LabelClicked");
tapGestureRecognizer_1.CommandParameter = dummyLabel;
dummyLabel.GestureRecognizers.Add(tapGestureRecognizer_1);
}
}
}
Layout2.Xaml
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Layout2">
<StackLayout x:Name="ParentStack">
<Button Command={Binding ButtonClickedCommand} Text="Click Me" />
</StackLayout>
</StackLayout>
ViewModel.cs
class ViewModel
{
public Label label = new Label();
public string textstring = "new text string";
ICommand _labelClicked;
public ICommand LabelClicked
{
get
{
this._labelClicked= this._labelClicked?? new Command(s =>
{
label = s as Label;
label.Text = "new text"; //this change the text of particular label when clicked but i need it from button clicked event from another layout.
// here I'm getting the instance of label which i clicked on label.
});
return this._labelClicked;
}
}
public ICommand ButtonClickedCommand{ protected set; get; }
public ViewModel()
{
this.ButtonClickCommand = new Command<Button>((key) =>
{
//here I want to change the value of label when button command is clicked.
aa.Text = "this is not changing the text";
});
}
}
Any help in this or do I need to follow some other pattern..??
My first thought would be to add each Label that you add to a List<Label> somewhere that you can access from both layouts... your View Model would seem like the logical place. Then when you click your button, you can find the particular Label whose text you want to change and change it. You will likely then have to reload your list.
However I think that a better way would be to use a ListView instead of a StackLayout. Then you can have an ItemTemplate for the ListView that includes one Label. You can then set up an ObservableCollection<T> of objects to use as the ListView.ItemsSource. You would want to make some custom object that has a Text property, or whatever you want to call the property that will hold the text for the Labels. It is better to use an object for the T in ObservableCollection<T> rather than using ObservableCollection<string> because changes to a string type will not be reflected in the ListView item, but changes to a property of an object (assuming of course that you make it a Bindable Property) will be reflected in those controls that are bound to that property. So in a nutshell, something like (in your ViewModel):
// Class level variable
ObservableCollection<CustomType> dummyLabelContents;
// then either in the ViewModel constructor or somewhere else:
dummyLabelContents = new ObservableCollection<CustomType>();
CustomType dummyText;
for (int i = 0; i < 3; i++)
{
dummyText = new CustomType
{
Text = " ",
};
}
dummyLabelContents.Add(dummyText);
And your CustomType would just be a simple class with only a BindableProperty called Text.
Set up like this, you can assign your ListView.ItemsSource to be the dummyLabelContents ObservableCollection and then whenever you add an item to the ObservableCollection, the ListView will update automatically. Also, since using a custom type with a bindable text property in the ObservableCollection, when that text property is changed the item in the ListView should also update accordingly.

Using ListPicker and DataBinding

Ok. I give up.
I want to use ListPicker control in one of my Windows Phone apps. I am getting an Exception SelectedItem must always be set to a valid value.
This is my XAML piece of ListPicker:
<toolkit:ListPicker x:Name="CategoryPicker"
FullModeItemTemplate="{StaticResource CategoryPickerFullModeItemTemplate}"
Margin="12,0,0,0"
ItemsSource="{Binding CategoryList}"
SelectedItem="{Binding SelectedCategory, Mode=TwoWay}"
ExpansionMode="ExpansionAllowed"
FullModeHeader="Pick Categories"
CacheMode="BitmapCache"
Width="420"
HorizontalAlignment="Left" />
CategoryList is an ObservableCollection<Category> in my ViewModel.
SelectedCategory is a property in my ViewModel of type Category.
This is how I am declaring both CategoryList and SelectedCategory:
private Category _selectedCategory;// = new Category();
private ObservableCollection<Category> _categoryList = new ObservableCollection<Category>();
public ObservableCollection<Category> CategoryList
{
get
{
return _categoryList;
}
set
{
_categoryList = value;
RaisePropertyChanged("CategoryList");
}
}
public Category SelectedCategory
{
get
{
return _selectedCategory;
}
set
{
if (_selectedCategory == value)
{
return;
}
_selectedCategory = value;
RaisePropertyChanged("SelectedCategory");
}
}
Appreciate your help!!! Maybe I have not understood the usage of ListPicker very well.
I'd expect the object returned by SelectedCategory to be one of the objects from the CategoryList collection. In your example you are instanciating it within the get, so this is definitely not the case.
If CategoryList contains some values, then perhaps initialize _selectedCategory to null, and then in the get
if(_selectedCategory == null) {
_selectedCategory = CategoryList.First();
}
Take a look at my answer to this question:
Silverlight ComboBox binding with value converter
The short answer is that the selected item must be an item that is contained within the collection. Your getter is setting the selected item to a new object. This new object is not contained within the collection

Resources