Binding DateTime to TimePicker in Xamarin Forms - datetime

I tried to bind a DateTime value to a TimePicker instead of a TimeSpan.
If I change the Datatype then I have to change my complete code.
The property is called Item.Time
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" Title="New Item">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Save" Clicked="Save_Clicked" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout Spacing="20" Padding="15">
<Label Text="Text" FontSize="Medium" />
<TimePicker Time="{Binding Item.Time}"/>
<Label Text="Description" FontSize="Medium" />
<Editor Text="{Binding Item.Text}" FontSize="Small" Margin="0" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
How can I convert DateTime to TimeSpan without using an other class or something like that?
Is it possible to convert it with code like this:
<TimePicker Time="{Binding **(TimeSpan)**Item.Time}"/>

You cannot do this without the help of any other class, so you will need to convert it in your ViewModel already and expose it as a property and use that.
This would simply mean something like:
public TimeSpan MyTimeSpan
{
get { return Item.Time; } // Assuming Item.Time is a TimeSpan
set { Item.Time = value; }
}
You could also use a value converter. To do this, create a new class which implements the IValueConverter interface. It should be something like this, note that this is pseudo-code from the top of my head and might not work out of the box:
public class DateTimeToTimeSpanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((DateTime)value).Time;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var incomingTimeSpan = (TimeSpan)value;
return new DateTime(2018, 1, 1, incomingTimeSpan.Hours, incomingTimeSpan.Minutes, incomingTimeSpan.Seconds);
}
}
In your XAML, you can use it like this:
<ContentPage xmlns:local="clr-namespace:YourNamespaceName"...>
<ContentPage.Resources>
<ResourceDictionary>
<local:DateTimeToTimeSpanConverter x:Key="timeSpanConverter" />
</ResourceDictionary>
</ContentPage.Resources>
...
<TimePicker Time="{Binding Item.Time, Converter={StaticResource timeSpanConverter}}"/>
...
</ContentPage>
Read more on value converters in the Docs: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/converters

You can get TimeStamp value from DataTime object, like "DataTimeObject.TimeOfDay", The TimeOfDay is a TimeStamp datatype.
<TimePicker x:Name="Timepicker" HeightRequest="100" Time="{Binding
Item.TimeOfDay, Mode=TwoWay}"
PropertyChanged="TimePicker_PropertyChanged"/>

Either use a value converter or add a TimeSpan property to your view model

A straight to the point example compiled from #GeraldVersluis example. Note that I have two controls "ReturnTime" and "ReturnDate":
DateTime d = this.ReturnDate.Date;
DateTime dtCombined = new DateTime(d.Year, d.Month, d.Day, ReturnTime.Time.Hours, this.ReturnTime.Time.Minutes, this.ReturnTime.Time.Seconds);

Related

How to create a custom control that user can add any kinds of view into it in Xamarin.Forms?

I want to create a custom control that can let users add any view to a specific location, like below:
MyCustomControl.xaml
<ContentView ...>
<!-- My customizations ... -->
<StackLayout>
<!-- Everything added by user should goes here -->
</StackLayout>
<!-- My other customizations ... -->
</ContentView>
When using it:
<ContentPage>
<controls:MyCustomControl>
<Label />
<Image />
...
<controls:MyCustomControl>
</ContentPage>
How can I do this?
I'm going to post one way of doing this here but there are others. From your question, I'm assuming you want to reuse a ContentView in various places and be allowed to change a part of that content view when you instantiate it. I'm going to assume you are going to specify the custom part in XAML. You can use the following pattern to achieve this:
Create your ContentView and add a bindable property for the custom part:
ContentViewWithCustomPart.xaml
<ContentView.Content>
<StackLayout>
<Label Text="I'm always here!" />
<StackLayout x:Name="StackToHoldCustomStuff">
<!-- Stuff goes here injected by bindable property -->
</StackLayout>
</StackLayout>
</ContentView.Content>
ContenViewWithCustomPart.xaml.cs
public partial class ContentViewWithCustomPart : ContentView
{
public static readonly BindableProperty CustomViewProperty =
BindableProperty.Create(nameof(CustomView), typeof(View), typeof(ContentViewWithCustomPart), propertyChanged: OnViewChanged);
static void OnViewChanged(object bindable, object oldValue, object newValue)
{
var page = (ContentViewWithCustomPart)bindable;
page.StackToHoldCustomStuff.Children.Clear();
if (newValue != null) page.StackToHoldCustomStuff.Children.Add((View)newValue);
}
public View CustomView { get => (View)GetValue(CustomViewProperty); set => SetValue(CustomViewProperty, value); }
public ContentViewWithCustomPart()
{
InitializeComponent();
}
}
Usage in a demo page:
<ContentPage.Content>
<StackLayout>
<cv:ContentViewWithCustomPart>
<cv:ContentViewWithCustomPart.CustomView>
<Label Text="I'm a custom bit!" />
</cv:ContentViewWithCustomPart.CustomView>
</cv:ContentViewWithCustomPart>
</StackLayout>
</ContentPage.Content>
Result:

Change binded value in listview

In my listview one of the controls is label which is binded to BoolValue comming from viewmodel, in this case BoolValue is bool type so value could be either true or false. Is there any way to replace it with other text? I use MVVM.
<Label
Text="{Binding BoolValue}" />
<Label
Yes, use a ValueConverter
public class BoolToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((bool)value != 0) ? "True Value" : "False Value";
}
}
then in your XAML
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyDemo"
x:Class="MyDemo.MyPage"
>
<ContentPage.Resources>
<ResourceDictionary>
<local:BoolToStringConverter x:Key="BoolToString" />
</ResourceDictionary>
</ContentPage.Resources>
...
<Label Text={Binding BoolValue, Converter={StaticResource BoolToString}}" />
...

Xamarin Forms Shell Flyout with Different Title on Tab

I'm making the move from traditional navigation to Shell. Is it possible to have different text on the flyout items vs the tabs? The tab text needs to be short where the flyout could be more descript.
For example, I may have Call for Assistance as the title of the flyout item, but just Call for the tab.
If you want to achieve this effect,you could define FlyoutItem appearance,customize it by setting the Shell.ItemTemplate attached property to a DataTemplate,then let your Label Binding Value Converters to convert the title string:
like:
<Shell>
...
<Shell.Resources>
<ResourceDictionary>
<local:TitlleConverter x:Key="titleConverter" />
</ResourceDictionary>
</Shell.Resources>
<Shell.ItemTemplate>
<DataTemplate>
<Label
Text="{Binding Title,Converter= {StaticResource titleConverter}}"
FontAttributes="Italic"
VerticalTextAlignment="Center" />
</DataTemplate>
</Shell.ItemTemplate>
<FlyoutItem>
<ShellContent Titile ="Call" />
<ShellContent Titile ="" />
<ShellContent Titile ="" />
</FlyoutItem>
</Shell>
the TitlleConverter.cs :
class TitlleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!string.IsNullOrEmpty((string)value) && value.Equals("Call"))
{
return "Call for Assistance";
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

How to format date and time in XAML in Xamarin application

I have a set up XAML code below.
<Label Text="{Binding Date}"></Label>
<Label Text="{Binding Time}'}"></Label>
I want result like september 12,2014 2:30 PM.
Change your code to:
<Label Text="{Binding Date, StringFormat='{0:MMMM dd, yyyy}'}"></Label>
<Label Text="{Binding Time, StringFormat='{}{0:hh\\:mm}'}"></Label>
Make a custom IValueConverter implementation:
public class DatetimeToStringConverter : IValueConverter
{
#region IValueConverter implementation
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return string.Empty;
var datetime = (DateTime)value;
//put your custom formatting here
return datetime.ToLocalTime().ToString("g");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Then use it like that:
<ResourceDictionary>
<local:DatetimeToStringConverter x:Key="cnvDateTimeConverter"></local:DatetimeToStringConverter>
</ResourceDictionary>
...
<Label Text="{Binding Date, Converter={StaticResource cnvDateTimeConverter}}"></Label>
<Label Text="{Binding Time, Converter={StaticResource cnvDateTimeConverter}}"></Label>
<Label>
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding Date, StringFormat='{0:MMMM dd, yyyy}'}"/>
<Span Text=" "/>
<Span Text="{Binding Time, StringFormat='{0:h:mm tt}'}"/>
</FormattedString>
</Label.FormattedText>
</Label>
Use the standard .NET Date Format specifiers.
To get
September 12, 2014 2:30 PM
use something like
MMMM d, yyyy h:mm tt

SearchBar.IsEnabled binding are not updated when property changed in Xamarin.Forms

I want to disable searchbar whenever my viewmodel is busy.
And I have the following xaml for my view (part of view):
<SearchBar x:Name="searchBar" TextChanged="OnSearchQueryChanged" Grid.Row="0" IsEnabled="{Binding IsBusy}"/>
<ActivityIndicator x:Name="progress" IsRunning="{Binding IsBusy}" IsVisible="{Binding IsBusy}"/>
Both elements are bound to the the same property however SearchBar stays disabled when my ViewModel raise IsBusy = false. Same time progress becomes hidden.
What could be wrong here?
What you want is to set the SearchBar.IsEnabled property to true when you view model IsBusy property is false, and vice versa.
What you're doing right now, is disabling (setting IsEnabled to false) the search bar when the your vie model is no longer busy (IsBusy is false).
You need a converter for this, one that returns true for false, and false for true:
public class NotConverter:IValueConverter
{
public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value.GetType () == typeof(bool))
return !((bool)value);
return value;
}
public object ConvertBack (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException ();
}
}
In order to use it in your binding in xaml, let's include an instance of it as a resource in the container wrapping your xaml snippet (let's assume it's a ContentPage), and then we can reference that converter in the {Binding} markup extension:
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:YourNamespace;assembly=YourAssemblyName">
<ContentPage.Resources>
<ResourceDictionary>
<local:NotConverter x:Key="notConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Orientation="Vertical">
<SearchBar x:Name="searchBar" TextChanged="OnSearchQueryChanged" Grid.Row="0" IsEnabled="{Binding IsBusy, Converter={StaticResource notConverter}}"/>
<ActivityIndicator x:Name="progress" IsRunning="{Binding IsBusy}" IsVisible="{Binding IsBusy}"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>

Resources