Xamarin Forms - Listview view cell swipe left and right events using xamal - xaml

I need to write code (or XAML) for listview viewcell swipe left and right gestures.
When swiping left, delete the records from listview (or observable collection) list and update the remaining listitems in listview. When swiping right, save the records.

I've do it using cs code,You can try it on xaml.
First, you should build swipe compoment using gesture
SwipeGestureGrid.cs
public class SwipeGestureGrid : Grid
{
#region Private Member
private double _gestureX { get; set; }
private double _gestureY { get; set; }
private bool IsSwipe { get; set; }
#endregion
#region Public Member
#region Events
#region Tapped
public event EventHandler Tapped;
protected void OnTapped(EventArgs e)
{
if (Tapped != null)
Tapped(this, e);
}
#endregion
#region SwipeUP
public event EventHandler SwipeUP;
protected void OnSwipeUP(EventArgs e)
{
if (SwipeUP != null)
SwipeUP(this, e);
}
#endregion
#region SwipeDown
public event EventHandler SwipeDown;
protected void OnSwipeDown(EventArgs e)
{
if (SwipeDown != null)
SwipeDown(this, e);
}
#endregion
#region SwipeRight
public event EventHandler SwipeRight;
protected void OnSwipeRight(EventArgs e)
{
if (SwipeRight != null)
SwipeRight(this, e);
}
#endregion
#region SwipeLeft
public event EventHandler SwipeLeft;
protected void OnSwipeLeft(EventArgs e)
{
if (SwipeLeft != null)
SwipeLeft(this, e);
}
#endregion
#endregion
public double Height
{
get
{
return HeightRequest;
}
set
{
HeightRequest = value;
}
}
public double Width
{
get
{
return WidthRequest;
}
set
{
WidthRequest = value;
}
}
#endregion
public SwipeGestureGrid()
{
PanGestureRecognizer panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += PanGesture_PanUpdated;
TapGestureRecognizer tapGesture = new TapGestureRecognizer();
tapGesture.Tapped += TapGesture_Tapped;
GestureRecognizers.Add(panGesture);
GestureRecognizers.Add(tapGesture);
}
private void TapGesture_Tapped(object sender, EventArgs e)
{
try
{
if (!IsSwipe)
OnTapped(null);
IsSwipe = false;
}
catch (Exception ex)
{
}
}
private void PanGesture_PanUpdated(object sender, PanUpdatedEventArgs e)
{
try
{
switch (e.StatusType)
{
case GestureStatus.Running:
{
_gestureX = e.TotalX;
_gestureY = e.TotalY;
}
break;
case GestureStatus.Completed:
{
IsSwipe = true;
//Debug.WriteLine("{0} {1}", _gestureX, _gestureY);
if (Math.Abs(_gestureX) > Math.Abs(_gestureY))
{
if (_gestureX > 0)
{
OnSwipeRight(null);
}
else
{
OnSwipeLeft(null);
}
}
else
{
if (_gestureY > 0)
{
OnSwipeDown(null);
}
else
{
OnSwipeUP(null);
}
}
}
break;
}
}
catch (Exception ex)
{
}
}
}
Next using datatemplate in listview andattach event for Gesturecompoment
Page.cs
ListView lsvData = new ListView()
{
VerticalOptions = LayoutOptions.Fill,
HorizontalOptions = LayoutOptions.Fill,
BackgroundColor = Color.White,
HasUnevenRows = true,
};
List<string> lstData = new List<string>();
public Pages()
{
#region DataTemplate
DataTemplate ListDataTemplate = new DataTemplate(() =>
{
#region DataArea of Template
SwipeGestureGrid gridData = new SwipeGestureGrid()
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
HeightRequest = 60,
RowDefinitions =
{
new RowDefinition { },
},
ColumnDefinitions =
{
new ColumnDefinition { },
}
};
#endregion
#region Base of Template
Grid gridBase = new Grid()
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
HeightRequest = 60,
RowDefinitions =
{
new RowDefinition { },
},
ColumnDefinitions =
{
new ColumnDefinition { }, //Put Cells Data here
new ColumnDefinition { Width = new GridLength(0, GridUnitType.Absolute)}, //Button for Cells here
},
};
#endregion
Label lblText = new Label
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
FontAttributes = FontAttributes.Bold,
VerticalTextAlignment = TextAlignment.End,
TextColor = Color.Black,
BackgroundColor = Color.Silver,
LineBreakMode = LineBreakMode.TailTruncation,
FontSize = 18,
};
lblText.SetBinding(Label.TextProperty, ".");
ImageButton btnCellDelete = new ImageButton() { Source = "Delete" };
gridData.Children.Add(lblText, 0, 0);
gridBase.Children.Add(gridData, 0, 0);
gridBase.Children.Add(btnCellDelete, 1, 0);
gridData.SwipeLeft += GridTemplate_SwipeLeft;
gridData.SwipeRight += GridTemplate_SwipeRight; ;
gridData.Tapped += GridTemplate_Tapped; ;
btnCellDelete.Clicked += BtnCellDelete_Clicked; ;
return new ViewCell
{
View = gridBase,
Height = 60,
};
});
#endregion
for (int i = 1; i <= 100; i++)
{
lstData.Add(i.ToString());
}
lsvData.ItemTemplate = ListDataTemplate;
lsvData.ItemsSource = lstData;
Content = lsvData;
}
event
SwipeLeft to show DeleteButton
private void GridTemplate_SwipeLeft(object sender, EventArgs e)
{
try
{
if (sender is SwipeGestureGrid)
{
var templateGrid = ((SwipeGestureGrid)sender).Parent;
if (templateGrid != null && templateGrid is Grid)
{
var CellTemplateGrid = (Grid)templateGrid;
CellTemplateGrid.ColumnDefinitions[1].Width = new GridLength(60, GridUnitType.Absolute);
}
}
}
catch (Exception ex)
{
}
}
swiperight to hide delete button
private void GridTemplate_SwipeRight(object sender, EventArgs e)
{
try
{
if (sender is SwipeGestureGrid)
{
var templateGrid = ((SwipeGestureGrid)sender).Parent;
if (templateGrid != null && templateGrid is Grid)
{
var CellTemplateGrid = (Grid)templateGrid;
CellTemplateGrid.ColumnDefinitions[1].Width = new GridLength(0, GridUnitType.Absolute);
}
}
}
catch (Exception ex)
{
}
}
Delete button click event
private void BtnCellDelete_Clicked(object sender, EventArgs e)
{
try
{
if (sender is ImageButton)
{
var templateGrid = ((ImageButton)sender);
//templateGrid.Parent = gridBase
//templateGrid.Parent.Parent = cell
if (templateGrid.Parent != null && templateGrid.Parent.Parent != null && templateGrid.Parent.Parent.BindingContext != null && templateGrid.Parent.Parent.BindingContext is string)
{
var deletedate = templateGrid.Parent.Parent.BindingContext as string;
lstData.RemoveAll(f => f == deletedate);
lsvData.ItemsSource = null;
lsvData.ItemsSource = lstData;
}
}
}
catch (Exception ex)
{
}
}
Source can be find in my github
https://github.com/act70255/ListViewSwipeGesture

I've reworked James Lin's class to be command based so that it's MVVM friendly.
public class SwipeGestureGrid : Grid
{
public static readonly BindableProperty SwipeLeftCommandProperty =
BindableProperty.Create("SwipeLeftCommand", typeof(ICommand), typeof(ICommand), null);
public static readonly BindableProperty SwipeRightCommandProperty =
BindableProperty.Create("SwipeRightCommand", typeof(ICommand), typeof(ICommand), null);
public static readonly BindableProperty SwipeUpCommandProperty =
BindableProperty.Create("SwipeUpCommand", typeof(ICommand), typeof(ICommand), null);
public static readonly BindableProperty SwipeDownCommandProperty =
BindableProperty.Create("SwipeDownCommand", typeof(ICommand), typeof(ICommand), null);
public static readonly BindableProperty TappedCommandProperty =
BindableProperty.Create("TappedCommand", typeof(ICommand), typeof(ICommand), null);
private double _gestureStartX;
private double _gestureStartY;
private double _gestureDistanceX;
private double _gestureDistanceY;
public double GestureStartX
{
get => _gestureStartX;
private set
{
_gestureStartX = value;
OnPropertyChanged();
}
}
public double GestureStartY
{
get => _gestureStartY;
private set
{
_gestureStartY = value;
OnPropertyChanged();
}
}
private bool IsSwipe { get; set; }
public ICommand TappedCommand
{
get => (ICommand) GetValue(TappedCommandProperty);
set => SetValue(TappedCommandProperty, value);
}
public ICommand SwipeLeftCommand
{
get => (ICommand)GetValue(SwipeLeftCommandProperty);
set => SetValue(SwipeLeftCommandProperty, value);
}
public ICommand SwipeRightCommand
{
get => (ICommand)GetValue(SwipeRightCommandProperty);
set => SetValue(SwipeRightCommandProperty, value);
}
public ICommand SwipeUpCommand
{
get => (ICommand)GetValue(SwipeUpCommandProperty);
set => SetValue(SwipeUpCommandProperty, value);
}
public ICommand SwipeDownCommand
{
get => (ICommand)GetValue(SwipeDownCommandProperty);
set => SetValue(SwipeDownCommandProperty, value);
}
public SwipeGestureGrid()
{
var panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += PanGesture_PanUpdated;
var tapGesture = new TapGestureRecognizer();
tapGesture.Tapped += TapGesture_Tapped;
GestureRecognizers.Add(panGesture);
GestureRecognizers.Add(tapGesture);
}
private void TapGesture_Tapped(object sender, EventArgs e)
{
try
{
if (!IsSwipe)
TappedCommand?.Execute(this);
IsSwipe = false;
}
catch (Exception ex)
{
}
}
private void PanGesture_PanUpdated(object sender, PanUpdatedEventArgs e)
{
switch (e.StatusType)
{
case GestureStatus.Started:
{
GestureStartX = e.TotalX;
GestureStartY = e.TotalY;
}
break;
case GestureStatus.Running:
{
_gestureDistanceX = e.TotalX;
_gestureDistanceY = e.TotalY;
}
break;
case GestureStatus.Completed:
{
IsSwipe = true;
if (Math.Abs(_gestureDistanceX) > Math.Abs(_gestureDistanceY))
{
if (_gestureDistanceX > 0)
{
SwipeRightCommand?.Execute(this);
}
else
{
SwipeLeftCommand?.Execute(null);
}
}
else
{
if (_gestureDistanceY > 0)
{
SwipeDownCommand?.Execute(null);
}
else
{
SwipeUpCommand?.Execute(null);
}
}
}
break;
}
}
}
We use it in a DataTemplate for a ScrollableListView:
<DataTemplate x:Key="ThreeRowTemplateTemplate" x:DataType="{x:Type tracking:TrackingItem}">
<ViewCell>
<controls:SwipeGestureGrid ColumnSpacing="0" RowSpacing="0" SwipeLeftCommand="{Binding SwipeLeftCommand}">
In this case the bound command has to be on TrackingItem. It seems to work quite well but the detection is sometimes a bit flaky - possibly there's a conflict with the ScrollableListView's gesture handling.

Related

display picker when clicking in imagebutton xamarin

i want to display a picker (or list) when i click in my imageButton but it didn't work, but when i create only a picker , it worked.
Xaml
<StackLayout Orientation="Horizontal" x:Name="stacklayout">
<Entry Placeholder="préciser l'entité correspondante"
ClearButtonVisibility="WhileEditing" x:Name="entit"/>
<ImageButton Source="list.png" WidthRequest="30" HeightRequest="30" x:Name="listEntité" Clicked="listEntité_Clicked"/>
Xaml.cs
private void listEntité_Clicked(object sender, EventArgs e)
{
Picker p = new Picker();
HttpClient httpClient = new HttpClient();
httpClient.BaseAddress = new Uri("http://192.168.1.3:3000/api/adepApi/GetCurrencyLists");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await httpClient.GetAsync("http://192.168.1.3:3000/api/adepApi/GetCurrencyLists");
var content = await response.Content.ReadAsStringAsync();
ResponseDataD EL = JsonConvert.DeserializeObject<ResponseDataD>(content);
p.ItemsSource= EL.Data.DeviseList;
stacklayout.Children.Add(p.ItemsSource);
}
class DeviseModel
public class DeviseModel
{
public class DeviseL
{
// public string devis;
[JsonProperty("Label")]
public string Devis { get; set; }
[JsonProperty("Value")]
public int id { get; set; }
}
public class ResponseDataD
{
public RootModelDevise Data;
}
public class RootModelDevise : INotifyPropertyChanged
{
List<DeviseL> deviseList;
[JsonProperty("list")]
public List<DeviseL> DeviseList
{
get { return deviseList; }
set
{
if (deviseList != value)
{
deviseList = value;
OnPropertyChanged();
}
}
}
DeviseL itemDevise;
public DeviseL ItemDevise
{
get { return itemDevise; }
set
{
if (itemDevise != value)
{
itemDevise = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}}
i have an error in the line
stacklayout.Children.Add(p.ItemsSource);
under p.itemsSource :unable to convert from 'System.Collections.Ilist' to 'Xamarin.Forms.View'
i have tried to add picker by imageButton click event , but nothing appears.
Firstly, please confirm that the EL.Data.DeviseList have list value, you have list binding to Picker, then adding picker to current contentPage.
public partial class Page16 : ContentPage
{
private List<string> list;
public Page16()
{
InitializeComponent();
list = new List<string>();
list.Add("test 1");
list.Add("test 2");
list.Add("test 3");
list.Add("test 4");
}
private void imagebutton1_Clicked(object sender, EventArgs e)
{
Picker p = new Picker();
p.ItemsSource = list;
stacklayout.Children.Add(p);
}
}
<StackLayout x:Name="stacklayout">
<ImageButton
x:Name="imagebutton1"
Clicked="imagebutton1_Clicked"
HeightRequest="30"
Source="plu3.png"
WidthRequest="30" />
</StackLayout>
Update:
private void imagebutton1_Clicked(object sender, EventArgs e)
{
Picker p = new Picker();
p.SelectedIndexChanged += P_SelectedIndexChanged;
p.ItemsSource = devs;
p.ItemDisplayBinding = new Binding("Devis");
stacklayout.Children.Add(p);
}
private void P_SelectedIndexChanged(object sender, EventArgs e)
{
Picker p = sender as Picker;
DeviseL selectitem = p.SelectedItem as DeviseL;
entit.Text =selectitem.Devis;
}

How to change when the Data Binding (back to Source) happens in Xamarin Forms?

I have multiple Entry views in my page connecting to a View Model using Data Binding. Everything works as intended except I need to calculate a values as the user enters it.
public decimal DownPayment
{
get => this.loanValues.DownPayment;
set
{
this.loanValues.DownPayment = value;
this.CalculateValues();
}
}
public decimal TradeInPrice
{
get => this.loanValues.TradeInPrice;
set
{
this.loanValues.TradeInPrice = value;
this.CalculateValues();
}
}
// Other properties
Now the problem is the property is set whenever user is entering the value. Is there anyway to change the event on which the Data Binding happens (i.e on Completed instead of TextChanged)?
I see there is UpdateSourceEventName property in XAML binding but I don't know why it doesn't work:
<Entry Placeholder="Down Payment ($)" Text="{Binding DownPayment, UpdateSourceEventName=Completed}" />
UPDATE: The documentation of UpdateSourceEventName says it's For internal use by the Xamarin.Forms platform
You could use EventToCommandBehavior to convert the Event Completed of Entry to Command and handle the logic in ViewModel .
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace App18
{
public class BehaviorBase<T> : Behavior<T> where T : BindableObject
{
public T AssociatedObject { get; private set; }
protected override void OnAttachedTo(T bindable)
{
base.OnAttachedTo(bindable);
AssociatedObject = bindable;
if (bindable.BindingContext != null)
{
BindingContext = bindable.BindingContext;
}
bindable.BindingContextChanged += OnBindingContextChanged;
}
protected override void OnDetachingFrom(T bindable)
{
base.OnDetachingFrom(bindable);
bindable.BindingContextChanged -= OnBindingContextChanged;
AssociatedObject = null;
}
void OnBindingContextChanged(object sender, EventArgs e)
{
OnBindingContextChanged();
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
BindingContext = AssociatedObject.BindingContext;
}
}
}
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.Windows.Input;
using Xamarin.Forms;
namespace App18
{
public class EventToCommandBehavior : BehaviorBase<View>
{
Delegate eventHandler;
public static readonly BindableProperty EventNameProperty = BindableProperty.Create("EventName", typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged);
public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(EventToCommandBehavior), null);
public static readonly BindableProperty InputConverterProperty = BindableProperty.Create("Converter", typeof(IValueConverter), typeof(EventToCommandBehavior), null);
public string EventName
{
get { return (string)GetValue(EventNameProperty); }
set { SetValue(EventNameProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public IValueConverter Converter
{
get { return (IValueConverter)GetValue(InputConverterProperty); }
set { SetValue(InputConverterProperty, value); }
}
protected override void OnAttachedTo(View bindable)
{
base.OnAttachedTo(bindable);
RegisterEvent(EventName);
}
protected override void OnDetachingFrom(View bindable)
{
DeregisterEvent(EventName);
base.OnDetachingFrom(bindable);
}
void RegisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return;
}
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
{
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't register the '{0}' event.", EventName));
}
MethodInfo methodInfo = typeof(EventToCommandBehavior).GetTypeInfo().GetDeclaredMethod("OnEvent");
eventHandler = methodInfo.CreateDelegate(eventInfo.EventHandlerType, this);
eventInfo.AddEventHandler(AssociatedObject, eventHandler);
}
void DeregisterEvent(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return;
}
if (eventHandler == null)
{
return;
}
EventInfo eventInfo = AssociatedObject.GetType().GetRuntimeEvent(name);
if (eventInfo == null)
{
throw new ArgumentException(string.Format("EventToCommandBehavior: Can't de-register the '{0}' event.", EventName));
}
eventInfo.RemoveEventHandler(AssociatedObject, eventHandler);
eventHandler = null;
}
void OnEvent(object sender, object eventArgs)
{
if (Command == null)
{
return;
}
object resolvedParameter;
if (CommandParameter != null)
{
resolvedParameter = CommandParameter;
}
else if (Converter != null)
{
resolvedParameter = Converter.Convert(eventArgs, typeof(object), null, null);
}
else
{
resolvedParameter = eventArgs;
}
if (Command.CanExecute(resolvedParameter))
{
Command.Execute(resolvedParameter);
}
}
static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue)
{
var behavior = (EventToCommandBehavior)bindable;
if (behavior.AssociatedObject == null)
{
return;
}
string oldEventName = (string)oldValue;
string newEventName = (string)newValue;
behavior.DeregisterEvent(oldEventName);
behavior.RegisterEvent(newEventName);
}
}
}
in xaml
</StackLayout>
<Entry WidthRequest="100" Text="{Binding Value1,Mode=OneWayToSource}" Keyboard="Numeric" >
<Entry.Behaviors>
<local:EventToCommandBehavior EventName="Unfocused" Command="{Binding CompletedCommand}" />
</Entry.Behaviors>
</Entry>
<Entry WidthRequest="100" Text="{Binding Value2,Mode=OneWayToSource}" Keyboard="Numeric">
<Entry.Behaviors>
<local:EventToCommandBehavior EventName="Unfocused" Command="{Binding CompletedCommand}" />
</Entry.Behaviors>
</Entry>
<Label WidthRequest="100" Text="{Binding Sum}" TextColor="Black" />
</StackLayout>
in ViewModel
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
double value1;
public double Value1
{
get
{
return value1;
}
set
{
if (value1 != value)
{
value1 = value;
NotifyPropertyChanged("Value1");
}
}
}
double value2;
public double Value2
{
get
{
return value2;
}
set
{
if (value2 != value)
{
value2 = value;
NotifyPropertyChanged("Value2");
}
}
}
private string sum;
public string Sum
{
get { return sum; }
set
{
if (sum != value)
{
sum = value;
NotifyPropertyChanged("Sum");
}
}
}
public ICommand CompletedCommand { get; set; }
public MyViewModel()
{
CompletedCommand = new Command(()=> {
Sum = (Value1 + Value2).ToString();
});
}
}

Change of color de my custom enter once is clicked my button

im working with custon entry rendered, i need to hear from xaml in my custom render when i clicked my button
i have this code in my xaml
<local:MyEntry eventRefresh="true">
when i clicked my button this function is actived
private async void Execute(object sender)
{
var entry = ((MyEntry)view);
entry.eventRefresh = "false";
but my EntryRendered donot hear the change
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
var element = Element as MyEntry;
You should define the property eventRefresh as Bindable Property .
in your custom Entry
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Xamarin.Forms;
namespace xxx
{
public class MyEntry:Entry,INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public static readonly BindableProperty eventRefreshProperty = BindableProperty.Create("eventRefresh", typeof(bool), typeof(MyEntry), true,propertyChanged:(obj,oldValue,newValue)=> {
//var entry = obj as MyEntry;
// entry.Text = newValue.ToString();
});
bool refresh;
public bool eventRefresh
{
get { return refresh; }
set {
if(refresh !=value)
{
refresh = value;
NotifyPropertyChanged("eventRefresh");
}
}
}
public MyEntry()
{
}
}
}
in xaml
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<local:MyEntry eventRefresh="{Binding Refresh}" BackgroundColor="{Binding BGcolor}" WidthRequest="200" HeightRequest="50" />
<Button Command="{Binding ClickCommand}" />
</StackLayout>
in View Model
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Color color;
public Color BGcolor
{
get { return color; }
set
{
if (color != value)
{
color = value;
NotifyPropertyChanged("BGcolor");
}
}
}
bool refresh;
public bool Refresh
{
get { return refresh; }
set
{
if (refresh != value)
{
refresh = value;
NotifyPropertyChanged("Refresh");
}
}
}
public ICommand ClickCommand { get; set; }
public MyViewModel()
{
BGcolor = Color.LightPink;
ClickCommand = new Command(()=> {
BGcolor = Color.Red;
});
}
}
in Custom Renderer
using System.ComponentModel;
using Android.Content;
using xxx;
using xxx.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly:ExportRenderer(typeof(MyEntry),typeof(NyEntryRenderer))]
namespace xxx.Droid
{
public class NyEntryRenderer : EntryRenderer
{
public NyEntryRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Element.TextChanged += Element_TextChanged;
}
}
private void Element_TextChanged(object sender, TextChangedEventArgs e)
{
// var content = Element.Text;
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == MyEntry.BackgroundColorProperty.PropertyName)
{
// will been invoked when click button
}
}
}
}
Make your view model like this.
public class YourViewModel
{
public Command command
{
get
{
return new Command(() => {
//Change here button background colors
BackgroundColor = Color.Green;
});
}
}
private _backgroundColor = Color.White;
public Color BackgroundColor
{
get { return _backgroundColor;}
set
{
if (value == _backgroundColor)
return;
_backgroundColor = value;
NotifyOnPropertyChanged(nameof(BackgroundColor));
}
}
}
Your XAML
<local:MyEntry Text="{Binding Password}" Placeholder="Enter" />
<Button Text="send" Command="{Binding command}" BackgroundColor="{Binding BackgroundColor}"></Button>

How to defer binding request until item becomes visible on the screen?

I noticed on ListBoxes and LongListSelectors, that the item bound property requests are deferred until they are scrolled toward.
Is it possible to do the same thing in relation to custom positioned items in a ScrollViewer, such that the item doesn't make any request for its bound property values until it is scrolled toward? Is there any easy setting to make this happen automatically?
If not, then what's the simplest way of doing it otherwise?
Its called Lazy Load
here you have an example of Lazy List:
public class LazyCollection<T> : IList<T>, IList, INotifyCollectionChanged, INotifyPropertyChanged
{
private const int LOAD_THRESHOLD = 3;
private ObservableCollection<T> _innerCollection;
public LazyCollection(Func<int, IEnumerable<T>> fetch)
: this(fetch, null)
{ }
public LazyCollection(Func<int, IEnumerable<T>> fetch, IEnumerable<T> items)
{
_fetch = fetch;
_innerCollection = new ObservableCollection<T>(items ?? new T[0]);
this.AttachEvents();
this.HasMoreItems = true;
}
private void AttachEvents()
{
_innerCollection.CollectionChanged += (s, e) => OnCollectionChanged(e);
((INotifyPropertyChanged)_innerCollection).PropertyChanged += (s, e) => OnPropertyChanged(e);
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, e);
}
#endregion
#region INotifyCollectionChanged
public event NotifyCollectionChangedEventHandler CollectionChanged;
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (this.CollectionChanged != null)
this.CollectionChanged(this, e);
}
#endregion
#region IList<T>
public int IndexOf(T item)
{
return _innerCollection.IndexOf(item);
}
public void Insert(int index, T item)
{
_innerCollection.Insert(index, item);
}
public void RemoveAt(int index)
{
_innerCollection.RemoveAt(index);
}
public T this[int index]
{
get
{
Debug.WriteLine("LazyCollection - Reading item {0}", index);
return _innerCollection[index];
}
set { _innerCollection[index] = value; }
}
public void Add(T item)
{
_innerCollection.Add(item);
}
public void Clear()
{
_innerCollection.Clear();
}
public bool Contains(T item)
{
return _innerCollection.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
_innerCollection.CopyTo(array, arrayIndex);
}
public int Count
{
get { return _innerCollection.Count; }
}
public bool IsReadOnly
{
get { return ((IList<T>)_innerCollection).IsReadOnly; }
}
public bool Remove(T item)
{
return _innerCollection.Remove(item);
}
public IEnumerator<T> GetEnumerator()
{
Debug.WriteLine("LazyCollection - GetEnumerator");
return _innerCollection.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
Debug.WriteLine("LazyCollection - GetEnumerator explicit");
return ((IEnumerable)_innerCollection).GetEnumerator();
}
#endregion
#region IList
int IList.Add(object value)
{
return ((IList)_innerCollection).Add(value);
}
bool IList.Contains(object value)
{
return ((IList)_innerCollection).Contains(value);
}
int IList.IndexOf(object value)
{
return ((IList)_innerCollection).IndexOf(value);
}
void IList.Insert(int index, object value)
{
((IList)_innerCollection).Insert(index, value);
}
bool IList.IsFixedSize
{
get { return ((IList)_innerCollection).IsFixedSize; }
}
bool IList.IsReadOnly
{
get { return ((IList)_innerCollection).IsReadOnly; }
}
void IList.Remove(object value)
{
((IList)_innerCollection).Remove(value);
}
object IList.this[int index]
{
get
{
if (index > this.Count - LOAD_THRESHOLD)
{
this.TryLoadMoreItems();
}
Debug.WriteLine("LazyCollection - Reading item {0} IList", index);
return ((IList)_innerCollection)[index];
}
set { ((IList)_innerCollection)[index] = value; }
}
void ICollection.CopyTo(Array array, int index)
{
((IList)_innerCollection).CopyTo(array, index);
}
bool ICollection.IsSynchronized
{
get { return ((IList)_innerCollection).IsSynchronized; }
}
object ICollection.SyncRoot
{
get { return ((IList)_innerCollection).SyncRoot; }
}
#endregion
public T[] GetLoadedItems()
{
return _innerCollection.ToArray();
}
public void ResetLoadedItems(IEnumerable<T> list)
{
_innerCollection.Clear();
foreach (var i in list)
_innerCollection.Add(i);
this.HasMoreItems = true;
}
public bool HasMoreItems { get; set; }
private bool _isLoading = false;
private Func<int, IEnumerable<T>> _fetch;
private async Task TryLoadMoreItems()
{
if (_isLoading || !this.HasMoreItems)
return;
try
{
_isLoading = true;
Debug.WriteLine("LazyCollection - Loading more items skip {0}", this.Count);
List<T> items = _fetch != null ? (_fetch(Count)).ToList() : new List<T>();
if (items.Count == 0)
{
Debug.WriteLine("LazyCollection - No items returned, Loading disabled", this.Count);
this.HasMoreItems = false;
}
items.ForEach(x => _innerCollection.Add(x));
Debug.WriteLine("LazyCollection - Items added. Total count: {0}", this.Count);
}
finally
{
_isLoading = false;
}
}
}
public class SearchResults : LazyCollection<Verse>
{
public SearchResults()
: base(count => GetSearchResult(), GetSearchResult())
{
}
public static int _index = 0;
public static string CurrentSearch = "";
public static List<Verse> AllVerses = new List<Verse>();
private static List<Verse> GetSearchResult()
{
List<Verse> results = new List<Verse>();
string lower = CurrentSearch.ToLower();
bool resultsChanged = false;
for (int index = _index; index < AllVerses.Count; index++)
{
Verse verse = AllVerses[index];
if (verse.Content.ToLower().Contains(lower) || verse.Header.ToLower().Contains(lower))
{
results.Add(verse);
resultsChanged = true;
}
if ((index >= (AllVerses.Count / 200) + _index || index + 1 == AllVerses.Count) && resultsChanged && (results.Count > 10 || AllVerses.Count == index + 1))
{
_index = index + 1;
return results;
}
}
return results;
}
}

calling alarm from a service

I designed my service as it will make an alarm when user will go to a certain location.
But it crashes when it go to the certain making the alarm.
public class CheckDestinationService extends Service {
Calendar calender;
double late,longe;
int dis;
String loc;
private LocationManager mLocationManager = null;
private static final int LOCATION_INTERVAL = 0;
private static final float LOCATION_DISTANCE = 0;
private class LocationListener implements android.location.LocationListener {
Location mLastLocation;
public LocationListener(String provider) {
mLastLocation = new Location(provider);
}
public void onLocationChanged(Location location) {
mLastLocation.set(location);
final double currlat;
final double currlong;
float[] DistanceArray = new float[1];
currlat = location.getLatitude();
currlong = location.getLongitude();
android.location.Location.distanceBetween(currlat,currlong,late,longe,DistanceArray);
float Distance = DistanceArray[0];
//Toast.makeText(getApplicationContext(), "asdf "+String.valueOf(Distance), Toast.LENGTH_SHORT).show();
Log.d("asdfasdas", String.valueOf(currlat)+","+String.valueOf(currlong)+" "+String.valueOf(Distance));
if (Distance<=dis && Distance!=0 && dis!=0)
{
dis = 0;
Intent intent = new Intent(getBaseContext(), AlarmReceiver.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Toast.makeText(getApplicationContext(), "Reached "+String.valueOf(Distance), Toast.LENGTH_SHORT).show();
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager)getSystemService(Activity.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, calender.getTimeInMillis(),pendingIntent);
//stopSelf();
}
/*final Handler handler = new Handler();
Runnable r = new Runnable() {
public void run() {
// TODO Auto-generated method stub
Intent intent = null;
intent.putExtra("lat", currlat);
intent.putExtra("long", currlong);
intent.putExtra("dis", dis);
intent.putExtra("loc", loc);
Toast.makeText(getApplicationContext(), "Sending", Toast.LENGTH_SHORT).show();
sendBroadcast(intent);
handler.postDelayed(this, 1000);
}
};
handler.postDelayed(r, 1000);*/
}
public void onProviderDisabled(String provider) {
}
public void onProviderEnabled(String provider) {
}
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}
LocationListener[] mLocationListeners = new LocationListener[] {
new LocationListener(LocationManager.GPS_PROVIDER),
new LocationListener(LocationManager.NETWORK_PROVIDER)
};
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
late = intent.getDoubleExtra("lat", 0);
longe = intent.getDoubleExtra("long", 0);
dis = intent.getIntExtra("dis", 0);
loc = intent.getStringExtra("loc");
Toast.makeText(getApplicationContext(), "Destination Set to: "+loc+
" and Minimum Distance: "+
String.valueOf(dis) , Toast.LENGTH_SHORT).show();
return START_STICKY;
}
#Override
public void onCreate() {
initializeLocationManager();
try {
mLocationManager.requestLocationUpdates(
LocationManager.NETWORK_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
mLocationListeners[1]);
} catch (java.lang.SecurityException ex) {
} catch (IllegalArgumentException ex) {
}
try {
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, LOCATION_INTERVAL, LOCATION_DISTANCE,
mLocationListeners[0]);
} catch (java.lang.SecurityException ex) {
} catch (IllegalArgumentException ex) {
}
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(getApplicationContext(), "Service Destroyed", Toast.LENGTH_SHORT).show();
if (mLocationManager != null) {
for (int i = 0; i < mLocationListeners.length; i++) {
try {
mLocationManager.removeUpdates(mLocationListeners[i]);
} catch (Exception ex) {
}
}
}
}
private void initializeLocationManager() {
if (mLocationManager == null) {
mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
}
}
and my AlarmReceiver class is
public class AlarmReceiver extends Activity {
private MediaPlayer mMediaPlayer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.alarmreceiver);
Button stopAlarm = (Button) findViewById(R.id.stopAlarm);
stopAlarm.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View arg0, MotionEvent arg1) {
stopService(new Intent(AlarmReceiver.this, CheckDestinationService.class));
mMediaPlayer.stop();
finish();
return false;
}
});
playSound(this, getAlarmUri());
}
private void playSound(Context context, Uri alert) {
mMediaPlayer = new MediaPlayer();
try {
mMediaPlayer.setDataSource(context, alert);
final AudioManager audioManager = (AudioManager) context
.getSystemService(Context.AUDIO_SERVICE);
if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mMediaPlayer.prepare();
mMediaPlayer.start();
}
} catch (IOException e) {
System.out.println("OOPS");
}
}
//Get an alarm sound. Try for an alarm. If none set, try notification,
//Otherwise, ringtone.
private Uri getAlarmUri() {
Uri alert = RingtoneManager
.getDefaultUri(RingtoneManager.TYPE_ALARM);
if (alert == null) {
alert = RingtoneManager
.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
if (alert == null) {
alert = RingtoneManager
.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
}
}
return alert;
}
#Override
public void onBackPressed() {
//MainActivity.iMinDistance = 0;
stopService(new Intent(AlarmReceiver.this, CheckDestinationService.class));
mMediaPlayer.stop();
finish();
}
}
I tested AlarmReceiver class from other activites and it worked properly
but it not working from the service.
please help!!
initalize Calendar
calender = Calendar.getInstance()