How to use PKPaymentButton in Xamarin.Forms - xamarin.forms

I have a page in Xamarin.Forms in which I have to show PKPaymentButton by using the same PKPaymentButton class which is a child of UIButton in PassKit.
I have written a custom ButtonRenderer and trying to convert the button into PKPayment button.
I got so far that in custom renderer we can change the appearance of a button but can we use something like creating a new button instance in my case PKPaymentButton and replace it with Button.
UPDATE-
I have achieved this by-
public class ApplePayButtonRenderer : Xamarin.Forms.Platform.iOS.ButtonRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
var button = new PKPaymentButton(PKPaymentButtonType.Buy, PKPaymentButtonStyle.Black);
SetNativeControl(button);
}
}
}
Now I am trying to get its click into Xamarin.Forms

You could use Messaging Center to send message when you click the payment Button.
in Custom Renderer
var button = new PKPaymentButton(PKPaymentButtonType.Buy, PKPaymentButtonStyle.Black);
button.TouchUpInside += Button_TouchUpInside;
SetNativeControl(button);
private void Button_TouchUpInside(object sender, EventArgs e)
{
MessagingCenter.Send<Object>(this,"PayButtonClick");
}
in Forms
Add the following code to the constructor of the ContentPage which contains the Payment Button
public xxxPage()
{
InitializeComponent();
MessagingCenter.Subscribe<Object>(this, "PayButtonClick",(args)=> {
//do some thing you want
});
}

Related

custom LabelRenderer shows wrong text style inside list view on scroll on Xamarin iOS

I am working on an App that requires one list view having text labels with NSUnderlineStyle on user deletion.
As per the requirement user have Delete/restore option in detail screen. On delete confirmation the text label should be underline style for that particular cell.
I am using LabelRenderer for NSUnderlineStyle in Xamarin iOS.
But currently ListView displays text Labels with underline style which is not deleted by user on list view scroll. The underline style are swapping from one cell label to another on list view scroll.
Below my sample code.
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (this.Control == null)
{
return;
}
if (this.Element is ExtendedLabel extended)
{
var strikethroughStyle = extended.IsStrikeThrough ? NSUnderlineStyle.Single : NSUnderlineStyle.None;
this.Control.AttributedText = new NSMutableAttributedString(
extended.Text ?? string.Empty,
this.Control.Font,
strikethroughStyle: strikethroughStyle);
}
}
This is the common issue of TableView Cell Resue , tableView will reuse the cell for the visible(inside screen shot) ones , so it would show the previous style .
To solve this we can forcedly set the style each time when the cell is going to display .
Create custom renderer for ListView , and do this in WillDisplay method ,before it we need to override TableView's Delegate.
[assembly: ExportRenderer(typeof(ListView), typeof(MyRenderer))]
namespace FormsApp.iOS
{
public class MyDelegate : UITableViewDelegate
{
List<Model> data;
public MyDelegate(List<Model> _data)
{
data = _data;
}
public override void WillDisplay(UITableView tableView, UITableViewCell cell, NSIndexPath indexPath)
{
var views = cell.ContentView.Subviews;
foreach (var view in views)
{
if(view is LabelRenderer renderer)
{
UILabel label = renderer.Control;
var strikethroughStyle = data[indexPath.Row].YourProperty?NSUnderlineStyle.Single : NSUnderlineStyle.None;
label.AttributedText = new NSMutableAttributedString(
label.Text ?? string.Empty,
label.Font,
strikethroughStyle: strikethroughStyle);
}
}
}
}
public class MyRenderer : ListViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<ListView> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
// Unsubscribe
}
if (e.NewElement != null)
{
IEnumerable<Model> data = (IEnumerable<Model>)Element.ItemsSource;
Control.Delegate = new MyDelegate(data.ToList());
}
}
}
}

C#, Xamarin Forms: No Custom TextChangedEvent Raised on initialization

I'm creating an Xamarin.Forms MVVM App (only using Android) which needs certain buttons to be outlined red, whenever their text property holds a specific value. (Purpose: alert the user to press the button and select a value, which will change the Button Text Property and therefore remove the red outline)
To achieve this I've create the following documents:
A custom button CButton that extents the default Button:
public class CButton : Button
{
// this Hides the Default .Text-Property
public string Text
{
get => base.Text;
set
{
base.Text = value;
TextChangedEvent(this, new EventArgs());
}
}
// The Raised Event
protected virtual void TextChangedEvent(object sender, EventArgs e)
{
EventHandler<EventArgs> handler = TextChanged;
handler(sender, e);
}
public event EventHandler<EventArgs> TextChanged;
}
A custom behavior makes use of the raised TextChangedEvent
public class ButtonValBehavior : Behavior<CButton>
{
protected override void OnAttachedTo(CButton bindable)
{
bindable.TextChanged += HandleTextChanged;
base.OnAttachedTo(bindable);
}
void HandleTextChanged(object sender, EventArgs e)
{
string forbidden = "hh:mm|dd.mm.yyyy";
if (forbidden.Contains((sender as CButton).Text.ToLower()))
{
//Do when Button Text = "hh:mm" || "dd.mm.yyyy"
(sender as CButton).BorderColor = Color.Gray;
}
else
{
//Do whenever Button.Text is any other value
(sender as CButton).BorderColor = Color.FromHex("#d10f32");
}
}
protected override void OnDetachingFrom(CButton bindable)
{
bindable.TextChanged -= HandleTextChanged;
base.OnDetachingFrom(bindable);
}
}
The relevant parts of the ViewModel look the following:
public class VM_DIVI : VM_Base
{
public VM_DIVI(O_BasisProtokoll base)
{
Base = base;
}
private O_BasisProtokoll _base = null;
public O_BasisProtokoll Base
{
get => _base;
set
{
_base = value;
OnPropertyChanged();
}
}
Command _datePopCommand;
public Command DatePopCommand
{
get
{
return _datePopCommand ?? (_datePopCommand = new Command(param => ExecuteDatePopCommand(param)));
}
}
void ExecuteDatePopCommand(object param)
{
//launch popup
var p = new PP_DatePicker(param);
PopupNavigation.Instance.PushAsync(p);
}
}
The .xmal looks the following (b is the xmlns of the Namespace):
<b:CButton x:Name="BTN_ED_Datum"
Text="{Binding Base.ED_datum, Mode=TwoWay}"
Grid.Column="1"
Command="{Binding DatePopCommand}"
CommandParameter="{x:Reference BTN_ED_Datum}">
<b:CButton.Behaviors>
<b:ButtonValBehavior/>
</b:CButton.Behaviors>
</b:CButton>
This solution works fine whenever the input is caused by user interaction. However, when a Value is assigned during the initialization of the Page no red outline is created, in fact the TextChangedEvent isn't raised. By using breakpoints I noticed that during initialization the Text Property of CButton is never set, eventhough it actually will be in the view.
Despite fiddling around with my solution I cannot make this work on initialization. I tried to work around this issue by outlining every button by default in their constructor, however this will outline every button red, even when their text value doesn't require them to be.
How can I achieve my initial goal?
Many thanks in advance!
It's been a while but if I recall correctly what I ended up doing was:
Changing the new Text-Property of my custom Button to CText and
Making sure that I have Mode=TwoWay activated for any Element, that doesn't have it enabled by default. (Look up Binding modes on msdn for more)
making CText a bindable property of CButton
My custom button now looks the following:
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace EORG_Anton.Model
{
public class CButton : Button
{
public static readonly BindableProperty CTextProperty =
BindableProperty.Create(nameof(CText),
typeof(string),
typeof(CButton),
default(string),
BindingMode.TwoWay,
propertyChanged: OnTextChanged);
private static void OnTextChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (CButton)bindable;
var value = (string)newValue;
control.CText = value;
}
public string CText
{
get => base.Text;
set
{
base.Text = value;
TextChangedEvent(this, new EventArgs());
}
}
protected virtual void TextChangedEvent(object sender, EventArgs e)
{
EventHandler<EventArgs> handler = TextChanged;
handler(sender, e);
}
public event EventHandler<EventArgs> TextChanged;
}
}

how to extend all contentpages using pagerenderer in UWP?

I would like to extend all the contentpages in my xamarin.forms app with a native view in UWP. I can basically go to each and every page and embed a native view but i dont want this. I want to know if there is a way to do it using a pagerenderer. I tried doing like below.
my idea was to get current page rendering and extend the content with native view and stacklayout and define app.content again with this change. It works in general. If you run the small test project below, you can see that native UWP FontIcons are displayed for each page but there is a problem, if i navigate same page 2 times in MasterDetail in the attached project, page becomes blank. Why is this happening?
and is the approach below best for my case? I am open for alternative solutions.
[assembly: ExportRenderer(typeof(ContentPage), typeof(App3.UWP.ContentPageRenderer))]
namespace App3.UWP
{
public class ContentPageRenderer : PageRenderer
{
bool isDisposing = false;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Page> e)
{
base.OnElementChanged(e);
if (isDisposing)
return;
if (e.OldElement != null || Element == null)
{
return;
}
ContentPage page = ((ContentPage)Element);
if (page.Content == null)
return;
var XboxControls = new MyUserControl1();
StackLayout stackLayout = new StackLayout() { Orientation = StackOrientation.Vertical };
stackLayout.Children.Add(page.Content);
stackLayout.Children.Add(XboxControls.ToView());
page.Content = stackLayout;
}
protected override Windows.Foundation.Size ArrangeOverride(Windows.Foundation.Size finalSize)
{
return base.ArrangeOverride(finalSize);
}
protected override void Dispose(bool disposing)
{
isDisposing = disposing;
base.Dispose(disposing);
}
}
Test Project

Xamarin forms check if keyboard is open or not

Is there any way to check if keyboard is open or not in Xamarin Forms? Are there any events getting fired when the keyboard opens or closes? If so, where can I find an example of it?
I don't believe that there's a Xamarin.Forms way of doing it. Anyway, for the different platforms (at least Android and iOS) there is a way to achieve what you want.
Android
Under android there is InputMethodManager class. You can obtain it from your activity
var inputMethodManager = (InputMethodManager)this.GetSystemService(Context.InputMethodService);
Now you can check if the keyboard is shown with
var keyboardIsShown = inputMethodManager.IsAcceptingText;
According to this article on CodeProject you can use a class derived from IOnGlobalLayoutListener to listen to global layout events. When this event has fired, you can use the code above to check, if the layout has been changed due to the keyboard popping up.
iOS
Under iOS you may use UIKeyboard class which allows you to observe the DidShowNotification (see here).
notification = UIKeyboard.Notifications.ObserveDidShow ((sender, args) => {
Debug.WriteLine("Keyboard is shown.");
// whatever
});
similarly you can observe DidHideNotification (and some others - see here).
Xamarin.Forms
To implement the keyboard-notification in your Xamarin.Forms the easiest way will be to implement platform dependencies which are resolved with the DependencyService. To do this, you'll first have to introduce an interface for the platform service.
public interface IKeyboardService
{
event EventHandler KeyboardIsShown;
event EventHandler KeyboardIsHidden;
}
In your platform specific projects you'll have to implement the functionality in a platform specific way. See the following code section for iOS implementation
[assembly: Xamarin.Forms.Dependency(typeof(Your.iOS.Namespace.KeyboardService))]
namespace Your.iOS.Namespace
{
public class KeyboardService : IKeyboardService
{
public event EventHandler KeyboardIsShown;
public event EventHandler KeyboardIsHidden;
public KeyboardService()
{
SubscribeEvents();
}
private void SubscribeEvents()
{
UIKeyboard.Notifications.ObserveDidShow(OnKeyboardDidShow);
UIKeyboard.Notifications.ObserveDidHode(OnKeyboardDidHide);
}
private void OnKeyboardDidShow(object sender, EventArgs e)
{
KeyboardIsShown?.Invoke(this, EventArgs.Empty);
}
private void OnKeyboardDidHide(object sender, EventArgs e)
{
KeyboardIsHidden?.Invoke(this, EventArgs.Empty);
}
}
}
The Xamarin.Forms.Dependency makes the class visible to the DependencyService. See the following code for Android implementation
[assembly: Xamarin.Forms.Dependency(typeof(Your.Android.Namespace.KeyboardService))]
namespace Your.Android.Namespace
{
public class KeyboardService : IKeyboardService
{
public event EventHandler KeyboardIsShown;
public event EventHandler KeyboardIsHidden;
private InputMethodManager inputMethodManager;
private bool wasShown = false;
public KeyboardService()
{
GetInputMethodManager();
SubscribeEvents();
}
public void OnGlobalLayout(object sender, EventArgs args)
{
GetInputMethodManager();
if(!wasShown && IsCurrentlyShown())
{
KeyboardIsShown?.Invoke(this, EventArgs.Empty);
wasShown = true;
}
else if(wasShown && !IsCurrentlyShown())
{
KeyboardIsHidden?.Invoke(this, EventArgs.Empty);
wasShown = false;
}
}
private bool IsCurrentlyShown()
{
return inputMethodManager.IsAcceptingText;
}
private void GetInputMethodManager()
{
if (inputMethodManager == null || inputMethodManager.Handle == IntPtr.Zero)
{
inputMethodManager = (InputMethodManager)this.GetSystemService(Context.InputMethodService);
}
}
private void SubscribeEvents()
{
((Activity)Xamarin.Forms.Forms.Context).Window.DecorView.ViewTreeObserver.GlobalLayout += this.OnGlobalLayout;
}
}
}
In your Xamarin.Forms app you can now obtain an instance of the correct implementation of IKeyboardService with
var keyboardService = Xamarin.Forms.DependencyService.Get<IKeyboardService>();
In Xamarin Forms in ANDROID CODE change
(InputMethodManager)this.GetSystemService(Context.InputMethodService);
with
(InputMethodManager)Xamarin.Forms.Forms.Context.GetSystemService(Context.InputMethodService);
You need to change:
var inputMethodManager = (InputMethodManager)this.GetSystemService(Context.InputMethodService);
To:
InputMethodManager inputMethodManager = (InputMethodManager)((Activity)Android.App.Application.Context).GetSystemService(Context.InputMethodService);

How to keep button enabled after closing the form

I'm trying to make a system and I'm having trouble with buttons being disabled.
I have a function that makes the button on a another form enable the button on the main form but whenever I get back to the main form the button becomes disabled again.
How do I keep this permanent even after closing the program? Can I save it in a database to keep its function enabled even if its default is disabled?
Here's the picture of what it looks like:
Thanks for the help.
Take two buttons - "button1" and "button2" on "MainForm" Form.
Set property Enabled=false for "button1"
MainForm.cs
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
Form2 oFrm2 = new Form2();
oFrm2.evtFrm += new ShowFrm(oFrm2_evtFrm);
oFrm2.Show();
}
void oFrm2_evtFrm()
{
button1.Enabled = true;
}
}
Take one button - "button1" on "Form2" Form.
Form2.cs
public delegate void ShowFrm();
public partial class Form2 : Form
{
public event ShowFrm evtFrm;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (evtFrm != null)
{
evtFrm();
}
}
}
MainForm will display first.
Click on "button2" to display "Form2".
On "Form2", click on "button1" to make enable "button1" of "MainForm"
If you want to make "button1" enable permanent, you have to store value - "button1" is enable or disable.

Resources