Event Raising in Custom Render - xaml

I have a custom Renderer which is a DatePicker Control placed inside a StackLayout. I have a label which will invoke the CustomRenderer and shows up date picker control. When i tap on the Label there is no event raised in the CustomRenderer (OnElementChanged && OnElementPropertyChanged) events. When we change the date the picker event fires and the value gets set to date picker and datepicker closes. When I try to open the date picker again the previous set date is showing. which i want to change to current date. i dont have the event to reset the date.
OnPlatform x:TypeArguments="View">
<OnPlatform.Android>
<local:CustomDatePicker AbsoluteLayout.LayoutBounds="1,0.5,-1,-1" WidthRequest="140" TextColor="Black" Date="{Binding ResourceDate}"
AbsoluteLayout.LayoutFlags="PositionProportional"/>
</OnPlatform.Android>
<OnPlatform.iOS>
<Label Text="{Binding ResourceDateIOS}" AbsoluteLayout.LayoutBounds="1,0.5,-1,-1" AbsoluteLayout.LayoutFlags="PositionProportional" FontSize="Small" TextColor="Black" >
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding OnDateClickIOSForResource}" />
</Label.GestureRecognizers>
</Label>
</OnPlatform.iOS>
</OnPlatform>
IOS Stack Custom Render:
using Xamarin.Forms;
using UIKit;
using CoreGraphics;
using Xamarin.Forms.Platform.iOS;
using System;
using VCS.FieldManager.UI.ViewModels;
[assembly: ExportRenderer(typeof(CustomStackLayout), typeof(DatePickerExtendedRender))]
namespace App.UI.iOS
{
class DatePickerExtendedRender : ViewRenderer<CustomStackLayout, UIView>
{
UIDatePicker datePicker = new UIDatePicker();
protected override void OnElementChanged(ElementChangedEventArgs<CustomStackLayout> e)
{
if (e.OldElement != null || Element == null)
{
return;
}
var customStackLayout = e.NewElement;
if (customStackLayout != null)
{
datePicker.Mode = UIDatePickerMode.Date;
UIView _view = new UIView()
{
Frame = new CGRect(10, 200, 50, 50),
// BackgroundColor = UIColor.Brown
};
datePicker.ValueChanged += (sender, arg) =>
{
var DateChangeEvent = DateTime.SpecifyKind(datePicker.Date.ToDateTime(), DateTimeKind.Utc).ToLocalTime();
var changedDate = DateChangeEvent.ToString("MMMM dd, yyyy");
//shouldnot set in application variable for Add Resources
if (GridEntryViewModel.IsResourceDate)
{
Xamarin.Forms.Application.Current.Properties["ResourceSelectedDate"] = DateChangeEvent.ToString("MMMM dd, yyyy");
datePicker.SetDate(datePicker.Date, true);
}
else
{
Xamarin.Forms.Application.Current.Properties["GlobalDateSelected"] = changedDate;
GridEntryViewModel.IsResourceDate = false;
datePicker.SetDate(datePicker.Date, true);
}
MessagingCenter.Send(changedDate, "DatePickerCallback");
};
_view.Add(datePicker);
SetNativeControl(_view);
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
}
}
}

UIDatepicker defaults to current date unless you change it. Since you instatiating your Datepicker at the class level it maintains the date. Id think one or both of the following would fix it.
if (customStackLayout != null)
{
datePicker = new UIDatePicker();
or
if (customStackLayout != null)
{
datePicker.Date = DateTime.Now;
Not sure on the second whats dataType Date is you'll have to check it and set it as appropriate but hopefiully you get my point.

Related

Xamarin binding IsEnabled does not works

I have this strange problem, where the binding seems completely ignored.
my xaml
<Button IsEnabled="{Binding ButtonEnabled}" x:Name="ButtonOK" BackgroundColor="Green" TextColor="White" Text="OK"/>
my C#
private bool _buttonEnabled = false;
public bool ButtonEnabled
{
get
{
// breakpoint 1, which never hits with value = false
return _buttonEnabled;
}
set
{
// breakpoint 2, which hits
_buttonEnabled = value;
OnPropertyChanged(nameof(ButtonEnabled));
}
}
private void ChassisEntry_TextChanged(object sender, TextChangedEventArgs e)
{
ButtonEnabled = ChassisEntry.Text != "";
}
private void PageScan_Appearing(object sender, EventArgs e)
{
ChassisEntry.Text = "";
}
I expect that when this page opens that ButtonOK is disabled, but it is not.
When I set breakpoints then breakpoint 1 (in the getter) never hits, its like if the xaml IsEnabled="{Binding ButtonEnabled}" is ignored.
The breakpoint 2 does hits, with value = false
What am I missing here ?
I googled this problem and found many similar questions, but all solutions given do not help with my problem.
Button IsEnabled binding not working properly
How to disable a button until all entries are filled?
Disable/Enable save button based on the mandatory field being null or empty using Behaviors
and many more
I am guessing you are using the xaml.cs page for holding your Bindings and hence if you are doing that there are two ways to do this
Set the BindingContext to the current class in the constructor before or right after InitializeComponent
BindingContext= this;
Or In your XAML
<ContentPage
....
x:Name="currentPage">
And in your button
<Button IsEnabled="{Binding ButtonEnabled, Source={x:Reference currentPage}}"
I would go with this: Set my Button in my XAML disabled.
<Button IsEnabled="False" x:Name="ButtonOK" BackgroundColor="Green" TextColor="White" Text="OK"/>
Then on my Entry control i would add the property TextChanged.
<Entry x:Name="ChassisEntry"
PlaceholderColor="DarkGray"
TextChanged="ChassisEntryChanged">
On xaml.cs file:
private void ChassisEntryChanged(object sender, TextChangedEventArgs e)
{
if (e.NewTextValue.Text != "")
{
ButtonOK.IsEnabled = true;
}
else
{
ButtonOK.IsEnabled = false;
}
}

Xamarin Forms: Not able to update the custom control on the UI

I have created a custom control that has horizontal bar there can be N number of boxview in the bar based on number I get from API for example i have a control with limit of 20 controls and i have selected 10 of them so 10 boxview will be on orange and remaining 10 from 20 will be black
i need to update control on every checkbox selection and it is working fine for me till i go to next screen and come back to the same screen once i come back to this screen control stops updating wile debug i get data in my code but its not updating on UI.
How i use it in my code
<views:CustomDashControl
x:Name="customDash"
Grid.Row="2"
Grid.ColumnSpan="3"
HorizontalOptions="FillAndExpand"
ItemsSource="{Binding ControlData}"
VerticalOptions="Start" />
My CustomControl XAML
<ContentView
x:Class="LIRAppV1.Controls.CustomDashControl"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
<StackLayout
Padding="1"
BackgroundColor="White"
HorizontalOptions="CenterAndExpand"
VerticalOptions="FillAndExpand">
<!--<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>-->
<Grid
x:Name="progressbar"
BackgroundColor="Transparent"
ColumnSpacing="0"
HorizontalOptions="FillAndExpand"
VerticalOptions="Start">
<Grid.RowDefinitions>
<RowDefinition Height="20" />
</Grid.RowDefinitions>
</Grid>
</StackLayout>
</ContentView>
My CodeBehind of custom control
public partial class CustomDashControl : ContentView
{
static int totalCount;
static Color barColor;
private static ObservableCollection<CustomControlData> tempData;
public static ObservableCollection<CustomControlData> TempData
{
get { return tempData; }
set
{
tempData = value;
customDashControl.OnPropertyChanged("TempData");
}
}
static CustomDashControl customDashControl;
public CustomDashControl()
{
try
{
InitializeComponent();
customDashControl = this;
}
catch (Exception ex)
{
BaseViewModel.HandleException(ex);
}
}
#region Bindable Properties
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create("ItemsSource",
typeof(ObservableCollection<CustomControlData>),
typeof(CustomDashControl), new
ObservableCollection<CustomControlData>(),
BindingMode.Default, null, OnItemsSourceChanged);
private static void OnItemsSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
if (oldValue != newValue)
{
(bindable as CustomDashControl).OnPropertyChanged("ItemsSource");
TempData = (ObservableCollection<CustomControlData>)newValue;
UpdateBar();
}
}
private static void UpdateBar()
{
try
{
if (TempData != null && TempData.Count > 0)
{
var control = customDashControl.progressbar;
control.ColumnDefinitions.Clear();
control.Children.Clear();
//Working
for (int i = 0, j = 0; i < TempData.Count; i++, j++)
{
control.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
var tempBox = new BoxView() { Color = TempData[i].BarColor, WidthRequest = TempData[i].BarWidth };
control.Children.Add(tempBox, j, 0);
j++;
control.ColumnDefinitions.Add(new ColumnDefinition() { Width = 1 });
control.Children.Add(new BoxView() { Color = Color.White, WidthRequest = 1 }, (j), 0);
}
Console.WriteLine(control.Children);
}
}
catch (Exception ex)
{
BaseViewModel.HandleException(ex);
}
}
public ObservableCollection<CustomControlData> ItemsSource
{
get { return (ObservableCollection<CustomControlData>)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly BindableProperty TotalCountProperty = BindableProperty.Create(propertyName: "TotalCount", returnType: typeof(int), declaringType: typeof(CustomDashControl), defaultValue: 0, propertyChanged: propertyChanges1);
private static void propertyChanges1(BindableObject bindable, object oldValue, object newValue)
{
if (oldValue != newValue)
{
var control = bindable as CustomDashControl;
totalCount = (int)newValue;
if (totalCount > 0)
{
(customDashControl.BindingContext as CustomDashControlViewModel).totalCount = totalCount;
}
}
}
public int TotalCount
{
get { return (int)GetValue(TotalCountProperty); }
set { SetValue(TotalCountProperty, value); }
}
#endregion
}
OnAppearing will be executed before the screen comes, when you want an Loaded event that needs to be executed right after the screen comes, there is a workaround.
Create an property in viewmodel like below.
private bool _toggleTemp;
public bool ToggleTemp
{
get => _toggleTemp;
set => SetProperty(ref _toggleTemp, value);
}
Add the following line to the last line of the constructor.
LoadingVm.ToggleTemp = true;
Add an Switch to your screen and make IsVisible to false as below.
<Switch IsToggled="{Binding ToggleTemp}" Toggled="Switch_OnToggled" IsVisible="False" />
Now you can write the code that you want to write in Page Loaded in Switch_OnToggled.
private async void Switch_OnToggled(object sender, ToggledEventArgs e)
{
/* Your code goes here... */
}
Thanks!
If this does not work refer this --
In the onappearing I wrapped everything in an async call and waited a few hundred ms for the page to get rendered.
await WaitAndExecute(1000, () =>
{
// refresh code
}
protected async Task WaitAndExecute(int milisec, Action actionToExecute)
{
await Task.Delay(milisec);
actionToExecute();
}
https://forums.xamarin.com/discussion/22561/page-loaded-event

Xamarin form app: Keyboard type telephone allow to input negative values in Android but not in IOS

I have made an application in Xamarin From. Design the UI in xaml. My issue is when i define the Keyboard telephone in entry field it allow to input negative value in android app but in IOS it not allowed.
<StackLayout Spacing="20" Padding="0" Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Entry Text="{Binding Item.TextProvider2017}" HorizontalTextAlignment="End" FontSize="Small" WidthRequest="140" MinimumWidthRequest="60" Placeholder="For 2017" Keyboard="Telephone" Completed="NoOfProvider_Completed" Unfocused="NoOfProvider_Unfocused"/>
<Entry Text="{Binding Item.TextProvider2018}" HorizontalTextAlignment="End" FontSize="Small" WidthRequest="140" MinimumWidthRequest="60" Placeholder="For 2018" Keyboard="Telephone"/>
<Entry Text="{Binding Item.TextProvider2019}" HorizontalTextAlignment="End" FontSize="Small" WidthRequest="140" MinimumWidthRequest="60" Placeholder="For 2019" Keyboard="Telephone"/>
<Entry Text="{Binding Item.TextProvider2020}" HorizontalTextAlignment="End" FontSize="Small" WidthRequest="140" MinimumWidthRequest="60" Placeholder="For 2020" Keyboard="Telephone"/>
</StackLayout>
Keypad in Android:
Keypad in IOS:
In Android keypad have negative sign but IOS don't have. IS there any way to make both same.
This is the old answer, see below for an updated version
You're going to want to create a custom renderer for the Entry control which has the default behavior for UWP and Android, while adding a custom InputAccessoryView to your iOS UITextField.
Here's what your custom renderer for iOS might look like:
class MinusButtonEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control == null) return;
UIBarButtonItem button = new UIBarButtonItem("-", UIBarButtonItemStyle.Plain, (sender, args) =>
{
var position = Control.SelectedTextRange.Start;
var idx = (int) Control.GetOffsetFromPosition(Control.BeginningOfDocument, position);
Element.Text.Insert(idx, "-");
});
UIToolbar toolbar = new UIToolbar()
{
Items = new [] { button }
};
Control.InputAccessoryView = toolbar;
}
}
This code basically creates a button, adds that to a toolbar, and then assigns that toolbar to the underlying UITextField. You will of course want to customize the toolbar and toolbar button to suit your needs.
EDIT:
There's a better way to do this using Effects in Xamarin Forms.
This class goes in the iOS project and is the main effect:
using MyApp;
using UIKit;
using Xamarin.Forms;
[assembly:ResolutionGroupName("Xamarin")]
[assembly:ExportEffect(typeof(MinusButtonEntryEffect), "MinusButtonEntryEffect")]
namespace MyApp
{
public class MinusButtonEntryEffect : PlatformEffect<UIView, UITextField>
{
protected override void OnAttached()
{
if (Control == null) return;
var element = Element as Entry;
if (element == null) return;
UIBarButtonItem button = new UIBarButtonItem("-", UIBarButtonItemStyle.Plain, (sender, args) =>
{
var position = Control.SelectedTextRange.Start;
var idx = (int)Control.GetOffsetFromPosition(Control.BeginningOfDocument, position);
element.Text = element.Text.Insert(idx, "-");
});
UIToolbar toolbar = new UIToolbar()
{
Items = new[] { button }
};
Control.InputAccessoryView = toolbar;
}
protected override void OnDetached()
{
Control.InputAccessoryView = null;
}
}
}
This code goes in the PCL and allows us to access the effect from XAML:
public class MinusButtonEntryEffect : RoutingEffect
{
public MinusButtonEntryEffect () : base ("Xamarin.MinusButtonEntryEffect") { }
}
So your XAML would look something like this:
<Entry Text="{Binding Item.TextProvider2017}" HorizontalTextAlignment="End" FontSize="Small" WidthRequest="140" MinimumWidthRequest="60" Placeholder="For 2017" Keyboard="Telephone">
<Entry.Effects>
<local:MinusButtonEntryEffect />
</Entry.Effects>
</Entry>
Make sure that local is whatever namespace your effect is in, for example:
xmlns:local="clr-namespace:MyApp"

User Control Animation Only Works On Last Declared Control Instance

I am proto-typing a (Windows 10 universal app) UI and have built a very simple/rough user control to act as a 'badge', i.e show a numeric value in a circle, and animate the value changing. My issue is the control works if there is only a single instance of it in an application page. If there are multiple instances (even if the other instances are invisible), then only the last declared instance animates.
I've tried declaring the animation both in the user control's XAML, and in code behind to attempt to ensure there's no cross-over/mix up with the animation being shared. I also added a change callback to the property being animated, which writes the property value out using Debug.WriteLine. For control instances that animate properly the value changes as expected, i.e if we go from 10 to 20, the property is set to 10, 11, 12, 13.... 20. For the instances that don't work, the value is just set to the from property every time, i.e 10, 10, 10, 10, 10.
Below is a sample of the user control, and then a sample page that uses three instances of it. Placing both of these is a new Windows 10 Universal app called App3 should reproduce the issue. In the sample page the first two badges don't animate properly when their button is clicked, but the last one does.
Is anyone able to point out what I'm doing wrong, and why this breaks with multiple instances on a page?
Thanks.
Note: The code has gotten quite rough as I've hacked things around trying to figure out what the issue is, and it was only prototype code to begin with, so I apologize for the mess.
<UserControl
x:Class="App3.BadgeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App3"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="20"
d:DesignWidth="20">
<Grid>
<Ellipse x:Name="Border" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="{Binding BadgeBorderBrush}" />
<Ellipse x:Name="BadgeInner" Margin="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="{Binding BadgeFillBrush}" />
<TextBlock x:Name="BadgeValue" Margin="5" HorizontalAlignment="Center" FontSize="10" VerticalAlignment="Center" TextAlignment="Center" TextTrimming="CharacterEllipsis" Foreground="White" Text="{Binding DisplayValue}" />
</Grid>
public sealed partial class BadgeView : UserControl
{
public DependencyProperty BadgeBorderBrushProperty = DependencyProperty.Register("BadgeBorderBrush", typeof(Brush), typeof(BadgeView), new PropertyMetadata(new SolidColorBrush(Windows.UI.Colors.Yellow)));
public DependencyProperty BadgeFillBrushProperty = DependencyProperty.Register("BadgeFillBrush", typeof(Brush), typeof(BadgeView), new PropertyMetadata(new SolidColorBrush(Windows.UI.Colors.Orange)));
public DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(BadgeView), new PropertyMetadata(0, new PropertyChangedCallback(ValueChanged)));
public DependencyProperty DisplayValueProperty = DependencyProperty.Register("DisplayValue", typeof(int), typeof(BadgeView), new PropertyMetadata(0, DisplayValueChanged));
private static void DisplayValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
System.Diagnostics.Debug.WriteLine(((BadgeView)d).DisplayValue);
}
private Storyboard AnimateBadgeValueCount;
private DoubleAnimation BadgeValueAnimation;
public BadgeView()
{
this.InitializeComponent();
this.BadgeValue.DataContext = this.BadgeInner.DataContext = this.Border.DataContext = this;
AnimateBadgeValueCount = new Storyboard(); ;
AnimateBadgeValueCount.Duration = TimeSpan.FromSeconds(0.5);
Storyboard.AllowDependentAnimations = true;
BadgeValueAnimation = new DoubleAnimation();
BadgeValueAnimation.Duration = TimeSpan.FromSeconds(0.5);
BadgeValueAnimation.EnableDependentAnimation = true;
BadgeValueAnimation.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
this.AnimateBadgeValueCount.FillBehavior = FillBehavior.Stop;
this.BadgeValueAnimation.FillBehavior = FillBehavior.Stop;
AnimateBadgeValueCount.Children.Add(BadgeValueAnimation);
Storyboard.SetTarget(AnimateBadgeValueCount, this);
Storyboard.SetTargetProperty(AnimateBadgeValueCount, "DisplayValue");
this.AnimateBadgeValueCount.Completed += AnimateBadgeValueCount_Completed;
}
private void AnimateBadgeValueCount_Completed(object sender, object e)
{
this.DisplayValue = this.Value;
}
private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var badgeView = (BadgeView)d;
badgeView.AnimateValue();
}
private void AnimateValue()
{
if (Value != DisplayValue)
{
this.BadgeValue.DataContext = this.BadgeInner.DataContext = this.Border.DataContext = this;
this.AnimateBadgeValueCount.Stop();
this.BadgeValueAnimation.From = this.DisplayValue;
this.BadgeValueAnimation.To = this.Value;
this.BadgeValueAnimation.FillBehavior = FillBehavior.Stop;
//Storyboard.SetTarget(this.AnimateBadgeValueCount, this);
//Storyboard.SetTargetProperty(this.AnimateBadgeValueCount, "DisplayValue");
this.AnimateBadgeValueCount.Begin();
}
}
public Brush BadgeBorderBrush
{
get { return (Brush)this.GetValue(this.BadgeBorderBrushProperty); }
set
{
this.SetValue(this.BadgeBorderBrushProperty, value);
}
}
public Brush BadgeFillBrush
{
get { return (Brush)this.GetValue(this.BadgeFillBrushProperty); }
set
{
this.SetValue(this.BadgeFillBrushProperty, value);
}
}
public int Value
{
get { return (int)this.GetValue(ValueProperty); }
set
{
this.SetValue(ValueProperty, value);
}
}
public int DisplayValue
{
get { return (int)this.GetValue(DisplayValueProperty); }
set
{
this.SetValue(DisplayValueProperty, value);
}
}
}
<Page
x:Class="App3.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App3"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Orientation="Vertical">
<Button Content="Do it" x:Name="DoIt1" Click="DoIt1_Click" />
<local:BadgeView x:Name="Badge1" Width="20" Height="20" BadgeFillBrush="Blue" />
<Button Content="Do it" x:Name="DoIt2" Click="DoIt2_Click" />
<local:BadgeView x:Name="Badge2" Width="20" Height="20" />
<Button Content="Do it" x:Name="DoIt3" Click="DoIt3_Click" />
<local:BadgeView x:Name="Badge3" Width="20" Height="20" />
</StackPanel>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void DoIt1_Click(object sender, RoutedEventArgs e)
{
this.Badge1.Value += 10;
}
private void DoIt2_Click(object sender, RoutedEventArgs e)
{
this.Badge2.Value += 10;
}
private void DoIt3_Click(object sender, RoutedEventArgs e)
{
this.Badge3.Value += 10;
}
}
What I have done is simplify code and simplify and move the datacontext inside the loaded event inside the constructor:
this.Loaded += (s, e) =>
{
this.DataContext = this;
AnimateBadgeValueCount = new Storyboard(); ;
AnimateBadgeValueCount.Duration = TimeSpan.FromSeconds(0.5);
BadgeValueAnimation = new DoubleAnimation();
BadgeValueAnimation.Duration = TimeSpan.FromSeconds(0.5);
//BadgeValueAnimation.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
AnimateBadgeValueCount.Children.Add(BadgeValueAnimation);
Storyboard.SetTarget(AnimateBadgeValueCount, this);
Storyboard.SetTargetProperty(AnimateBadgeValueCount, "DisplayValue");
this.AnimateBadgeValueCount.Completed += AnimateBadgeValueCount_Completed;
};
private async void AnimateValue()
{
if (Value != DisplayValue)
{
this.AnimateBadgeValueCount.Stop();
this.BadgeValueAnimation.From = this.DisplayValue;
this.BadgeValueAnimation.To = this.Value;
BadgeValueAnimation.EnableDependentAnimation = true;
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
{
this.AnimateBadgeValueCount.Begin();
});
}
}
I have commented the EasingFunction, it works but in my opinion fit betters.
It is curious, because if I set the datacontext just in the constructor it works bad, but inside goes fine.
Tell me if you try.

I need a event for the slider it should fire only if user ends touching the control

My Requriment : I need a event for slider it should fire only if user ends touching the control
Custom Control :
public class ExtendedSlider : Slider
{
public event EventHandler StopedDraging;
public void OnStopedDrag()
{
if (StopedDraging != null)
{
StopedDraging(this,EventArgs.Empty);
}
}
}
UI :
<ListView.ItemTemplate >
<Label Text="{Binding luminaireLevel, StringFormat='{0:F0}%'}" />
<PCAControls:ExtendedSlider Maximum="100" Minimum="25"
Value="{Binding luminaireLevel, Mode=TwoWay}"
LuminaireID="{Binding id}"
StopedDraging="ExtendedSlider_StopedDraging"
/>
</ListView.ItemTemplate>
Renderer :
class ExtendedSliderRenderer : SliderRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var slider = (PCA.CustomControls.ExtendedSlider)e.NewElement;
Control.Max = (int)(slider.Maximum - slider.Minimum);
Control.Progress = (int)(slider.Value - slider.Minimum);
Control.StopTrackingTouch += Control_StopTrackingTouch;
}
}
void Control_StopTrackingTouch(object sender, SeekBar.StopTrackingTouchEventArgs e)
{
var slider = (PCA.CustomControls.ExtendedSlider)Element;
slider.Value = Control.Progress + slider.Minimum;
slider.OnStopedDrag();
}
}
Problem is : I achieved what i expected, but user stop draging the slider or tap between the slider , luminaireLevel (vewmodel property) is updating but the slider always showing the full progess
When your renderer changes the value of the iOS control the "binding" isn't Two=Way in that respect. To achieve what you want you need to bind the Xamarin.Forms Slider to value in your viewmodel then in your renderer you change the value in your viewmodel.
If you bind all your properties (min, max, value, progress) itll be easier