Truncate the label text makes it one line. App shows description, it needs to be displayed in 2-3 lines but Xamarin "LineBreakMode=TailTruncation" truncates it and restricts it to one line.
Is there any way to truncate label text and show in multi-lines. If text doesn't fit into n number of lines, then it should be truncated.
<Label LineBreakMode="TailTruncation" FontSize = "20" Text="Multi line Text" />
Thanks.
Since Xamarin.Forms 3.3 a new property was introduced for this feature. It's called MaxLines.
Here is an example in C#:
var yourLabel = new Label
{
LineBreakMode = LineBreakMode.TailTruncation,
Text = "Your text",
MaxLines = 2
};
Here is an example in XAML:
<Label
LineBreakMode="TailTruncation"
Text="Your text"
MaxLines="2" />
See https://learn.microsoft.com/de-de/dotnet/api/xamarin.forms.label.maxlines?view=xamarin-forms for more information.
I have implemented custom renderer to handle this.
http://depblog.weblogs.us/2016/06/27/xamarin-forms-multi-line-label-custom-renderer-gotcha/
//Droid
public class MultiLineLabelRenderer : LabelRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.LayoutChange += (s, args) =>
{
Control.Ellipsize = TextUtils.TruncateAt.End;
Control.SetMaxLines(2);
}
};
}
}
Related
Im creating an App where I want have multiple icons in my titlebar (they should be clickable). One Icon should be on the Left of the title text like so (this icon is static and will not change):
The other Icons should be on the right (these icons should be dynamic, as they will be used to alert the user if anything important happens):
I'm using a simple shell, so no Navigationpage, thus I don't think <NavigationPage.Titleview> can be used in this case. Is there any way to achieve something like this in Maui?
You can use the shell title view as stated in this answer, it is pointing to Xamarin documentation but it is also valid for MAUI.
In your case you will have something like this inside your AppShell.xaml :
<Shell.TitleView>
<Grid ColumnDefinitions="auto,*,auto">
<Label Text="Title" BackgroundColor="Red"></Label>
<HorizontalStackLayout Grid.Column="2">
<Label Text="Icon" BackgroundColor="Red"></Label>
</HorizontalStackLayout>
</Grid>
</Shell.TitleView>
Which look like this (very trendy design) :
How to update the icons can be done by data binding or creating directly the object from C# :
<HorizontalStackLayout Grid.Column="2" x:Name="IconsContainer">
<Label Text="Icon" BackgroundColor="Red" IsVisible="{Binding Icon1Visible}"></Label>
</HorizontalStackLayout>
And in the C# :
public partial class AppShell : Shell
{
public bool Icon1Visible { get; set; } = false;
public AppShell()
{
InitializeComponent();
// An object containing the binding data
BindingContext = this;
// Directly create a new icon
AddIcon();
// Show an icon through binding
ShowIcon();
}
public void ShowIcon()
{
Icon1Visible = true;
}
public void AddIcon()
{
var icon = new Label();
icon.Text = "And another one";
IconsContainer.Children.Add(icon);
}
}
To get whenever you want to update the icons I would go with dependency injection and either pass directly a view model to bind the icons on or using events.
I really don't know how to get control dimensions in Xamarin Forms. I thought it would be as easy as:
View control = GetControlSomehow();
var bounds = control.Bounds;
But View.Bounds returns different things depending on wether the control is inside a grid or not; or wether the main layout is AbsoluteLayout or some other one.
For example if I do something like:
<AbsoluteLayout>
<Button AbsoluteLayout.LayoutBounds="200,200" x:Name="btn" Text="Btn"/>
</AbsoluteLayout>
then I am not able to read actual height or width of that button. Although MSDN says that Height & Width properties should return these values.
I tried even:
var width = ctrl.Width;
or
var width = ctrl.GetValue(WidthProperty);
But really non of these worked. I always get -1
So how can I get the control dimensions that could be reliable?
Complete example showing how to pass button itself, using data binding.
AbsoluteLayoutPage.xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TestBugs.AbsoluteLayoutPage">
<ContentPage.Content>
<AbsoluteLayout>
<Button AbsoluteLayout.LayoutBounds="200,200" x:Name="btn" Text="Btn"
Command="{Binding ButtonCommand}" CommandParameter="{x:Reference btn}"/>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>
AbsoluteLayoutPage.xaml.cs:
using System.Diagnostics;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace TestBugs
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AbsoluteLayoutPage : ContentPage
{
public AbsoluteLayoutPage()
{
ButtonCommand = new Command(ButtonClick);
InitializeComponent();
BindingContext = this;
}
private void ButtonClick(object ob)
{
var button = ob as View;
var bounds = btn.Bounds;
var width = btn.Width;
var height = btn.Height;
Debug.WriteLine($"--- ButtonClick {bounds}, ({width},{height})---");
}
public Command ButtonCommand { get; set; }
}
}
When click button, in VS Output pane:
[0:] --- ButtonClick {X=200 Y=200 Width=88 Height=48}, (88,48)---
this works for me
<Button Text="Click" Clicked="Clicked" />
public void Clicked(object sender, EventArgs a)
{
var btn = (Button)sender;
var w = btn.Width;
var h = btn.Height;
DisplayAlert("Dimesions", $"{w}x{h}","OK");
}
Sorry guys, my bad.
I was testing it on two pages - the real one and the test one. The test page is built in a different way and I confirm that the problem was in time when I retrieved these values. Control wasn't painted yet.
So I am really sorry to bother you and thank you all for investing your time into this.
I am trying to create a Trivia App. I have some very basic Xamarin Form code implementing a Radio Button. The buttons work fine (ie a selection is registered and processed properly). The issue is that after the first question is answered, the radio button selection persists when the second question is displayed. Is there a way to reset the radio buttons between questions so that they are all not selected?
Here is the basic xaml code and the code behind:
Xaml:
<StackLayout Margin="20">
<RadioButton x:Name="Option0" CheckedChanged="RadioButton_CheckedChanged" IsTabStop="False" IsChecked="False"></RadioButton>
<RadioButton x:Name="Option1" CheckedChanged="RadioButton_CheckedChanged" IsTabStop="False" IsChecked="False"></RadioButton>
<RadioButton x:Name="Option2" CheckedChanged="RadioButton_CheckedChanged" IsTabStop="False" IsChecked="False"></RadioButton>
<RadioButton x:Name="Option3" CheckedChanged="RadioButton_CheckedChanged" IsTabStop="False" IsChecked="False"></RadioButton>
</StackLayout>
Code behind: (Note: getQuestion() has the logic to display the next question so I have not included it here and I suspect something needs to be done at // do something to reset the radio button but I am not sure what to do)
void RadioButton_CheckedChanged(System.Object sender, Xamarin.Forms.CheckedChangedEventArgs e) // sender is of class System.Object and must be converted in the proper type
{
Debug.WriteLine("\nRadio Button Clicked");
Debug.WriteLine("sender: " + sender);
Debug.WriteLine("e: " + e);
var s = sender;
var radioEvent = e;
// converts sender to Radio Button type
var radioButton = (RadioButton)sender;
// Once in Radio Button type now you can see and use content
string contentString = radioButton.Content.ToString();
Debug.WriteLine("contentString: " + contentString);
if (radioButton.IsChecked == true)
{
if (contentString == Movie.Text)
{
DisplayAlert("Correct", "You're Good!", "OK");
Debug.WriteLine("Correct Answer");
ans_correct = ans_correct + 1;
// do something to reset the radio button
getQuestion();
}
else
{
DisplayAlert("Whoops", "Wrong Agian!", "OK");
Debug.WriteLine("Wrong Answer");
ans_wrong = ans_wrong + 1;
}
}
}
Never mind - I guess I just had to post the question to find the answer.
It turns out all I needed to do was put
radioButton.IsChecked = false;
where I had my comment
// do something to reset the radio button
i have a page where user can swap labels. So I have a ExtendedWebView CZ and ExtendedWebView EN once user presses button i need them to swap. I have decided to swap these ExtendedWebView in the bac of my page as that seemed much easier however both these commes with button that each fires different pop up. So if i swap ExtendedWebView CZ i need the button that fires CZ pop up to be swapped also.
This is how i am changing my ExtendedWebViews
bool isSwap = false;
private void ChangePosition(object sender, EventArgs e)
{
isSwap = !isSwap;
czView.RemoveBinding(ExtendedWebView.SourceProperty);
enView.RemoveBinding(ExtendedWebView.SourceProperty);
if (isSwap)
{
btnChangePositions.Text = "EN/CZ";
czView.SetBinding(ExtendedWebView.SourceProperty,("EN"));
enView.SetBinding(ExtendedWebView.SourceProperty, ("CZ"));
}
else
{
btnChangePositions.Text = "CZ/EN";
czView.SetBinding(ExtendedWebView.SourceProperty, ("CZ"));
enView.SetBinding(ExtendedWebView.SourceProperty, ("EN"));
}
}
Xaml
<Label
x:Name="makeLargerEN"
FontFamily="{StaticResource IconsFontFamily}"
HorizontalTextAlignment="End"
Text="{Binding MakeLargerEN}"
TextColor="{DynamicResource AccentColor}"
VerticalTextAlignment="End">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding MakeWebViewLargeEnCommand}" />
</Label>
And this is my pop up in the vIew Model
private async void MakeWebViewLargeEN()
{
var popup = new WordAndPhrasePopup(htmlSourceName.Html);
await PopupNavigation.Instance.PushAsync(popup);
}
I have tried in back of the content page
makeLargerEN.SetBinding(Label.TextProperty, "MakeLargerEN");
Just to swap labels but then the right command doesnt get fired
I have tried this, but gesture doesnt have Command or CommandProperty
makeLargerCZ.SetBinding(GestureRecognizer.Command, new Binding("MakeLargerEN"));
I am doing it in the back of COntent page because i am setting up there another swap that goes along with this one.
You could remove and add GestureRecognize in code behind .
Remove
makeLargerEN.GestureRecognizers.Clear();
Add
makeLargerEN.GestureRecognizers.Add(new TapGestureRecognizer
{
NumberOfTapsRequired = 1,
Command = new Command(() =>
{
//...
}),
});
I have to create a form in which the user must input his age. I would like to use a numeric keyboard:
<Entry
x:Name="AgeEntry"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
Keyboard="Numeric"
/>
but it shows even the decimal point character, I'd like to show only numbers...
To restrict the Entry to only accept numbers you could use a Behavior or a Trigger.
Both of those will react to a user typing into them. So for your use, you could have the trigger or behavior look for any characters that are not numbers and remove them.
Something like this for a behavior (note that I wrote all this on SO and did not try compiling it, let me know if it does not work):
using System.Linq;
using Xamarin.Forms;
namespace MyApp {
public class NumericValidationBehavior : Behavior<Entry> {
protected override void OnAttachedTo(Entry entry) {
entry.TextChanged += OnEntryTextChanged;
base.OnAttachedTo(entry);
}
protected override void OnDetachingFrom(Entry entry) {
entry.TextChanged -= OnEntryTextChanged;
base.OnDetachingFrom(entry);
}
private static void OnEntryTextChanged(object sender, TextChangedEventArgs args)
{
if(!string.IsNullOrWhiteSpace(args.NewTextValue))
{
bool isValid = args.NewTextValue.ToCharArray().All(x=>char.IsDigit(x)); //Make sure all characters are numbers
((Entry)sender).Text = isValid ? args.NewTextValue : args.NewTextValue.Remove(args.NewTextValue.Length - 1);
}
}
}
}
Then in your XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyApp;assembly=MyApp"> <!-- Add the local namespace so it can be used below, change MyApp to your actual namespace -->
<Entry x:Name="AgeEntry"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
Keyboard="Numeric">
<Entry.Behaviors>
<local:NumericValidationBehavior />
</Entry.Behaviors>
</Entry>
</ContentPage>
To me the simple solution is just to add a TextChanged handle to the Entry (this is UI specific code so does not break MVVM)
<Entry Text="{Binding BoundValue}" Keyboard="Numeric" TextChanged="OnTextChanged"/>
Then in code behind
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
//lets the Entry be empty
if ( string.IsNullOrEmpty(e.NewTextValue) ) return;
if ( !double.TryParse(e.NewTextValue, out double value) )
{
((Entry) sender).Text = e.OldTextValue;
}
}
Change in int.Parse if need an integer
I was facing this too, but the best way to implement this is through behaviors, here is an article which shows you in detail how to implement this and even more, like limiting the value of the number entered to a given value you set in your XAML.
if (!string.IsNullOrWhiteSpace(args.NewTextValue))
{
bool isValid = args.NewTextValue.ToCharArray().All(char.IsDigit);
((Editor)sender).Text = isValid ? args.NewTextValue : args.OldTextValue;
}
This prevents adding any non digit char into the Editor no matter where you added it.
So if your cursor was in the middle of your number and you got for example 21h3 in #hvaughan3's answer you would just remove the last char giving you 21h with the non digit still being present.
My answer will just use the value you had before adding the non digit char (213).
But keep in mind!
If you put this in a behavior and react to editor.TextChanged Event, this is still gonna change the Text for a brief second to the invalid value since this event triggers when it ALREADY was set. this is no OnTextChanging event.
Same for #hvaughan3's answer.
To prevent any issues you might get because of this, for example because you're also listening to OnTextChanged in Code behind, just add this line before working with the new text value
if (!editor.Text.All(char.IsDigit)) return;