Is the Picker Control available in Xamarin bindable? If so, could someone help on how to use it ? I would like to bind a Picker control with data (XAML approach) that comes from a DB.
The bindable Picker is available since 13th January 2017. Currently, it is contained in version 2.3.4.184-pre1.
If you want to use it, you have to install Xamarin.Forms via nuget using the -Pre flag. Or check the Prerelease checkbox in the nuget UI.
Install-Package Xamarin.Forms -Pre
And then, you can just bind your collection to ItemsSource.
<Picker
Title="Select a Color"
ItemsSource="{Binding Colors}" />
Announcement: https://blog.xamarin.com/new-xamarin-forms-pre-release-2-3-4-pre1-quality-improvements-bindable-picker
It will be released as stable not later than February 2017 (according to the Roadmap)
Yes, You can us the Picker control in Xamarin Forms.
Please check this link for the description: https://developer.xamarin.com/api/type/Xamarin.Forms.Picker/
Thank You.
Example #1 :
Use Extendedpicker of xlabs following is link to implement extended picker
Cs code of extended picker
https://github.com/XLabs/Xamarin-Forms-Labs/blob/master/src/Forms/XLabs.Forms/Controls/ExtendedPicker.cs
Implementation in xaml page:-
https://github.com/XLabs/Xamarin-Forms-Labs/blob/7a58dc349f17351813afa24df97ef7fea545a833/samples/XLabs.Samples/XLabs.Samples/Pages/Controls/ExtendedPickerPage.xaml
Example #2:
Try to create own bendable picker refer following link
https://forums.xamarin.com/discussion/30801/xamarin-forms-bindable-picker
Here is the complete solution:
https://hiranpeiris.com/2017/02/24/how-to-add-a-custom-bindable-property-to-xamarin-forms-control/
Create your custom picker class.
using System.Collections.Generic;
using Xamarin.Forms;
namespace FDNet
{
public class OutletPicker : Picker
{
public static readonly BindableProperty ItemSourceProperty = BindableProperty.Create(nameof(ItemSource), typeof(List<string>), typeof(OutletPicker), null);
public List<string> ItemSource
{
get
{
return (List<string>)GetValue(ItemSourceProperty);
}
set
{
SetValue(ItemSourceProperty, value);
}
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == nameof(ItemSource))
{
this.Items.Clear();
if (ItemSource != null)
{
foreach (var item in ItemSource)
{
this.Items.Add(item);
}
}
}
}
}
}
Add XAML reference variable to the Page.
xmlns:local=“clr–namespace:FDNet;assembly=FDNet“
Add the control and bind the property.
<local:OutletPicker Title=“Select“ ItemSource=“{Binding Outlets}“ HorizontalOptions=“Center“ WidthRequest=“300“ />
Now you can see our custom bindable property ItemSource=“{Binding Outlets}“)
Demo.
Outlets = new List<string> { “4G LTE“, “4G Broadband“, “Fiber connection“ };
<local:OutletPicker Title=“Select“ ItemSource=“{Binding Outlets}“ HorizontalOptions=“Center“ WidthRequest=“300“ />
(1)bind picker :
Dictionary dicobj= new Dictionary();
dicobj.Add(1, "abc");
dicobj.Add(2, "xyz");
foreach (var item in dicobj.Values)
{
YorPickerName.Items.Add(item);
}
(2)then get the selected value on SelectedIndexChanged event of picker:
var selval = Service_category.SelectedIndex;
int value = dicobj.ElementAt(selval).Key;
var data = Service_category.Items[selval];
int id = dicval.FirstOrDefault(x => x.Value == data).Key;
Related
I am trying to get my picker to be an wheel/spinning type.
My Current Picker:
<Picker x:Name="AmountPicker" />
AmountPicker.ItemsSource = new List<string>() { "1", "2", "3","4","5","6","7","8" };
My Picker
You have a couple of options.
1. Use Custom Renderers which enables you to achieve the wheel/spinning type. There is a similar thread you could refer to: Apply styles on Picker items in Xamarin Forms.
1.1 Create the Custom Picker Control in Shared Project:
public class MyPicker : Picker
{
}
1.2 Creating the Custom Renderer on Android & iOS:
Android:
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(MyPicker), typeof(MyPickerRenderer))]
namespace App35.Droid
{
class MyPickerRenderer : PickerRenderer
{
public MyPickerRenderer(Context context) : base(context)
{
}
}
}
iOS:
[assembly: ExportRenderer(typeof(MyPicker), typeof(MyPickerRenderer))]
namespace App35.iOS
{
class MyPickerRenderer : PickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
}
}
}
1.3 Consume it in XAML:
<local:MyPicker ItemsSource="{Binding MyListProperty}" ></local:MyPicker>
Output:
2. Use Xamarin.SfPicker. Firstly, install the package and then set SfPicker control namespace as xmlns:syncfusion="clr- namespace:Syncfusion.SfPicker.XForms;assembly=Syncfusion.SfPicker.XForms in XAML Content page. So you can consume it in XAML like below.For more you can refer to Getting Started with Xamarin Picker (SfPicker)
<syncfusion:SfPicker x:Name="picker" HeaderText="Choose Value" />
3. Use Wheel Picker for Xamarin Samples package, you can refer to Wheel Picker for Xamarin Samples for more details.
So I have the following code:
<TabBar Route="Dashboard">
<Tab Title="Dashboard" AutomationId="DashboardId">
//more codes here
</Tab>
<Tab AutomationId="AddNewId">
//more codes here
</Tab>
<Tab Title="Statistics" AutomationId="StatisticsId">
//more codes here
</Tab>
</TabBar>
Note that in my MainActivity's OnCreate() I have set up the following:
Xamarin.Forms.Forms.ViewInitialized += (object sender, Xamarin.Forms.ViewInitializedEventArgs e) => {
if (!string.IsNullOrWhiteSpace(e.View.AutomationId))
{
e.NativeView.ContentDescription = e.View.AutomationId;
}
};
This works perfectly with my other elements except for the TabBar items. Somehow the TabBar items are getting the Title property and setting is at the accessibilityId/content-dec.
Anyone knows why this is and how can I make it so it will get the right AutomationId? Thanks
There are multiple issues with AutomationId on Android.
The underlying problem is discussed in Android - Using AutomationId prevents TalkBack screenreader accessibility:
Xamarin.Forms "borrows" the ContentDescription property on Android for Automation IDs. These IDs polute Android's TalkBack accessibility tree, making apps almost impossible to navigate.
This means you can support test automation or accessibility, not both. Our app needs to support both.
In the case of Tabs, presumably Xamarin code is doing what you see: copying Title to content-desc, so that Android text readers will speak it.
The suggested work-around is to write custom renderer(s) that do what you need. Described in a comment by codingL3gend :
i was able to find a work around to this issue by creating a customrenderer and respective custom component to allow for overriding the native android method(s) that get triggered when accessibility events are fired. you will need to create some bindable properties on your custom component that you can access in the custom renderer to allow for setting the content description value to what you want but that's simple enough.
this method gets triggered in the control/custom renderer whenever an accessibility event is fired
public override bool OnRequestSendAccessibilityEvent(Android.Views.View child, AccessibilityEvent e)
{
if (AccessibilityHandler.IsAccessibilityEnabled(_context) && child != null)
{
if (!string.IsNullOrEmpty(_automationId) && _automationId.Equals(child.ContentDescription))
{
child.ContentDescription = $"{_automationName} {_helpText}";
}
}
return base.OnRequestSendAccessibilityEvent(child, e);
}
then you can set the contentDescription value of the control/custom renderer back to what the automationId value was originally when the control/custom renderer is detached from the view.
protected override void OnDetachedFromWindow()
{
base.OnDetachedFromWindow();
if (!string.IsNullOrEmpty(_automationId))
{
Control.ContentDescription = _automationId;
}
}
helper class
public static class AccessibilityHandler
{
public static bool IsAccessibilityEnabled(Context context)
{
var accessibility = (AccessibilityManager)context.GetSystemService(MainActivity.AccessibilityService);
return accessibility?.GetEnabledAccessibilityServiceList(Android.AccessibilityServices.FeedbackFlags.Spoken)?.Count > 0;
}
}
If you only need AutomationId during testing, or you can live with the effect this has on Accessibility Screen Readers (esp. it won't be multi-lingual), then you could make a much simpler custom renderer for use when testing.
Put this in your custom renderer (if isn't Tab, then change <Tab> to appropriate Xamarin class):
protected override void OnElementChanged( ElementChangedEventArgs<Tab> e )
{
base.OnElementChanged( e );
if (e.OldElement != null)
{
// Removing previous element.
// TBD: Remove obsolete references. (usually not needed)
}
if (Element == null)
// Going away with no replacement.
return;
UpdateAutomationId();
}
void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Element.AutomationId))
{
UpdateAutomationId();
}
}
void UpdateAutomationId()
{
var _automationId = Element.AutomationId;
if (!string.IsNullOrEmpty(_automationId))
{
Control.ContentDescription = _automationId;
}
}
I want to hide navigation bar button in xamarin. how can i do that using binding. Toolbar item doesn't have "IsVisible" property.
Following is my xaml code
please help me to sort out this issue.
I would suggest to build a bindable ToolBoxItem. That way you can control the visibility through a view model property.
An implementation could look like that:
public class BindableToolbarItem : ToolbarItem
{
public static readonly BindableProperty IsVisibleProperty = BindableProperty.Create(nameof(IsVisible), typeof(bool), typeof(BindableToolbarItem), true, BindingMode.TwoWay, propertyChanged: OnIsVisibleChanged);
public bool IsVisible
{
get => (bool)GetValue(IsVisibleProperty);
set => SetValue(IsVisibleProperty, value);
}
private static void OnIsVisibleChanged(BindableObject bindable, object oldvalue, object newvalue)
{
var item = bindable as BindableToolbarItem;
if (item == null || item.Parent == null)
return;
var toolbarItems = ((ContentPage)item.Parent).ToolbarItems;
if ((bool)newvalue && !toolbarItems.Contains(item))
{
Device.BeginInvokeOnMainThread(() => { toolbarItems.Add(item); });
}
else if (!(bool)newvalue && toolbarItems.Contains(item))
{
Device.BeginInvokeOnMainThread(() => { toolbarItems.Remove(item); });
}
}
}
As you have discovered yourself there is not IsVisible. So you will have to implement functionality like that yourself if you still want it.
Another way would be to handle it in the pages' code-behind and remove or add the toolbar item whenever needed.
Adding and removing is simple, just add and remove items to the ToolbarItems collection: ToolbarItems.RemoveAt(0); for instance will remove the first toolbar item.
Putting #Gerald answer in action, it would be done this way:
void Done_Clicked(System.Object sender, System.EventArgs e)
{
//Do somthing and hide the done item
ShowDoneToolbarItem(false, (ToolbarItem)sender);
}
void Entry_Focused(System.Object sender, Xamarin.Forms.FocusEventArgs e)
{
//Show the done item
ShowDoneToolbarItem(true);
}
void ShowDoneToolbarItem(bool show, ToolbarItem item = null)
{
if(show)
{
ToolbarItem done = new ToolbarItem();
done.Text = "Done";
done.Clicked += Done_Clicked;
ToolbarItems.Add(done);
}
else if(item != null)
{
ToolbarItems.Remove(item);
}
}
This is cleaner and works from the code behind.
Well we need the IsVisible property for the front end, as xamarin doesn't have it, you can use Device.RuntimePlatform to check in real time which device the application is running. Since my code is in .cs of the XAML file, we can use xaml .cs to insert items into the screen.I put if () to do the logic and check if my device is on which platform, because I don't want it to display in UWP a toolbar.
The code is in .cs of the XAML file:
public kingTest()
{
InitializeComponent();
if((Device.RuntimePlatform == "Android")||(Device.RuntimePlatform == "iOS"))
{
ToolbarItem toolbar = new ToolbarItem();
toolbar.IconImageSource = "ic_ToolBar.png";
this.ToolbarItems.Add(toolbar);
}
};
I've achieved this easily using overloaded constructors. Here's an example:
View (add the name property):
<ContentPage x:Name="ContentPage"
<!-- rest of the tag -->
/>
Code-behind (add the toolbar items):
public partial class ExamplePage : ContentPage
{
public ExamplePage()
{
InitializeComponent();
BindingContext = this;
var saveToolbarItem = new ToolbarItem { Text = "Save" };
saveToolbarItem.Clicked += YourMethodToBeRan;
ContentPage.ToolbarItems.Add(saveToolbarItem);
}
public ExamplePage(Object object)
{
InitializeComponent();
BindingContext = this;
var updateToolbarItem = new ToolbarItem { Text = "Update" };
updateToolbarItem.Clicked += YourMethodToBeRan;
var deleteToolbarItem = new ToolbarItem { Text = "Delete" };
deleteToolbarItem.Clicked += YourMethodToBeRan;
ContentPage.ToolbarItems.Add(updateToolbarItem);
ContentPage.ToolbarItems.Add(deleteToolbarItem);
}
// rest of the class
}
The above pseudocode will add the "Save" toolbar item when the class is instantiated with no parameter, or the "Update" and "Delete" when a parameter is provided.
This isn't as elegant as IsEnabled / IsVisible booleans but it's a step in the right direction. Following this train of thought, you could modify the children of your toolbar during runtime to "show" and "hide" by adding and removing them as children.
Good luck!
I don't know if #tequila slammer's solution fully worked on Xamarin, but for us it only kind of works in .Net Maui (the evolution of Xamarin) and binding the IsVisible property to a variable.
Once the BindableToolbarItem is removed from the ContentPage's list of ToolbarItems, it is disconnected from the object that IsVisible is bound to forever.
For example: We want to use this control to hide or show a ToolbarItem that navigates to the admin screen, if I log in as the administrator on app launch, the item is there...great. If I then log out and log in as a non-admin, the item is not there...perfect. If I then log out and log in as an admin, the item is not there (the propertyChanged: OnIsVisibleChanged never fired)...:-(.
Not a big deal for us, if you want admin access then stopping the app and starting the app to log in as the admin is not a big ask.
In the newest release with .Net 7 the workaround works never more !
The reason is because the toolbar item which revomed will destoyed !
Is it possible to truncate long texts with ellipsis in a picker control. I have already created a custom renderer to set a fontsize and no border in order to achieve the following result.
Also tried to set Control.Ellipsize = TextUtils.TruncateAt.End; but nothing happens
[assembly: ExportRenderer(typeof(NoBorderPicker), typeof(CustomPicker))]
namespace Prj.Droid.Renderers
{
public class CustomPicker : PickerRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var customBG = new GradientDrawable();
customBG.SetColor(Android.Graphics.Color.Transparent);
customBG.SetCornerRadius(3);
Control.SetBackground(customBG);
Control.Ellipsize = TextUtils.TruncateAt.End;
var custdatepicker = (NoBorderPicker) this.Element;
this.Control.TextSize = (float)custdatepicker.FontSize;
}
}
}
}
Now, I could be sure that Control.SetSingleLine(true); will work.
if you are using a custom renderer can be the incorret inheritance.
Use Xamarin.Forms.Platform.Android.AppCompat.PickerRenderer not Xamarin.Forms.Platform.Android.PickerRenderer
Tks to https://www.damirscorner.com/blog/posts/20201204-CustomPickerRendererOnAndroid.html
Oddly enough, for me in the latest Xamarin Forms, on Android the Picker automatically truncates text, but on iOS the Picker becomes arbitrarily wide, covering up other UI elements.
The fix is to set the MinimumWidthRequest = 1, which for some reason re-enables text truncation. I have no idea why. Welcome to Xamarin.
I have localised the whole app but not able to localise the date picker. A bit of searchin in the forum gave me few answers like this one
but i cant find a properties folder with the resx for different lang for toolkit! I have jus added the toolkit reference in the solution explorer under reference and thats im able to access date picker. I have made a folder called toolkit.content to put the ok and cancel images.
so how do i add the resx for the toolkit date picker :(
You can also create a custom control which inherits from the original DatePicker.
public class MyDatePicker : Microsoft.Phone.Controls.DatePicker
{
public string PickerPageHeader
{
get { return (string)GetValue(PickerPageHeaderProperty); }
set { SetValue(PickerPageHeaderProperty, value); }
}
// Using a DependencyProperty as the backing store for PickerPageHeader. This enables animation, styling, binding, etc...
public static readonly DependencyProperty PickerPageHeaderProperty =
DependencyProperty.Register("PickerPageHeader", typeof(string), typeof(MyDatePicker)
, new PropertyMetadata("Choose date text in your language"));
public MyDatePicker()
{
base.PickerPageUri = new Uri("/Sample;component/CustomControls/MyDatePickerPage.xaml?Header=" + PickerPageHeader, UriKind.Relative);
//Don't forget to change the project name and xaml location
}
}
And create picker page xaml file in a CustomControls folder:
<toolkit:DatePickerPage
x:Class="Sample.MyDatePickerPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
/>
Code behind:
public partial class MyDatePickerPage : Microsoft.Phone.Controls.DatePickerPage
{
public MyDatePickerPage ()
{
InitializeComponent();
foreach (var item in base.ApplicationBar.Buttons)
{
IApplicationBarIconButton button = item as IApplicationBarIconButton;
if (null != button)
{
if ("DONE" == button.Text.ToUpper())
{
button.Text = "done in your language";
}
else if ("CANCEL" == button.Text.ToUpper())
{
button.Text = "cancel in your language";
}
}
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
(base.FindName("HeaderTitle") as TextBlock).Text = e.Uri.OriginalString.Substring(e.Uri.OriginalString.IndexOf("Header=") + 7);
base.OnNavigatedTo(e);
}
}
You have to get the source for the ToolKit and rebuild it with your localization
WP7 ToolKit Source
It's very simple: Parameter - Language.
Xaml code:
<toolkit:DatePicker Language="ru-RU" Margin="-12, 0" Value="{Binding BirthDate, Mode=TwoWay}" />