How to format string in XAML Setter Value? - data-binding

I have learned how to format strings in the content attribute of a label like this:
<Label Content="{Binding ElementName=theSlider, Path=Value}"
ContentStringFormat="The font size is {0}."/>
I want to do the same thing in a Setter but "ValueStringFormat" doesn't exist, what is the correct syntax to do what I want to accomplish here:
<DataTrigger Binding="{Binding Path=Kind}" Value="Task">
<Setter TargetName="TheTitle" Property="Text"
Value="{Binding Title}"
ValueStringFormat="Your title was: {0}"/>
</DataTrigger>

Can you simply use the StringFormat property of the Binding itself?
<DataTrigger Binding="{Binding Path=Kind}" Value="Task">
<Setter TargetName="TheTitle" Property="Text"
Value="{Binding Title,StringFormat='Your title was: {}{0}'}"
/>
</DataTrigger>

I can't test this but hope it works:
...
xmlns:local="clr-namespace:ValueConverter"
...
<Window.Resources>
<local:MyTextConverter x:Key="MyTextConverter" />
</Window.Resources>
...
<DataTrigger Value="Task">
<DataTrigger.Binding>
<Binding Converter="{StaticResource MyTextConverter}"
Path="Kind" />
</DataTrigger.Binding>
<Setter TargetName="TheTitle" Property="Text"/>
</DataTrigger>
where MyTextConverter is a class implementing IValueConverter interface:
public class PositionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
return String.Format("Your title was: {0}", value);
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
throw new Exception("The method or operation is not implemented.");
}

Related

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();
}
}

Binding DateTime to TimePicker in Xamarin Forms

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);

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>

How to highlight edited cell in a datagrid

How can I highlight a cell in DataGrid that has been edited? XAML solution through some style using triggers is preferable. But if not possible, then a code behind approach would be good enough.
I am not posting any code as I did not have any break through with the problem.
the answer is simply to create a style targeting DataGridCell and trigger the condition through binding, hopefully the steps below are easy to follow:
//lets say you bind datagrid to
List<RowValues> RowsView {get;}
//were RowValues is
List<RowValue> RowValues
// and RowValue is
public class RowValue
{
public bool IsEdited
{
get {return _isEdited;}
set
{
if(_isEdited== value) return;
_isEdited= value;
RaisePropertyChanged(()=>IsEdited);
}
}
public string Value
{
get {return _value;}
set
{
if(_value == value) return;
_value = value;
//check if the value is edited
IsEdited = _value == _originalValue;
RaisePropertyChanged(()=>Value);
}
}
}
//so in code accessing the structure would look like:
var row = RowView[0];
var cell = row[1];
cell.IsEdited... just to make it easier to see the XAML bindings below..
<DataGrid ItemsSource="{Binding RowsView}">
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Background" Value="Transparent" />
<Style.Triggers>
<DataTrigger Binding="{Binding RowValues[0].IsEdited}" Value="True">
<Setter Property="Background" Value="{StaticResource MissingDataBrush}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding RowValues[0].Value}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding RowValues[0].Value}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
....

Resources