I am using BooleanToVisibilityConvertor for manipulating visibility of TextBlock in a ListBox DataTemplate.
Here is my XAML code:
<phone:PhoneApplicationPage.Resources>
<Converters:BooleanToVisibilityConvertor x:Key="booleanToVisibilityConvertor"/>
</phone:PhoneApplicationPage.Resources>
<TextBlock Grid.Row="2" HorizontalAlignment="Right" Padding="0,0,7,0" Visibility="{Binding AverageConsumption, Converter={StaticResource booleanToVisibilityConvertor}}">
<Run Text="{Binding AverageConsumption}"/>
<Run Text="l./100 km."/>
</TextBlock>
And the code behind:
public class BooleanToVisibilityConvertor : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
{
if (value != null)
{
if (!string.IsNullOrEmpty(value.ToString()))
{
return Visibility.Visible;
}
}
return Visibility.Collapsed;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
This is working correct, but i need one more (reversed) convertor for another TextBlock placed on the same position (Grid.Row="2" HorizontalAlignment="Right")
with static Text="Partial Refueling" so when {Binding AverageConsumption} is not null or empty first TextBlock will be vissible and second will be collapsed and vice versa. Something like this:
class BooleanToVisibilityConvertorReversed : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
{
if (value != null)
{
if (!string.IsNullOrEmpty(value.ToString()))
{
return Visibility.Collapsed;
}
}
return Visibility.Visible;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I have tried to declare another convertor in XAML:
<phone:PhoneApplicationPage.Resources>
<Converters:BooleanToVisibilityConvertor x:Key="booleanToVisibilityConvertor"/>
<Converters:BooleanToVisibilityConvertorReversed x:Key="booleanToVisibilityConvertorReversed"/>
</phone:PhoneApplicationPage.Resources>
But got an exception on InitializeComponent():
'A first chance exception of type 'System.Windows.Markup.XamlParseException' occurred in System.Windows.ni.dll'
How can i solve this?
Seems like I've found what is your problem. Your BooleanToVisibilityConvertorReversed class is not public. Make it public and your issues should be gone.
Related
Good morning
I have a problem with binding initial state for each radio button.
<StackLayout Orientation="Horizontal"
RadioButtonGroup.GroupName="{Binding Source}"
RadioButtonGroup.SelectedValue="{Binding Frequency}">
<RadioButton FontSize="10" Content="Never" Value="0"/>
<RadioButton FontSize="10" Content="Rare" Value="25"/>
<RadioButton FontSize="10" Content="Often" Value="75"/>
<RadioButton FontSize="10" Content="Always" Value="100"/>
</StackLayout>
When the view is loaded there is no any RadioButton selected. The source binding Frequency is of type double.
public double Frequency
{
get => GetPropertyValue<double>();
set => SetPropertyValue(value);
}
I was thinking it is related with comparassion of types object and double. I have created converter as below:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!int.TryParse(value.ToString(), out var intValue))
return value;
var result = FrequencyValues.GetValue(intValue).ToString();
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!int.TryParse(value.ToString(), out var intValue))
return value;
var result = FrequencyValues.GetValue(intValue);
return result;
}
The solution with converter is also not working. Is that related with comprassion of types or I am missing some knowledge?
Thanks!
try
<StackLayout
RadioButtonGroup.GroupName="Source"
RadioButtonGroup.SelectedValue="{Binding Frequency}"
>
<RadioButton Content="a" Value="1"
IsChecked="{Binding Frequency, Converter={StaticResource RadioIsCheckedConverter}, ConverterParameter={x:Reference page}}" />
<RadioButton Content="b" Value="2"
IsChecked="{Binding Frequency, Converter={StaticResource RadioIsCheckedConverter}, ConverterParameter={x:Reference page}}" />
</StackLayout>
converter
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
var radioButton = parameter as RadioButton;
if (radioButton != null && radioButton.Value.Equals(value))
{
return true;
}
}
return false;
}
Change the type of Frequency from Double to Object;
The same Xaml as yours.
Code behind:
public partial class Page1 : ContentPage
{
RadioButtonModel _viewModel;
public Page1()
{
InitializeComponent();
_viewModel = new RadioButtonModel() { Source = "Group1", Frequency="100" };
this.BindingContext = _viewModel;
}
}
public class RadioButtonModel : INotifyPropertyChanged
{
private object _frequency;
public object Frequency
{
get => _frequency;
set
{
_frequency = value;
GetPropertyValue(nameof(Frequency));
}
}
private string _source;
public string Source
{
get => _source;
set
{
_source = value;
GetPropertyValue(nameof(Source));
}
}
public event PropertyChangedEventHandler PropertyChanged;
void GetPropertyValue(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I have created a markup extension to convert a DateTime into a string
public class DateTimeConverterExtension : IMarkupExtension<string> {
public DateTime Source { get; set; }
public string ProvideValue(IServiceProvider serviceProvider) {
var delta = DateTime.Now -Source;
if (delta.TotalDays > 0) {
return string.Format(StringResources.DaysAgo, delta.TotalDays);
}
if (delta.TotalHours > 0) {
return string.Format(StringResources.HoursAgo, delta.TotalHours);
}
if (delta.TotalMinutes > 0) {
return string.Format(StringResources.MinutesAgo, delta.TotalMinutes);
}
return string.Format(StringResources.MinutesAgo, 0);
}
object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider) {
return (this as IMarkupExtension<string>).ProvideValue(serviceProvider);
}
}
But when I use this in XAML:
<Label Text="{markupExtensions:DateTimeConverter Source={Binding Time}}" />
I get the following error:
No property, BindableProperty, or event found for "Source", or mismatching type between value and property.
Where did I go wrong?
You can convert Datetime with Converter.
To work with Converter, you need to create a class that implements the IValueConverter interface
code like:
public class DatetimeToStringConverter : IValueConverter
{
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();
}
}
then use it in xaml:
<ResourceDictionary>
<local:DatetimeToStringConverter x:Key="cnvDateTimeConverter"></local:DatetimeToStringConverter>
</ResourceDictionary>
...
<Label Text="{Binding Date, Converter={StaticResource cnvDateTimeConverter}}"></Label>
I have an Entry on a Xamarin Forms ContentPage that I have bound to a ViewModel property QtyIn which is an Int32:
private int _qtyIn;
public int QtyIn
{
get { return _qtyIn; }
set
{
if (_qtyIn != value)
{
_qtyIn = value;
RaisePropertyChanged("QtyIn");
}
}
}
Here is my XAML:
<Entry Text="{Binding Path=Source.QtyIn, Mode=TwoWay, Converter={StaticResource intToStringConverter}}" />
And my IValueConverter:
public class IntToStringConverter : IValueConverter
{
// from Int32 to String
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.ToString();
}
// String to Int
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
int parsedInt = 0;
if (int.TryParse(value.ToString(), out parsedInt))
{
return parsedInt;
}
return value;
}
}
The problem is when I try and enter a negative number, starting with the '-' minus sign, the binding fails because it can't convert '-' to an Int32. This is the error I see in the mono output when running this app on an Android device:
05-03 15:19:27.923 I/mono-stdout(19384): Binding: - can not be converted to type 'System.Int32'
Does anyone know how to bind an integer to an Text property that allows negative numbers? I can't find any documentation about this on Xamarin's website or forums.
In WPF, I would use the UpdateSourceTrigger=LostFocus property to only do the conversion after the whole number is entered, but Xamarin Forms doesn't have this property available.
Have you tried returning a 0 if the value passed is "-"?
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
int parsedInt = 0;
if (value == "-") return 0;
if (int.TryParse(value.ToString(), out parsedInt))
{
return parsedInt;
}
return value;
}
Your problem is, you return value, which is a string with - and try to pass it to an Int32 (back in your ViewModel).
Instead put second state into your logic. Return a null if parsing did fail - this also helps avoiding problems with any other character input.
public class IntToStringConverter : IValueConverter
{
// from Int32 to String
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value?.ToString() ?? "";
}
// String to Int
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
int parsedInt = 0;
if (int.TryParse(value.ToString(), out parsedInt))
{
return parsedInt;
}
return null;
}
}
And here is the ViewModel:
private int? _qtyIn;
public int? QtyInNullable // you should bind on this one in your entry
{
get { return _qtyIn; }
set
{
if (_qtyIn != value)
{
_qtyIn = value;
if (value != null)
OnPropertyChanged("QtyInNullable");
OnPropertyChanged("QtyIn");
}
}
}
public int QtyIn // you should bind on this one in your entry
{
get { return _qtyIn ?? 0; }
}
And bind it:
<Entry Text="{Binding Path=Source.QtyInNullable, Mode=TwoWay, Converter={StaticResource intToStringConverter}}" />
Is it possible to hide TextBlock if binding observablecollection contain empty,using xaml codes.?
xaml
<TextBlock Visibility="{Binding ElementName=Labour,Path=Items.Count, Converter={StaticResource ZeroToVisibilityConverter}}" TextWrapping="Wrap" Text="There is no data on this date" Margin="314,200,0,0" FontFamily="Arial" FontSize="14" Height="37" VerticalAlignment="Top" HorizontalAlignment="Left" Width="188"/>
Converter
public class ZeroToVisibilityConverter : IValueConverter
{
#region Implementation of IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return int.Parse(value.ToString()) == 0 ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
I have a ComboBox with some values, and I want to have two things working at once.
Here is my ComboBox and I want to show the 10 as default value and also to bind it to a double? Distance property.
<ComboBox Grid.Row="5" Grid.Column="1"
SelectedIndex="1"
SelectedValue="{Binding Distance, Mode=TwoWay, Converter={StaticResource StringToDoubleConverter}}">
<ComboBoxItem>1</ComboBoxItem>
<ComboBoxItem IsSelected="True">10</ComboBoxItem>
<ComboBoxItem>100</ComboBoxItem>
<ComboBoxItem>1000</ComboBoxItem>
</ComboBox>
And here is the converter:
public class StringToDoubleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
ComboBoxItem item = value as ComboBoxItem;
if (item != null)
{
double d;
if (double.TryParse(item.Content.ToString(), out d))
return d;
}
return null;
}
}
The problem is that in this code, The selected item 10 is not show at the start of the application.
If I will remove the line with the converter, then it will show the selected item 10, but then, I can't bind it to the double? Distance property. I dont want to write a code behind for it, such as: Convert.ToDouble(combobox1.SelectedValue)...
What can I do to make both things work?
You need to populate combo box items from ViewModel. Moreover you should not use SelectedValue property, instead of it you should use SelectedItem. See the below given code.
XAML
<ComboBox x:Name="cmb" ItemsSource="{Binding DistanceCollection}"
SelectedItem="{Binding Distance, Converter={StaticResource StringToDoubleConverter}, Mode=TwoWay}"/>
ViewModel
public class viewModel : INotifyPropertyChanged
{
public viewModel()
{
DistanceCollection = new ObservableCollection<string>
{
"1",
"10",
"100",
"1000"
};
Distance = double.Parse(DistanceCollection[1].ToString());
}
public ObservableCollection<string> DistanceCollection { get; set; }
private double _Distance;
public double Distance
{
get
{
return _Distance;
}
set
{
_Distance = value;
OnPropertyChanged("Distance");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Converter
public class StringToDoubleConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return value.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
string item = value as string;
if (!string.IsNullOrWhiteSpace(item))
{
double d;
if (double.TryParse(item, out d))
return d;
}
return null;
}
}