Time Need to validate for timepicker in xamarin forms - xamarin.forms

I need to validate a selected time from the time picker. So if the selected time is not valid then I need to display a toast message.
Which event will trigger if time will select from the time picker?
And I don't want to bind the time if the selected time is not valid based on my condition.
XAML Code:
<controls:DatePickerCustom FontSize="14" HeightRequest="35" Date="{Binding CustomDate,Mode=TwoWay}" MaximumDate="{Binding MaximumDate}" FontFamily="Segoe UI" Format="D" IsEnabled="{Binding IsDatePickerEnable}">
<DatePicker.Triggers>
<DataTrigger TargetType="DatePicker" Binding="{Binding IsCustomSelected}" Value="true">
<Setter Property="TextColor" Value="{DynamicResource HeadingTextColor}" />
<Setter Property="TextColor" Value="{DynamicResource HeadingTextColor}" />
</DataTrigger>
</DatePicker.Triggers>
</controls:DatePickerCustom>

Handle this in your "setter" for property CustomDate.
In a setter, the new value is value. If value isn't valid, Show the toast message. Return from setter, without changing the internal field that holds the value, and without calling OnPropertyChanged.
If you need more information, please show the code that declares property CustomDate.
It that property is currently an "auto-property", convert it to a "full-property" - this will have a "backing field", and gives you a place to do the test, and reject the change.

You could listen the PropertyChanged event of TimePicker,then match the Time property.
For example:
<TimePicker PropertyChanged="TimePicker_PropertyChanged"></TimePicker>
private void TimePicker_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
TimePicker timePicker = sender as TimePicker;
if (e.PropertyName.Equals("Time") )
{
var time = timePicker.Time;
if (time.Minutes == 10) // your condition
{
}
else
{
DisplayAlert("Warning", "This is a validate time", "Cancel");
}
}
}

Related

How to display two text boxes as pop up using DisplayPromptAsync method in xamarin?

When I use -
string result = await DisplayPromptAsync("Question 1", "What's your name?");
It shows only one textbox in the pop-up. But how to display two or more textboxes in the pop-up?
Any help would be greatly appreciated.
As IvanIčin said that you can use Rg.Plugins.Popup to create custom popup.
Firstly, install Rg.Plugins.Popup bu nuget package..., then creating popup page
<pages:PopupPage
x:Class="FormsSample.popup.popup2"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup">
<pages:PopupPage.Content>
<StackLayout
Padding="20,0"
BackgroundColor="CadetBlue"
HorizontalOptions="FillAndExpand"
VerticalOptions="Center">
<Label Text="Question 1" />
<Label Text="this is one question!" />
<Entry />
<Entry />
<Button
x:Name="btnsub"
Clicked="btnsub_Clicked"
Text="subit" />
</StackLayout>
</pages:PopupPage.Content>
</pages:PopupPage>
public partial class popup2 : PopupPage
{
public popup2()
{
InitializeComponent();
}
private void btnsub_Clicked(object sender, EventArgs e)
{
}
}
To call this Popup Page from contentpage button.click event.
private async void btnPopupButton_Clicked(object sender, EventArgs e)
{
await PopupNavigation.Instance.PushAsync(new popup2());
}
You can see the screenshot:
You can't as it is not intended to. You can create a custom pop-up either by using some pop-up plug-in or by creating your custom code based on the native prompts (similar to what Xamarin.Forms do).
Just for the record having one input field is very generous from Xamarin as the native Android or iOS developers don't have such a prompt with the input field out of the box (though it isn't too hard to create it but still it goes much beyond one line of code).

how to change custom render label textcolor inside list view in xamarin forms

We are developing a small application, we have created dashboard using custom render but I can’t change label text color. it is default showing like lable text color white, list view background color It will come via api so that if it is coming white background then label text color is not able to see. Here I have attached the code below. Give me suggestions to resolve this issue
Menucontrol custom render
public static readonly BindableProperty ItemsSourceProperty =
BindableProperty.Create<MenuControl, IEnumerable>(
view => view.ItemsSource,
null,
BindingMode.TwoWay,
null,
propertyChanged: (bindableObject, oldValue, newValue) =>
{
((MenuControl)bindableObject).ItemsSourceChanged(bindableObject, oldValue, newValue);
}
);
public IEnumerable ItemsSource
{
get
{
return (IEnumerable)GetValue(ItemsSourceProperty);
}
set
{
SetValue(ItemsSourceProperty, value);
}
}
Add a Data Trigger
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor={Binding BGColor}>
<Label TextColor="White">
<Label.Triggers>
<!--(or Value ="White" depends on binding value Xamarin.Color or string) -->
<DataTrigger TargetType="Label" Binding={Binding BGColor} Value="#FFFFFF">
<Setter Property="TextColor" Value="Red"/>
<!--(or your color) -->
</DataTrigger>
</Label.Triggers>
</Label>
</StackLayout>
<ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
So when your BGColor(or any property you bind to color) property is something you think that can clash(for e.g. white) with your text color(e.g. also white) use data triggers. You can create multiple but if there are more than 3 or 4 I would advise you to use converters in that case.

Add element to XAML page whiles in Task.Delay()

I'm building a chatbot app with chat bubbles for incoming and outgoing messages. For the incoming messages, I've given it a Task.Delay() and now I'd like to give it an ActivityIndicator every time before the message pops up (i.e. I want to show the activity indicator whiles the message is being delayed). I've added the activity indicator to the XAML of the incoming messages control;
IncomingMessageItemControl
<ViewCell
x:Class="BluePillApp.Controls.IncomingMessageItemControl"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:pancake="clr-namespace:Xamarin.Forms.PancakeView;assembly=Xamarin.Forms.PancakeView"
mc:Ignorable="d">
<Grid x:Name="Gridoo">
<pancake:PancakeView
Margin="10,10,80,10"
Padding="15"
BackgroundColor="#53ffc6"
CornerRadius="20,20,0,20"
HasShadow="False"
HorizontalOptions="StartAndExpand">
<Label
FontSize="Medium"
Text="{Binding Text}"
TextColor="#1a1a1a" />
</pancake:PancakeView>
<ActivityIndicator IsRunning="True" IsVisible="True" />
</Grid>
</ViewCell>
The problem is, in the ChatbotMessagingPage, the send button is pressed then an outgoing message is sent before getting a reply/incoming message and I've done this in MVVM like so;
ChatbotMessagingPageViewModel
//This gets the chatbots response for each message
chatbot.MainUser.ResponseReceived += async (sender, args) =>
{
await Task.Delay(1500);
Messages.Add(new ChatMessageModel() { Text = args.Response.Text, User = App.ChatBot });
};
}
#region CLASS METHODS
/// <summary>
/// This function sends a message
/// </summary>
public void Send()
{
if (!string.IsNullOrEmpty(TextToSend))
{
var msgModel = new ChatMessageModel() { Text = TextToSend, User = App.User };
//This adds a new message to the messages collection
Messages.Add(msgModel);
var result = chatbot.Evaluate(TextToSend);
result.Invoke();
//Removes the text in the Entry after message is sent
TextToSend = string.Empty;
}
}
Everytime I press the send button the ActivityIndicator comes along with the IncomingMessage, I'd like the ActivityIndicator to come first, whiles the IncomingMessage is being delayed.
I'm guessing that that view cell is the message bubble.
When you do:
Messages.Add(new ChatMessageModel() { Text = args.Response.Text, User = App.ChatBot });
Your collection is updated and your ListView or whatever hold those ViewCelss is also updated. The ActivityIndicator is part of the ViewCell so it comes at the same time as the message.
[OPTION 1] Using an additional flag
What you can do is create a flag IsBusy or IsDelay or something and bind the visibility of the ActivityIndicator and Label to it:
<Grid x:Name="Gridoo">
<pancake:PancakeView
Margin="10,10,80,10"
Padding="15"
BackgroundColor="#53ffc6"
CornerRadius="20,20,0,20"
HasShadow="False"
HorizontalOptions="StartAndExpand">
<Label
FontSize="Medium"
Text="{Binding Text}"
TextColor="#1a1a1a"
IsVisible="{Binding IsBusy, Converter={Helpers:InverseBoolConverter}}""> />
</pancake:PancakeView>
<ActivityIndicator x:Name="activityIndicator" IsRunning="True" IsVisible="{Binding IsBusy}" />
</Grid>
Note that I've used a IValueConverter to negate the value for the label. In case you're not familiar with it, check this
What's left is to add the flag in your ViewModel:
IsBusy = true; // this will make the activity indicator visible, but not the Label
// Also note that you first need to add the message
Messages.Add(new ChatMessageModel() { Text = args.Response.Text, User = App.ChatBot });
await Task.Delay(1500);
IsBusy = false; // this will hige the activity indicator visible, and make Label visible
So basically the logic is the following:
You add the message to your chat BUT the actual text is hidden when on the other hand, the activity indicator is visible.
You apply the delay
Delay ends, you change the visibility of both views.
Note that in my example I've not declared where that flag is since I'm not sure how the rest of your code looks like. It could be added to ChatMessageModel or ChatMessageViewModel since you would need a flag for each message.
[OPTION 2] in IncomingMessageItemControl.xaml.cs
A better solution could be to handle it in the code behind of your control. The issue is the same, the activity indicator and the label comes at the same time.
To fix this you can move the delay in IncomingMessageItemControl.xaml.cs.
First, you need to add x:Name to both the activity indicator and the label.
Then you could do:
private async Task ChangeVisibilityAsync()
{
Label.IsVisibe= false;
ActivityIndicator.IsVisible = true;
await Task.Delay(1500);
Label.IsVisibe = true;
ActivityIndicator.IsVisible = false;
}

Change Xamarin.Forms button clicked colour

I am working on a Xamarin.Forms UWP application and I wanted to change my button's background colour when pressed. I have been searching the web and the most straightforward way I could find is this:
private void Button_OnClicked(object s, EventArgs e)
{
var b = (Button) s;
var originalColour = b.BackgroundColor;
b.BackgroundColor = Color.DarkOrange;
Device.StartTimer(TimeSpan.FromSeconds(0.25), () =>
{
b.BackgroundColor = originalColour;
return false;
});
}
However, personally, I am not liking this approach very much. How can this be done better?
An EventTrigger solution in XAML:
Implement the following in MyAssembly, e.g. the portable assembly containing App.xaml:
using Xamarin.Forms;
namespace MyNamespace
{
public class ButtonTriggerAction : TriggerAction<VisualElement>
{
public Color BackgroundColor { get; set; }
protected override void Invoke(VisualElement visual)
{
var button = visual as Button;
if (button == null) return;
if (BackgroundColor != null) button.BackgroundColor = BackgroundColor;
}
}
}
XAML:
xmlns:local="clr-namespace:MyNamespace;assembly=MyAssembly"
...
<Button Text="EventTrigger">
<Button.Triggers>
<EventTrigger Event="Pressed">
<local:ButtonTriggerAction BackgroundColor="Red" />
</EventTrigger>
<EventTrigger Event="Released">
<local:ButtonTriggerAction BackgroundColor="Default" />
</EventTrigger>
</Button.Triggers>
</Button>
a more natural and cleaner way to do it would be using VisualStateManager
<Button Text="Click Me!">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Green" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Red" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Button>
you can read more about in here.
This is the simplest solution but of course not very clean.
THe problem here is that each platform implements the "pressed" state differently and Xamarin.Forms doesn't have any built-in way how to handle this.
In case of UWP, you have two options. First, you can create a new default button style that will be used throughout your app. You can find the default style here, and just copy it, modify the Pressed VisualState and add is as a default resource:
<Style TargetType="Button">
<!-- ... your style -->
</Style>
However, if the pressed button color should be applied only in some places, you should rather create a new view that derives from button and uses a custom renderer on UWP that applies a custom style in the OnElementChanged event handler:
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (this.Element != null)
{
this.Control.Style = ( Style )Application.Current.Resources["CustomButtonStyle"];
}
}
Other platforms will have similar solutions as well, but you will definitely have to implement them in such platform-specific way, probably using the custom renderers.
For more information on custom renderers see the documentation. You may also find some inspiration in Xamarin.Forms Labs repository.

How add a global "IsReadOnly" style to all DataGridTextColumns

I currently have a ResourceDictionary file for my WPF application, which pretty much adds every style that I could possibly want throughout all of my application's DataGrids.
Except one.
How can I add a global "IsReadOnly" setter, for all of my DataGrid's DataGridTextColumn columns ?
Basically, I use a few DataGrids, and if I want to display read-only data in a particular column, I'll just display the data using a DataGridTextColumn:
<WPFtoolkit:DataGridTextColumn Binding="{Binding Path=DOB,StringFormat='dd/MMM/yyyy'}" Header="DOB" Width="120" />
However, if I have a column which has editable data, then I'll use a DataGridTemplateColumn instead.
<WPFtoolkit:DataGridTemplateColumn xHeader="Department Name" >
<WPFtoolkit:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Width="175"
ItemsSource="{Binding Source={StaticResource AllDepartmentsDataSource}}"
SelectedValue="{Binding DepartmentID}" SelectedValuePath="DepartmentID" DisplayMemberPath="DepartmentName"
VerticalAlignment="Center"
>
</ComboBox>
</DataTemplate>
</WPFtoolkit::DataGridTemplateColumn.CellTemplate>
</tWPFtoolkit:DataGridTemplateColumn>
The problem is, for every one of my DataGridTextColumns, I specifically need to add the IsReadOnly parameter, otherwise the user can (incorrectly) edit that data:
<WPFtoolkit:DataGridTextColumn IsReadOnly="True" Binding="{Binding Path=DOB,StringFormat='dd/MMM/yyyy'}" Header="DOB" Width="120" />
Is there a way to add this "IsReadOnly" setting globally, in the ResourceDictionary file, to all of my DataGridTextColumns...?
I can add global styles to DataGrid, DataGridColumnHeader, DataGridRow, and DataGridCell, but if I try to define a style with a TargetType of DataGridTextColumn, then Visual Studio complains that DataGridTextColumn is not derived from a FrameworkElement or FrameworkContentElement.
<Style TargetType="{x:Type WPFToolkit:DataGridTextColumn}">
<Setter Property="IsReadOnly" Value="True"/>
</Style>
I can add IsReadOnly to the Grid style, but this makes all columns uneditable !
Can anyone think of an quick and easy way to add this simple property to the DataGridTextColumns ?
Update:
My solution has been (reluctantly) to add a Loaded handler to each of my DataGrids, which runs this code:
void grdGrid_Loaded(object sender, RoutedEventArgs e)
{
DataGrid dg = (DataGrid)sender;
foreach (DataGridColumn col in dg.Columns)
{
DataGridTextColumn textCol = col as DataGridTextColumn;
if (textCol != null)
{
textCol.IsReadOnly = true;
}
else
{
// This DataGridColumn isn't of type "DataGridTextColumn", so do nothing.
}
}
}
You could, of course, put this in your own DataGrid-inherited control, rather than repeating it for each of your DataGrids.
(Sigh.)
Why didn't MS make IsReadOnly an attachable property..? It would've made life so much easier!

Resources