How to access existing AppBarButton and disable it - windows

Is there a way to access an existing AppBarButton and disable it programmatically when I'm on a specific page other than the MainPage?
<CommandBar Grid.Row="0">
<CommandBar.Content>
<Button
Style="{StaticResource NavigationBackButtonNormalStyle}"
Name="BackButton"
VerticalAlignment="Top"
Click="Back_Click"/>
</CommandBar.Content>
<AppBarButton Icon="Mail" Name="ContactUs"/>
</CommandBar>
Update
Main Page
public sealed partial class MainPage : Page
{
public static AppBarButton MyAppBarButton;
public MainPage()
{
this.InitializeComponent();
Current = this;
Frame_Main.Navigate(typeof(Frame1));
MyAppBarButton = AppBarButtonSettings;
}
public static MainPage Current;
private void Back_Click(object sender, RoutedEventArgs e)
{
On_BackRequested();
}
private bool On_BackRequested()
{
if (Frame_Main.CanGoBack)
{
Frame_Main.GoBack();
return true;
}
return false;
}
private void BackInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
{
On_BackRequested();
args.Handled = true;
}
private void AppBarButtonContactUs_Click(object sender, RoutedEventArgs e)
{
Frame_Main.Navigate(typeof(ContactUs));
}
}
Contact Us page
public sealed partial class ContactUs: Page
{
public ContactUs()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
MainPage.Current.BackButton.Visibility = Visibility.Visible;
MainPage.Current.BackButton.IsEnabled = true;
MainPage.MyAppBarButton.IsEnabled = false;
}
}

Sure, derive from your code, you could access AppBarButton with name in the code behind. for example:
private void Btn_Click(object sender, RoutedEventArgs e)
{
ContactUs.IsEnabled = false;
}
Update
You could make static AppBarButton to record ContactUs and access with the page class name.
public static AppBarButton MyAppBarButton;
public TestPage()
{
this.InitializeComponent();
MyAppBarButton = ContactUs;
}
Usage
TestPage.MyAppBarButton.IsEnabled = false;

Related

Set binding value as a parameter on a behavior from another control value in Xamarin Forms

I am trying to validate a entry value using the entry behaviors. In order to do that I need to pass the value to behavior class from another control in the same xaml.
I have below two controls
<Entry
x:Name="RegisterQty"
Grid.Column="0"
WidthRequest="120"
TextChanged="RegisterQty_TextChanged"
TextColor="Black"
HorizontalOptions="Start"
VerticalOptions="Center"
FontAttributes="Bold"
PlaceholderColor="Black"
Keyboard="Numeric"
FontSize="20">
<Entry.Behaviors>
<local:RegisterQtyBehavior LoadQty = "{Binding BindingContext.qty, Source={x:Reference RegisterQty}} "/>
</Entry.Behaviors>
</Entry>
public class RegisterQtyBehavior : Behavior<Entry>
{
public static readonly BindableProperty LoadQtyProperty = BindableProperty.Create(nameof(LoadQty), typeof(double), typeof(RegisterQtyBehavior), 0);
public double LoadQty
{
get { return (double)GetValue(LoadQtyProperty); }
set { SetValue(LoadQtyProperty, value); }
}
protected override void OnAttachedTo(Entry entry)
{
entry.TextChanged += OnEntryTextChanged;
base.OnAttachedTo(entry);
}
protected override void OnDetachingFrom(Entry entry)
{
entry.TextChanged -= OnEntryTextChanged;
base.OnDetachingFrom(entry);
}
void OnEntryTextChanged(object sender, TextChangedEventArgs args)
{
double result = LoadQty;
bool isValid = double.TryParse(args.NewTextValue, out result);
((Entry)sender).TextColor = isValid ? Color.Red : Color.Default;
}
}
I want to pass label binding Qty to entry control. How could i achieve this? Adding directly LoadQty = "{Binding Qty}"
does not work.
According to your description, you want to parameter in entry behaviors using binding, am I right? if yes, I do one sample you can take a look:
<Entry x:Name="registerqty">
<Entry.Behaviors>
<local:RegisterQtyBehavior LoadQty="{Binding BindingContext.qty, Source={x:Reference registerqty}}}" />
</Entry.Behaviors>
</Entry>
public partial class Page37 : ContentPage, INotifyPropertyChanged
{
private int _qty;
public int qty
{
get { return _qty; }
set
{
_qty = value;
RaisePropertyChanged("qty");
}
}
public Page37 ()
{
InitializeComponent ();
qty = 100;
this.BindingContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class RegisterQtyBehavior:Behavior<Entry>
{
public static readonly BindableProperty LoadQtyProperty = BindableProperty.Create("LoadQty", typeof(int), typeof(RegisterQtyBehavior), defaultValue: 0);
public int LoadQty
{
get { return (int)GetValue(LoadQtyProperty); }
set
{
SetValue(LoadQtyProperty,value);
}
}
protected override void OnAttachedTo(Entry entry)
{
entry.TextChanged += OnEntryTextChanged;
base.OnAttachedTo(entry);
}
protected override void OnDetachingFrom(Entry entry)
{
entry.TextChanged -= OnEntryTextChanged;
base.OnDetachingFrom(entry);
}
void OnEntryTextChanged(object sender, TextChangedEventArgs args)
{
//double result;
//bool isValid = double.TryParse(args.NewTextValue, out result);
//((Entry)sender).TextColor = isValid ? Color.Default : Color.Red;
if(!string.IsNullOrEmpty(args.NewTextValue))
{
if (Convert.ToInt32(args.NewTextValue) > LoadQty)
{
((Entry)sender).TextColor = Color.Red;
}
else
{
((Entry)sender).TextColor = Color.Default;
}
}
}
}

Xamarin Forms Button Command doesn't fire after adding button effect

I have a button like this:
<Button Margin="0,20,0,0" Command="{Binding OnSkip}" BackgroundColor="{StaticResource Primary}" CornerRadius="2"
Text="Terms and Conditions of Use" VerticalOptions="End" TextColor="White">
<Button.Effects>
<effects1:ButtonClickEffect></effects1:ButtonClickEffect>
</Button.Effects>
</Button>
Upon adding the button effect inside the button, the 'OnSkip' command no longer fires and I'm not sure why.
The button click effect code is implemented as follows:
public class AndroidButtonClickEffect : PlatformEffect
{
protected override void OnAttached()
{
this.Control.Touch += this.Control_Touch;
}
private void Control_Touch(object sender, Android.Views.View.TouchEventArgs e)
{
if (e.Event.Action == MotionEventActions.Down)
{
this.SetColor(Android.Graphics.Color.Blue);
}
else if (e.Event.Action == MotionEventActions.Up)
{
this.SetColor(Android.Graphics.Color.LightBlue);
}
}
private void SetColor(Android.Graphics.Color color)
{
this.Control.SetBackgroundColor(color);
}
protected override void OnDetached()
{
this.Control.Touch -= this.Control_Touch;
}
}
Removing the button effect causes the command to fire again. Why does the button effect interfere with the command firing? Is there a way I can get the effect to invoke the desired command (generically so I can reuse the effect)?
Thanks.
In the main project, I added the following class, which binds the Command:
public class ButtonClickEffect : RoutingEffect
{
public ButtonClickEffect() : base("Framework.ButtonClickEffect") { }
public static readonly BindableProperty CommandProperty =
BindableProperty.Create("Command", typeof(ICommand), typeof(ButtonClickEffect));
public static ICommand GetCommand(BindableObject view)
{
return (ICommand)view.GetValue(CommandProperty);
}
public static void SetCommand(BindableObject view, ICommand value)
{
view.SetValue(CommandProperty, value);
}
public static readonly BindableProperty CommandParameterProperty =
BindableProperty.CreateAttached("CommandParameter", typeof(object),
typeof(ButtonClickEffect), (object)null);
public static object GetCommandParameter(BindableObject view)
{
return view.GetValue(CommandParameterProperty);
}
public static void SetCommandParameter(BindableObject view, object value)
{
view.SetValue(CommandParameterProperty, value);
}
}
The Android implementation was implemented as follows:
[assembly:ResolutionGroupName("Framework")]
[assembly:ExportEffect(typeof(AndroidButtonClickEffect), "ButtonClickEffect")]
namespace Framework.Droid.Effects
{
public class AndroidButtonClickEffect : PlatformEffect
{
protected override void OnAttached()
{
Control.Touch += Control_Touch;
}
private void Control_Touch(object sender, Android.Views.View.TouchEventArgs e)
{
if (e.Event.Action == MotionEventActions.Down)
{
SetColor(Color.LightBlue);
}
else if (e.Event.Action == MotionEventActions.Up)
{
SetColor(Color.Blue);
}
var command = ButtonClickEffect.GetCommand(Element);
command?.Execute(ButtonClickEffect.GetCommandParameter(Element));
}
private void SetColor(Color color)
{
Control.SetBackgroundColor(color);
}
protected override void OnDetached()
{
Control.Touch -= Control_Touch;
}
}
}
I then removed the 'Command' property from my button and replaced it as follows:
<Button Margin="0,20,0,0" BackgroundColor="{StaticResource Primary}" CornerRadius="2"
Text="Terms and Conditions of Use" VerticalOptions="End" TextColor="White"
effects1:ButtonClickEffect.Command="{Binding OnSkip}" effects1:ButtonClickEffect.CommandParameter="{Binding .}">
<Button.Effects>
<effects1:ButtonClickEffect></effects1:ButtonClickEffect>
</Button.Effects>
</Button>
In all honesty, the command binding is a lot more awkward now (all this code just to get a simple button effect), but the important thing is that it now works. Now I need to work out how implement for iOS.
Credit from here for the answer and whoever posted this URL as an answer (it got deleted).

My UI did not response for orientation change

I am developing a native mobile app for all platforms. I have created my own theme content page. Then after deployment on android when I make phone landscape it did not respond. what's the reason here.
Here is my base content page.
public abstract class BaseContentPage : ContentPage
{
public readonly BaseViewModel BaseViewModel;
protected bool _isNavigated = false;
public BaseContentPage(BaseViewModel baseViewModel)
{
BaseViewModel = baseViewModel;
}
public abstract void Navigate(SelectedItemChangedEventArgs e);
protected abstract override void OnAppearing();
protected override void OnDisappearing()
{
_isNavigated = true;
}
public BaseContentPage()
{
}
}
here Xaml
<views:BaseContentPage
xmlns:views="clr-namespace:DipsDemoXaml.Views"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:Resource="clr-namespace:DipsDemoXaml.Resources"
x:Class="DipsDemoXaml.Views.WardListPage" Title="{x:Static Resource:AppResources.WardListPageTitle}">
<StackLayout BackgroundColor="{StaticResource DefaultBackgroundColor}" Orientation="Vertical" x:Name="s1">
I even try this also in code behind constructor I call size changed and create a method called Wardpagesizechanged.
public WardListPage(WardListPageViewModel wardListViewModel) : base(wardListViewModel)
{
InitializeComponent();
this.SizeChanged += wardpagesizechanged;
}
Wardpagesizechanged method
private void wardpagesizechanged(object sender, EventArgs e)
{
if(this.Width> this.Height)
{
s1.Orientation = StackOrientation.Horizontal;
}
else
{
s1.Orientation = StackOrientation.Vertical;
}
}
what is the problem here, I am clueless

How can I share the value of a field between back-end C# and a renderer?

My C# looks like this:
public App()
{
InitializeComponent();
MainPage = new Japanese.MainPage();
}
public partial class MainPage : TabbedPage
{
public MainPage()
{
InitializeComponent();
var phrasesPage = new NavigationPage(new PhrasesPage())
{
Title = "Play",
Icon = "ionicons-2-0-1-ios-play-outline-25.png"
};
public partial class PhrasesPage : ContentPage
{
public PhrasesFrame phrasesFrame;
public PhrasesPage()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
App.phrasesPage = this;
}
protected override void OnAppearing()
{
base.OnAppearing();
App.dataChange = true;
phrasesFrame = new PhrasesFrame(this);
phrasesStackLayout.Children.Add(phrasesFrame);
}
public partial class PhrasesFrame : Frame
{
private async Task ShowCard()
{
if (pauseCard == false)
..
and I have an iOS renderer for a tab page
public class TabbedPageRenderer : TabbedRenderer
{
private MainPage _page;
private void OnTabBarReselected(object sender, UITabBarSelectionEventArgs e)
{
...
pauseCard = false;
...
My problem is there is no connection between the two and I would like to know how I can make it so that pauseCard could be set in one place and read in another.
Here is a simple custom Entry example using a bindable bool property that gets changed from the renderer every time the text changes in the entry.
Entry subclass w/ a bindable property called OnOff (bool)
public class CustomPropertyEntry : Entry
{
public static readonly BindableProperty OnOffProperty = BindableProperty.Create(
propertyName: "OnOff",
returnType: typeof(bool),
declaringType: typeof(CustomPropertyEntry),
defaultValue: false);
public bool OnOff
{
get { return (bool)GetValue(OnOffProperty); }
set { SetValue(OnOffProperty, value); }
}
}
iOS Renderer
Note: I keep a reference to the instance of the CustomPropertyEntry passed into OnElementChanged so later I can set its custom property when needed.
public class CustomPropertyEntryRenderer : ViewRenderer<CustomPropertyEntry, UITextField>
{
UITextField textField;
CustomPropertyEntry entry;
protected override void OnElementChanged(ElementChangedEventArgs<CustomPropertyEntry> e)
{
base.OnElementChanged(e);
if (Control == null)
{
textField = new UITextField();
SetNativeControl(textField);
}
if (e.OldElement != null)
{
textField.RemoveTarget(EditChangedHandler, UIControlEvent.EditingChanged);
entry = null;
}
if (e.NewElement != null)
{
textField.AddTarget(EditChangedHandler, UIControlEvent.EditingChanged);
entry = e.NewElement;
}
}
void EditChangedHandler(object sender, EventArgs e)
{
entry.OnOff = !entry.OnOff;
}
}
XAML Example:
<local:CustomPropertyEntry x:Name="customEntry" Text="" />
<Switch BindingContext="{x:Reference customEntry}" IsToggled="{Binding OnOff}" />

Xamarin Forms Password and Confirm Password Validation

I have a Xamarin Forms application in which I have a registration form in which I need to validate Password and Confirm Password fields should be same.
Is there any way to implement this using Xamarin Behaviour?
I have already implemented Xamarin Behaviour for Required Field validation and Email Regex validation like this below-
public class RequiredValidatorBehavior : Behavior<Entry>
{
static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly("IsValid", typeof(bool), typeof(RequiredValidatorBehavior), false);
static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty;
public bool IsValid
{
get { return (bool)base.GetValue(IsValidProperty); }
private set { base.SetValue(IsValidPropertyKey, value); }
}
protected override void OnAttachedTo(Entry bindable)
{
bindable.Unfocused += HandleFocusChanged;
base.OnAttachedTo(bindable);
}
protected override void OnDetachingFrom(Entry bindable)
{
bindable.Unfocused -= HandleFocusChanged;
base.OnDetachingFrom(bindable);
}
void HandleFocusChanged(object sender, FocusEventArgs e)
{
IsValid = !string.IsNullOrEmpty (((Entry)sender).Text);
}
}
Implementation of Behaviour in XAML Content Page-
<Entry x:Name="password" Placeholder="New Password">
<Entry.Behaviors>
<local:RequiredValidatorBehavior x:Name="passwordValidator"/>
</Entry.Behaviors>
</Entry>
The problem is - I am new in Xamarin development and have no idea how can I get the value of both Password and Confirm Password fields in Behaviour so that I can compare them. I do not wish to compare them on click of button when the form is submitted, fields should be compared while the user is typing in the fields. Any code, help or guidance is appreciable.
https://forums.xamarin.com/discussion/34695/xaml-how-do-you-pass-a-control-view-reference-into-a-behavior
This will help you.
You will use Compare Validator behavior for this as following.
<behaviors:CompareValidator x:Name="ComparePasswordsValidator"
CompareToEntry="{Binding Source={x:Reference PasswordEntry}}" />
Finally The Solution:
XAML-
<Entry x:Name="password" Placeholder="New Password" IsPassword="true">
<Entry.Behaviors>
<local:RequiredValidatorBehavior x:Name="passwordValidator"/>
</Entry.Behaviors>
</Entry>
<Entry x:Name="confirmPassword" Placeholder="Confirm Password" IsPassword="true">
<Entry.Behaviors>
<local:ConfirmPasswordBehavior x:Name="confirmPasswordBehavior" CompareToEntry="{Binding Source={x:Reference password}}" />
</Entry.Behaviors>
</Entry>
BEHAVIOR-
public class ConfirmPasswordBehavior : Behavior<Entry>
{
static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly("IsValid", typeof(bool), typeof(ConfirmPasswordBehavior), false);
public static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty;
public static readonly BindableProperty CompareToEntryProperty = BindableProperty.Create("CompareToEntry", typeof(Entry), typeof(ConfirmPasswordBehavior), null);
public Entry CompareToEntry
{
get { return (Entry)base.GetValue(CompareToEntryProperty); }
set { base.SetValue(CompareToEntryProperty, value); }
}
public bool IsValid
{
get { return (bool)base.GetValue(IsValidProperty); }
private set { base.SetValue(IsValidPropertyKey, value); }
}
protected override void OnAttachedTo(Entry bindable)
{
bindable.TextChanged += HandleTextChanged;
base.OnAttachedTo(bindable);
}
protected override void OnDetachingFrom(Entry bindable)
{
bindable.TextChanged -= HandleTextChanged;
base.OnDetachingFrom(bindable);
}
void HandleTextChanged(object sender, TextChangedEventArgs e)
{
var password = CompareToEntry.Text;
var confirmPassword = e.NewTextValue;
IsValid = password.Equals (confirmPassword);
}
}
I've make some changes on Punnet answer:
First, to fix the null exception on HandleTextChanged that was thrown when the comparable string was null
void HandleTextChanged(object sender, TextChangedEventArgs e)
{
string theBase = CompareToEntry.Text;
string confirmation = e.NewTextValue;
// here is the change
IsValid = (bool)theBase?.Equals(confirmation);
((Entry)sender).TextColor = IsValid ? Color.Green : Color.Red;
}
And the second was to check if the comparable string was changed after the validation becomes true.
void baseValue_changed(object sender, TextChangedEventArgs e)
{
IsValid = (bool)((Entry)sender).Text?.Equals(thisEntry.Text);
thisEntry.TextColor = IsValid ? Color.Green : Color.Red;
}
So the new code become
public class ComparisonBehavior : Behavior<Entry>
{
private Entry thisEntry;
static readonly BindablePropertyKey IsValidPropertyKey = BindableProperty.CreateReadOnly("IsValid", typeof(bool), typeof(ComparisonBehavior), false);
public static readonly BindableProperty IsValidProperty = IsValidPropertyKey.BindableProperty;
public static readonly BindableProperty CompareToEntryProperty = BindableProperty.Create("CompareToEntry", typeof(Entry), typeof(ComparisonBehavior), null);
public Entry CompareToEntry
{
get { return (Entry)base.GetValue(CompareToEntryProperty); }
set
{
base.SetValue(CompareToEntryProperty, value);
if (CompareToEntry != null)
CompareToEntry.TextChanged -= baseValue_changed;
value.TextChanged += baseValue_changed;
}
}
void baseValue_changed(object sender, TextChangedEventArgs e)
{
IsValid = ((Entry)sender).Text.Equals(thisEntry.Text);
thisEntry.TextColor = IsValid ? Color.Green : Color.Red;
}
public bool IsValid
{
get { return (bool)base.GetValue(IsValidProperty); }
private set { base.SetValue(IsValidPropertyKey, value); }
}
protected override void OnAttachedTo(Entry bindable)
{
thisEntry = bindable;
if (CompareToEntry != null)
CompareToEntry.TextChanged += baseValue_changed;
bindable.TextChanged += HandleTextChanged;
base.OnAttachedTo(bindable);
}
protected override void OnDetachingFrom(Entry bindable)
{
bindable.TextChanged -= HandleTextChanged;
if (CompareToEntry != null)
CompareToEntry.TextChanged -= baseValue_changed;
base.OnDetachingFrom(bindable);
}
void HandleTextChanged(object sender, TextChangedEventArgs e)
{
string theBase = CompareToEntry.Text;
string confirmation = e.NewTextValue;
IsValid = (bool)theBase?.Equals(confirmation);
((Entry)sender).TextColor = IsValid ? Color.Green : Color.Red;
}
}
I have developed custom control to validate our model using data annotation method.
Here is project url.
https://github.com/MaulikParmar/XamarinForms/tree/master/ValidationDemo
It is not working for window 8.1 phone.
Here is youtube url for project description and how to use this control more effectively.
https://www.youtube.com/watch?v=eEi-Oky4U08
If you want to add exception handling because of System.InvalidOperationException error is showing when typing confirm password first before typing a password.
void HandleTextChanged(object sender, TextChangedEventArgs e)
{
try
{
string theBase = CompareToEntry.Text;
string confirmation = e.NewTextValue;
IsValid = (bool)theBase?.Equals(confirmation);
((Entry)sender).TextColor = IsValid ? Color.FromHex("#e6a94d")/*correct*/ : Color.FromHex("#CD5C5C")/*incorrect*/;
}
catch (System.InvalidOperationException)
{
string theBase = CompareToEntry.Text;
string confirmation = e.NewTextValue;
((Entry)sender).TextColor = IsValid ? Color.FromHex("#e6a94d")/*correct*/ : Color.FromHex("#CD5C5C")/*incorrect*/;
}
}

Resources